Integrated internal changes from Google

This includes all internal changes from around May 20 to now.
diff --git a/Makefile.am b/Makefile.am
index 31ca9a1..1443b75 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -209,6 +209,7 @@
   java/core/src/main/java/com/google/protobuf/Extension.java                       \
   java/core/src/main/java/com/google/protobuf/ExtensionLite.java                   \
   java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java               \
+  java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java        \
   java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java           \
   java/core/src/main/java/com/google/protobuf/FieldSet.java                        \
   java/core/src/main/java/com/google/protobuf/FloatArrayList.java                  \
@@ -273,6 +274,7 @@
   java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java             \
   java/core/src/test/java/com/google/protobuf/DynamicMessageTest.java              \
   java/core/src/test/java/com/google/protobuf/EnumTest.java                        \
+  java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java    \
   java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java               \
   java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java              \
   java/core/src/test/java/com/google/protobuf/ForceFieldBuildersPreRun.java        \
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
index 03c0d57..b8fdb2b 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -54,12 +54,40 @@
     // TODO(dweis): Update GeneratedMessage to parameterize with MessageType and BuilderType.
     extends AbstractMessageLite
     implements Message {
-  
+
   @Override
   public boolean isInitialized() {
     return MessageReflection.isInitialized(this);
   }
 
+  /**
+   * Interface for the parent of a Builder that allows the builder to
+   * communicate invalidations back to the parent for use when using nested
+   * builders.
+   */
+  protected interface BuilderParent {
+
+    /**
+     * A builder becomes dirty whenever a field is modified -- including fields
+     * in nested builders -- and becomes clean when build() is called.  Thus,
+     * when a builder becomes dirty, all its parents become dirty as well, and
+     * when it becomes clean, all its children become clean.  The dirtiness
+     * state is used to invalidate certain cached values.
+     * <br>
+     * To this end, a builder calls markDirty() on its parent whenever it
+     * transitions from clean to dirty.  The parent must propagate this call to
+     * its own parent, unless it was already dirty, in which case the
+     * grandparent must necessarily already be dirty as well.  The parent can
+     * only transition back to "clean" after calling build() on all children.
+     */
+    void markDirty();
+  }
+
+  /** Create a nested builder. */
+  protected Message.Builder newBuilderForType(BuilderParent parent) {
+    throw new UnsupportedOperationException("Nested builder is not supported for this type.");
+  }
+
 
   @Override
   public List<String> findInitializationErrors() {
@@ -460,6 +488,31 @@
           MessageReflection.findMissingFields(message));
     }
 
+    /**
+     * Used to support nested builders and called to mark this builder as clean.
+     * Clean builders will propagate the {@link BuildParent#markDirty()} event
+     * to their parent builders, while dirty builders will not, as their parents
+     * should be dirty already.
+     *
+     * NOTE: Implementations that don't support nested builders don't need to
+     * override this method.
+     */
+    void markClean() {
+      throw new IllegalStateException("Should be overriden by subclasses.");
+    }
+
+    /**
+     * Used to support nested builders and called when this nested builder is
+     * no longer used by its parent builder and should release the reference
+     * to its parent builder.
+     *
+     * NOTE: Implementations that don't support nested builders don't need to
+     * override this method.
+     */
+    void dispose() {
+      throw new IllegalStateException("Should be overriden by subclasses.");
+    }
+
     // ===============================================================
     // The following definitions seem to be required in order to make javac
     // not produce weird errors like:
@@ -550,4 +603,44 @@
       return super.mergeDelimitedFrom(input, extensionRegistry);
     }
   }
+
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatiblity with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashLong(long n) {
+    return (int) (n ^ (n >>> 32));
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatiblity with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashBoolean(boolean b) {
+    return b ? 1231 : 1237;
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatiblity with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashEnum(EnumLite e) {
+    return e.getNumber();
+  }
+  //
+  /**
+   * @deprecated from v3.0.0-beta-3+, for compatiblity with v2.5.0 and v2.6.1
+   * generated code.
+   */
+  @Deprecated
+  protected static int hashEnumList(List<? extends EnumLite> list) {
+    int hash = 1;
+    for (EnumLite e : list) {
+      hash = 31 * hash + hashEnum(e);
+    }
+    return hash;
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
index 43736dd..046030f 100644
--- a/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -45,10 +45,10 @@
  */
 public abstract class AbstractMessageLite<
     MessageType extends AbstractMessageLite<MessageType, BuilderType>,
-    BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>> 
+    BuilderType extends AbstractMessageLite.Builder<MessageType, BuilderType>>
         implements MessageLite {
   protected int memoizedHashCode = 0;
-  
+
   @Override
   public ByteString toByteString() {
     try {
@@ -57,9 +57,7 @@
       writeTo(out.getCodedOutput());
       return out.build();
     } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a ByteString threw an IOException (should " +
-        "never happen).", e);
+      throw new RuntimeException(getSerializingExceptionMessage("ByteString"), e);
     }
   }
 
@@ -72,9 +70,7 @@
       output.checkNoSpaceLeft();
       return result;
     } catch (IOException e) {
-      throw new RuntimeException(
-        "Serializing to a byte array threw an IOException " +
-        "(should never happen).", e);
+      throw new RuntimeException(getSerializingExceptionMessage("byte array"), e);
     }
   }
 
@@ -109,6 +105,11 @@
     return new UninitializedMessageException(this);
   }
 
+  private String getSerializingExceptionMessage(String target) {
+    return "Serializing " + getClass().getName() + " to a " + target
+        + " threw an IOException (should never happen).";
+  }
+
   protected static void checkByteStringIsUtf8(ByteString byteString)
       throws IllegalArgumentException {
     if (!byteString.isValidUtf8()) {
@@ -120,7 +121,7 @@
       final Collection<? super T> list) {
     Builder.addAll(values, list);
   }
-  
+
   /**
    * A partial implementation of the {@link Message.Builder} interface which
    * implements as many methods of that interface as possible in terms of
@@ -156,9 +157,7 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
       }
     }
 
@@ -174,9 +173,7 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a ByteString threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("ByteString"), e);
       }
     }
 
@@ -197,9 +194,7 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
       }
     }
 
@@ -225,9 +220,7 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (IOException e) {
-        throw new RuntimeException(
-          "Reading from a byte array threw an IOException (should " +
-          "never happen).", e);
+        throw new RuntimeException(getReadingExceptionMessage("byte array"), e);
       }
     }
 
@@ -321,7 +314,7 @@
       return mergeDelimitedFrom(input,
           ExtensionRegistryLite.getEmptyRegistry());
     }
-    
+
     @Override
     @SuppressWarnings("unchecked") // isInstance takes care of this
     public BuilderType mergeFrom(final MessageLite other) {
@@ -329,12 +322,17 @@
         throw new IllegalArgumentException(
             "mergeFrom(MessageLite) can only merge messages of the same type.");
       }
-        
+
       return internalMergeFrom((MessageType) other);
     }
-    
+
     protected abstract BuilderType internalMergeFrom(MessageType message);
 
+    private String getReadingExceptionMessage(String target) {
+      return "Reading " + getClass().getName() + " from a " + target
+          + " threw an IOException (should never happen).";
+    }
+
     /**
      * Construct an UninitializedMessageException reporting missing fields in
      * the given message.
diff --git a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
index 8b2820b..0d9f87b 100644
--- a/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/BooleanArrayList.java
@@ -38,21 +38,22 @@
 
 /**
  * An implementation of {@link BooleanList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 final class BooleanArrayList
-    extends AbstractProtobufList<Boolean> implements BooleanList, RandomAccess {
-  
+    extends AbstractProtobufList<Boolean>
+    implements BooleanList, RandomAccess {
+
   private static final BooleanArrayList EMPTY_LIST = new BooleanArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static BooleanArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
@@ -72,13 +73,14 @@
   }
 
   /**
-   * Constructs a new mutable {@code BooleanArrayList}.
+   * Constructs a new mutable {@code BooleanArrayList}
+   * containing the same elements as {@code other}.
    */
-  private BooleanArrayList(boolean[] array, int size) {
-    this.array = array;
+  private BooleanArrayList(boolean[] other, int size) {
+    array = other;
     this.size = size;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -91,14 +93,14 @@
     if (size != other.size) {
       return false;
     }
-    
+
     final boolean[] arr = other.array;
     for (int i = 0; i < size; i++) {
       if (array[i] != arr[i]) {
         return false;
       }
     }
-    
+
     return true;
   }
 
@@ -170,7 +172,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -178,10 +180,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       boolean[] newArray = new boolean[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -195,38 +197,38 @@
   @Override
   public boolean addAll(Collection<? extends Boolean> collection) {
     ensureIsMutable();
-    
+
     if (collection == null) {
       throw new NullPointerException();
     }
-    
+
     // We specialize when adding another BooleanArrayList to avoid boxing elements.
     if (!(collection instanceof BooleanArrayList)) {
       return super.addAll(collection);
     }
-    
+
     BooleanArrayList list = (BooleanArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -255,7 +257,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
index ad174d0..576a350 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -36,12 +36,9 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
-import java.lang.reflect.Field;
 import java.nio.BufferOverflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 
@@ -59,9 +56,8 @@
  */
 public abstract class CodedOutputStream extends ByteOutput {
   private static final Logger logger = Logger.getLogger(CodedOutputStream.class.getName());
-  private static final sun.misc.Unsafe UNSAFE = getUnsafe();
-  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
-  private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = UnsafeUtil.hasUnsafeArrayOperations();
+  private static final long ARRAY_BASE_OFFSET = UnsafeUtil.getArrayBaseOffset();
 
   private static final int FIXED_32_SIZE = 4;
   private static final int FIXED_64_SIZE = 8;
@@ -869,7 +865,7 @@
     return computeLengthDelimitedFieldSize(value.getSerializedSize());
   }
 
-  private static int computeLengthDelimitedFieldSize(int fieldLength) {
+  static int computeLengthDelimitedFieldSize(int fieldLength) {
     return computeUInt32SizeNoTag(fieldLength) + fieldLength;
   }
 
@@ -948,6 +944,10 @@
     OutOfSpaceException(Throwable cause) {
       super(MESSAGE, cause);
     }
+
+    OutOfSpaceException(String explanationMessage, Throwable cause) {
+      super(MESSAGE + ": " + explanationMessage, cause);
+    }
   }
 
   /**
@@ -1250,8 +1250,8 @@
       try {
         buffer[position++] = value;
       } catch (IndexOutOfBoundsException e) {
-        throw new OutOfSpaceException(new IndexOutOfBoundsException(
-            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+        throw new OutOfSpaceException(
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
       }
     }
 
@@ -1271,11 +1271,11 @@
         long pos = ARRAY_BASE_OFFSET + position;
         while (true) {
           if ((value & ~0x7F) == 0) {
-            UNSAFE.putByte(buffer, pos++, (byte) value);
+            UnsafeUtil.putByte(buffer, pos++, (byte) value);
             position++;
             return;
           } else {
-            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+            UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
             position++;
             value >>>= 7;
           }
@@ -1293,8 +1293,7 @@
           }
         } catch (IndexOutOfBoundsException e) {
           throw new OutOfSpaceException(
-              new IndexOutOfBoundsException(
-                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+              String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
         }
       }
     }
@@ -1308,8 +1307,7 @@
         buffer[position++] = (byte) ((value >> 24) & 0xFF);
       } catch (IndexOutOfBoundsException e) {
         throw new OutOfSpaceException(
-            new IndexOutOfBoundsException(
-                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
       }
     }
 
@@ -1319,11 +1317,11 @@
         long pos = ARRAY_BASE_OFFSET + position;
         while (true) {
           if ((value & ~0x7FL) == 0) {
-            UNSAFE.putByte(buffer, pos++, (byte) value);
+            UnsafeUtil.putByte(buffer, pos++, (byte) value);
             position++;
             return;
           } else {
-            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+            UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
             position++;
             value >>>= 7;
           }
@@ -1341,8 +1339,7 @@
           }
         } catch (IndexOutOfBoundsException e) {
           throw new OutOfSpaceException(
-              new IndexOutOfBoundsException(
-                  String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+              String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
         }
       }
     }
@@ -1360,8 +1357,7 @@
         buffer[position++] = (byte) ((int) (value >> 56) & 0xFF);
       } catch (IndexOutOfBoundsException e) {
         throw new OutOfSpaceException(
-            new IndexOutOfBoundsException(
-                String.format("Pos: %d, limit: %d, len: %d", position, limit, 1)));
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, 1), e);
       }
     }
 
@@ -1372,8 +1368,7 @@
         position += length;
       } catch (IndexOutOfBoundsException e) {
         throw new OutOfSpaceException(
-            new IndexOutOfBoundsException(
-                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
       }
     }
 
@@ -1390,8 +1385,7 @@
         position += length;
       } catch (IndexOutOfBoundsException e) {
         throw new OutOfSpaceException(
-            new IndexOutOfBoundsException(
-                String.format("Pos: %d, limit: %d, len: %d", position, limit, length)));
+            String.format("Pos: %d, limit: %d, len: %d", position, limit, length), e);
       }
     }
 
@@ -1855,10 +1849,10 @@
         long pos = originalPos;
         while (true) {
           if ((value & ~0x7F) == 0) {
-            UNSAFE.putByte(buffer, pos++, (byte) value);
+            UnsafeUtil.putByte(buffer, pos++, (byte) value);
             break;
           } else {
-            UNSAFE.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
+            UnsafeUtil.putByte(buffer, pos++, (byte) ((value & 0x7F) | 0x80));
             value >>>= 7;
           }
         }
@@ -1890,10 +1884,10 @@
         long pos = originalPos;
         while (true) {
           if ((value & ~0x7FL) == 0) {
-            UNSAFE.putByte(buffer, pos++, (byte) value);
+            UnsafeUtil.putByte(buffer, pos++, (byte) value);
             break;
           } else {
-            UNSAFE.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
+            UnsafeUtil.putByte(buffer, pos++, (byte) (((int) value & 0x7F) | 0x80));
             value >>>= 7;
           }
         }
@@ -2600,65 +2594,4 @@
       position = 0;
     }
   }
-
-  /**
-   * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
-   * platform.
-   */
-  private static sun.misc.Unsafe getUnsafe() {
-    sun.misc.Unsafe unsafe = null;
-    try {
-      unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
-        @Override
-        public sun.misc.Unsafe run() throws Exception {
-          Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
-
-          for (Field f : k.getDeclaredFields()) {
-            f.setAccessible(true);
-            Object x = f.get(null);
-            if (k.isInstance(x)) {
-              return k.cast(x);
-            }
-          }
-          // The sun.misc.Unsafe field does not exist.
-          return null;
-        }
-      });
-    } catch (Throwable e) {
-      // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
-      // for Unsafe.
-    }
-
-    logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
-        unsafe != null ? "available" : "unavailable");
-    return unsafe;
-  }
-
-  /**
-   * Indicates whether or not unsafe array operations are supported on this platform.
-   */
-  // TODO(nathanmittler): Add support for Android's MemoryBlock.
-  private static boolean supportsUnsafeArrayOperations() {
-    boolean supported = false;
-    if (UNSAFE != null) {
-      try {
-        UNSAFE.getClass().getMethod("arrayBaseOffset", Class.class);
-        UNSAFE.getClass().getMethod("putByte", Object.class, long.class, byte.class);
-        supported = true;
-      } catch (Throwable e) {
-        // Do nothing.
-      }
-    }
-    logger.log(Level.FINEST, "Unsafe array operations: {}",
-        supported ? "available" : "unavailable");
-    return supported;
-  }
-
-  /**
-   * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
-   * available.
-   */
-  private static <T> int byteArrayBaseOffset() {
-    return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
-  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java
index e00ea34..1c34c24 100644
--- a/java/core/src/main/java/com/google/protobuf/Descriptors.java
+++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java
@@ -871,6 +871,10 @@
         nestedTypes[i].setProto(proto.getNestedType(i));
       }
 
+      for (int i = 0; i < oneofs.length; i++) {
+        oneofs[i].setProto(proto.getOneofDecl(i));
+      }
+
       for (int i = 0; i < enumTypes.length; i++) {
         enumTypes[i].setProto(proto.getEnumType(i));
       }
@@ -2513,6 +2517,10 @@
 
     public int getFieldCount() { return fieldCount; }
 
+    public OneofOptions getOptions() {
+      return proto.getOptions();
+    }
+
     /** Get a list of this message type's fields. */
     public List<FieldDescriptor> getFields() {
       return Collections.unmodifiableList(Arrays.asList(fields));
@@ -2522,6 +2530,10 @@
       return fields[index];
     }
 
+    private void setProto(final OneofDescriptorProto proto) {
+      this.proto = proto;
+    }
+
     private OneofDescriptor(final OneofDescriptorProto proto,
                             final FileDescriptor file,
                             final Descriptor parent,
diff --git a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
index a9543b8..6177f3c 100644
--- a/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/DoubleArrayList.java
@@ -38,26 +38,27 @@
 
 /**
  * An implementation of {@link DoubleList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 final class DoubleArrayList
-    extends AbstractProtobufList<Double> implements DoubleList, RandomAccess {
-  
+    extends AbstractProtobufList<Double>
+    implements DoubleList, RandomAccess {
+
   private static final DoubleArrayList EMPTY_LIST = new DoubleArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static DoubleArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private double[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -72,13 +73,14 @@
   }
 
   /**
-   * Constructs a new mutable {@code DoubleArrayList} containing the same elements as {@code other}.
+   * Constructs a new mutable {@code DoubleArrayList}
+   * containing the same elements as {@code other}.
    */
-  private DoubleArrayList(double[] array, int size) {
-    this.array = array;
+  private DoubleArrayList(double[] other, int size) {
+    array = other;
     this.size = size;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -91,14 +93,14 @@
     if (size != other.size) {
       return false;
     }
-    
+
     final double[] arr = other.array;
     for (int i = 0; i < size; i++) {
       if (array[i] != arr[i]) {
         return false;
       }
     }
-    
+
     return true;
   }
 
@@ -119,7 +121,7 @@
     }
     return new DoubleArrayList(Arrays.copyOf(array, capacity), size);
   }
-  
+
   @Override
   public Double get(int index) {
     return getDouble(index);
@@ -171,7 +173,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -179,10 +181,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       double[] newArray = new double[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -196,38 +198,38 @@
   @Override
   public boolean addAll(Collection<? extends Double> collection) {
     ensureIsMutable();
-    
+
     if (collection == null) {
       throw new NullPointerException();
     }
-    
+
     // We specialize when adding another DoubleArrayList to avoid boxing elements.
     if (!(collection instanceof DoubleArrayList)) {
       return super.addAll(collection);
     }
-    
+
     DoubleArrayList list = (DoubleArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -256,7 +258,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
index 0067392..1c2e7e6 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -101,7 +101,7 @@
 
   /** Get the unmodifiable singleton empty instance. */
   public static ExtensionRegistry getEmptyRegistry() {
-    return EMPTY;
+    return EMPTY_REGISTRY;
   }
 
 
@@ -243,6 +243,11 @@
     add(newExtensionInfo(extension), extension.getExtensionType());
   }
 
+  /** Add an extension from a generated file to the registry. */
+  public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
+    add((Extension<?, ?>) extension);
+  }
+
   static ExtensionInfo newExtensionInfo(final Extension<?, ?> extension) {
     if (extension.getDescriptor().getJavaType() ==
         FieldDescriptor.JavaType.MESSAGE) {
@@ -311,7 +316,7 @@
   private final Map<DescriptorIntPair, ExtensionInfo> mutableExtensionsByNumber;
 
   ExtensionRegistry(boolean empty) {
-    super(ExtensionRegistryLite.getEmptyRegistry());
+    super(EMPTY_REGISTRY_LITE);
     this.immutableExtensionsByName =
         Collections.<String, ExtensionInfo>emptyMap();
     this.mutableExtensionsByName =
@@ -321,7 +326,7 @@
     this.mutableExtensionsByNumber =
             Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
   }
-  private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
+  static final ExtensionRegistry EMPTY_REGISTRY = new ExtensionRegistry(true);
 
   private void add(
       final ExtensionInfo extension,
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
new file mode 100644
index 0000000..23174e2
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryFactory.java
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 static com.google.protobuf.ExtensionRegistryLite.EMPTY_REGISTRY_LITE;
+
+/**
+ * A factory object to create instances of {@link ExtensionRegistryLite}.
+ * 
+ * <p>
+ * This factory detects (via reflection) if the full (non-Lite) protocol buffer libraries
+ * are available, and if so, the instances returned are actually {@link ExtensionRegistry}.
+ */
+final class ExtensionRegistryFactory {
+
+  static final String FULL_REGISTRY_CLASS_NAME = "com.google.protobuf.ExtensionRegistry";
+
+  /* Visible for Testing
+     @Nullable */
+  static final Class<?> EXTENSION_REGISTRY_CLASS = reflectExtensionRegistry();
+
+  /* @Nullable */
+  static Class<?> reflectExtensionRegistry() {
+    try {
+      return Class.forName(FULL_REGISTRY_CLASS_NAME);
+    } catch (ClassNotFoundException e) {
+      // The exception allocation is potentially expensive on Android (where it can be triggered
+      // many times at start up). Is there a way to ameliorate this?
+      return null;
+    }
+  }
+
+  /** Construct a new, empty instance. */
+  public static ExtensionRegistryLite create() {
+    if (EXTENSION_REGISTRY_CLASS != null) {
+      try {
+        return invokeSubclassFactory("newInstance");
+      } catch (Exception e) {
+        // return a Lite registry.
+      }
+    }
+    return new ExtensionRegistryLite();
+  }
+
+  /** Get the unmodifiable singleton empty instance. */
+  public static ExtensionRegistryLite createEmpty() {
+    if (EXTENSION_REGISTRY_CLASS != null) {
+      try {
+        return invokeSubclassFactory("getEmptyRegistry");
+      } catch (Exception e) {
+        // return a Lite registry.
+      }
+    }
+    return EMPTY_REGISTRY_LITE;
+  }
+
+  static boolean isFullRegistry(ExtensionRegistryLite registry) {
+    return EXTENSION_REGISTRY_CLASS != null
+        && EXTENSION_REGISTRY_CLASS.isAssignableFrom(registry.getClass());
+  }
+
+  private static final ExtensionRegistryLite invokeSubclassFactory(String methodName)
+      throws Exception {
+    return (ExtensionRegistryLite) EXTENSION_REGISTRY_CLASS
+        .getMethod(methodName).invoke(null);
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
index 65cf738..5e4d773 100644
--- a/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
@@ -79,6 +79,22 @@
   // applications. Need to support this feature on smaller granularity.
   private static volatile boolean eagerlyParseMessageSets = false;
 
+  // Visible for testing.
+  static final String EXTENSION_CLASS_NAME = "com.google.protobuf.Extension";
+
+  /* @Nullable */
+  static Class<?> resolveExtensionClass() {
+    try {
+      return Class.forName(EXTENSION_CLASS_NAME);
+    } catch (ClassNotFoundException e) {
+      // See comment in ExtensionRegistryFactory on the potential expense of this.
+      return null;
+    }
+  }
+
+  /* @Nullable */
+  private static final Class<?> extensionClass = resolveExtensionClass();
+
   public static boolean isEagerlyParseMessageSets() {
     return eagerlyParseMessageSets;
   }
@@ -87,14 +103,22 @@
     eagerlyParseMessageSets = isEagerlyParse;
   }
 
-  /** Construct a new, empty instance. */
+  /**
+   * Construct a new, empty instance.
+   * 
+   * <p>
+   * This may be an {@code ExtensionRegistry} if the full (non-Lite) proto libraries are available.
+   */
   public static ExtensionRegistryLite newInstance() {
-    return new ExtensionRegistryLite();
+    return ExtensionRegistryFactory.create();
   }
 
-  /** Get the unmodifiable singleton empty instance. */
+  /**
+   * Get the unmodifiable singleton empty instance of either ExtensionRegistryLite or
+   * {@code ExtensionRegistry} (if the full (non-Lite) proto libraries are available).
+   */
   public static ExtensionRegistryLite getEmptyRegistry() {
-    return EMPTY;
+    return ExtensionRegistryFactory.createEmpty();
   }
 
   /** Returns an unmodifiable view of the registry. */
@@ -128,6 +152,23 @@
       extension);
   }
 
+  /**
+   * Add an extension from a lite generated file to the registry only if it is
+   * a non-lite extension i.e. {@link GeneratedMessageLite.GeneratedExtension}. */
+  public final void add(ExtensionLite<?, ?> extension) {
+    if (GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(extension.getClass())) {
+      add((GeneratedMessageLite.GeneratedExtension<?, ?>) extension);
+    }
+    if (ExtensionRegistryFactory.isFullRegistry(this)) {
+      try {
+        this.getClass().getMethod("add", extensionClass).invoke(this, extension);
+      } catch (Exception e) {
+        throw new IllegalArgumentException(
+            String.format("Could not invoke ExtensionRegistry#add for %s", extension), e);
+      }
+    }
+  }
+
   // =================================================================
   // Private stuff.
 
@@ -139,9 +180,11 @@
         new HashMap<ObjectIntPair,
                     GeneratedMessageLite.GeneratedExtension<?, ?>>();
   }
+  static final ExtensionRegistryLite EMPTY_REGISTRY_LITE =
+      new ExtensionRegistryLite(true);
 
   ExtensionRegistryLite(ExtensionRegistryLite other) {
-    if (other == EMPTY) {
+    if (other == EMPTY_REGISTRY_LITE) {
       this.extensionsByNumber = Collections.emptyMap();
     } else {
       this.extensionsByNumber =
@@ -153,11 +196,9 @@
                     GeneratedMessageLite.GeneratedExtension<?, ?>>
       extensionsByNumber;
 
-  private ExtensionRegistryLite(boolean empty) {
+  ExtensionRegistryLite(boolean empty) {
     this.extensionsByNumber = Collections.emptyMap();
   }
-  private static final ExtensionRegistryLite EMPTY =
-    new ExtensionRegistryLite(true);
 
   /** A (Object, int) pair, used as a map key. */
   private static final class ObjectIntPair {
diff --git a/java/core/src/main/java/com/google/protobuf/FieldSet.java b/java/core/src/main/java/com/google/protobuf/FieldSet.java
index 4e89709..5b25174 100644
--- a/java/core/src/main/java/com/google/protobuf/FieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/FieldSet.java
@@ -120,21 +120,21 @@
   public boolean isImmutable() {
     return isImmutable;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
       return true;
     }
-    
+
     if (!(o instanceof FieldSet)) {
       return false;
     }
-    
+
     FieldSet<?> other = (FieldSet<?>) o;
-    return other.fields.equals(other.fields);
+    return fields.equals(other.fields);
   }
-  
+
   @Override
   public int hashCode() {
     return fields.hashCode();
@@ -493,7 +493,7 @@
   }
 
   /**
-   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another 
+   * Like {@link Message.Builder#mergeFrom(Message)}, but merges from another
    * {@link FieldSet}.
    */
   public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
@@ -638,10 +638,11 @@
    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
    *               this field.
    */
-  private static void writeElement(final CodedOutputStream output,
-                                   final WireFormat.FieldType type,
-                                   final int number,
-                                   final Object value) throws IOException {
+  static void writeElement(
+      final CodedOutputStream output,
+      final WireFormat.FieldType type,
+      final int number,
+      final Object value) throws IOException {
     // Special case for groups, which need a start and end tag; other fields
     // can just use writeTag() and writeFieldNoTag().
     if (type == WireFormat.FieldType.GROUP) {
@@ -804,9 +805,8 @@
    *               {@link Message#getField(Descriptors.FieldDescriptor)} for
    *               this field.
    */
-  private static int computeElementSize(
-      final WireFormat.FieldType type,
-      final int number, final Object value) {
+  static int computeElementSize(
+      final WireFormat.FieldType type, final int number, final Object value) {
     int tagSize = CodedOutputStream.computeTagSize(number);
     if (type == WireFormat.FieldType.GROUP) {
       // Only count the end group tag for proto2 messages as for proto1 the end
diff --git a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
index 63cb6d7..90d6154 100644
--- a/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/FloatArrayList.java
@@ -38,25 +38,27 @@
 
 /**
  * An implementation of {@link FloatList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class FloatArrayList extends AbstractProtobufList<Float> implements FloatList, RandomAccess {
-  
+final class FloatArrayList
+    extends AbstractProtobufList<Float>
+    implements FloatList, RandomAccess {
+
   private static final FloatArrayList EMPTY_LIST = new FloatArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static FloatArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private float[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -71,13 +73,14 @@
   }
 
   /**
-   * Constructs a new mutable {@code FloatArrayList} containing the same elements as {@code other}.
+   * Constructs a new mutable {@code FloatArrayList}
+   * containing the same elements as {@code other}.
    */
-  private FloatArrayList(float[] array, int size) {
-    this.array = array;
+  private FloatArrayList(float[] other, int size) {
+    array = other;
     this.size = size;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -90,14 +93,14 @@
     if (size != other.size) {
       return false;
     }
-    
+
     final float[] arr = other.array;
     for (int i = 0; i < size; i++) {
       if (array[i] != arr[i]) {
         return false;
       }
     }
-    
+
     return true;
   }
 
@@ -117,7 +120,7 @@
     }
     return new FloatArrayList(Arrays.copyOf(array, capacity), size);
   }
-  
+
   @Override
   public Float get(int index) {
     return getFloat(index);
@@ -169,7 +172,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -177,10 +180,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       float[] newArray = new float[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -194,38 +197,38 @@
   @Override
   public boolean addAll(Collection<? extends Float> collection) {
     ensureIsMutable();
-    
+
     if (collection == null) {
       throw new NullPointerException();
     }
-    
+
     // We specialize when adding another FloatArrayList to avoid boxing elements.
     if (!(collection instanceof FloatArrayList)) {
       return super.addAll(collection);
     }
-    
+
     FloatArrayList list = (FloatArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -254,7 +257,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
index 790cb62..2c87302 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -355,31 +355,30 @@
     // Noop for messages without extensions.
   }
 
-  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
+  /**
+   * TODO(xiaofeng): remove this after b/29368482 is fixed. We need to move this
+   * interface to AbstractMessage in order to versioning GeneratedMessage but
+   * this move breaks binary compatibility for AppEngine. After AppEngine is
+   * fixed we can exlude this from google3.
+   */
+  protected interface BuilderParent extends AbstractMessage.BuilderParent {}
 
   /**
-   * Interface for the parent of a Builder that allows the builder to
-   * communicate invalidations back to the parent for use when using nested
-   * builders.
+   * TODO(xiaofeng): remove this together with GeneratedMessage.BuilderParent.
    */
-  protected interface BuilderParent {
+  protected abstract Message.Builder newBuilderForType(BuilderParent parent);
 
-    /**
-     * A builder becomes dirty whenever a field is modified -- including fields
-     * in nested builders -- and becomes clean when build() is called.  Thus,
-     * when a builder becomes dirty, all its parents become dirty as well, and
-     * when it becomes clean, all its children become clean.  The dirtiness
-     * state is used to invalidate certain cached values.
-     * <br>
-     * To this end, a builder calls markAsDirty() on its parent whenever it
-     * transitions from clean to dirty.  The parent must propagate this call to
-     * its own parent, unless it was already dirty, in which case the
-     * grandparent must necessarily already be dirty as well.  The parent can
-     * only transition back to "clean" after calling build() on all children.
-     */
-    void markDirty();
+  @Override
+  protected Message.Builder newBuilderForType(final AbstractMessage.BuilderParent parent) {
+    return newBuilderForType(new BuilderParent() {
+      @Override
+      public void markDirty() {
+        parent.markDirty();
+      }
+    });
   }
 
+
   @SuppressWarnings("unchecked")
   public abstract static class Builder <BuilderType extends Builder<BuilderType>>
       extends AbstractMessage.Builder<BuilderType> {
@@ -403,6 +402,7 @@
       this.builderParent = builderParent;
     }
 
+    @Override
     void dispose() {
       builderParent = null;
     }
@@ -420,6 +420,7 @@
      * Called by the subclass or a builder to notify us that a message was
      * built and may be cached and therefore invalidations are needed.
      */
+    @Override
     protected void markClean() {
       this.isClean = true;
     }
@@ -755,6 +756,33 @@
     <Type> Type getExtension(
         ExtensionLite<MessageType, List<Type>> extension,
         int index);
+
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        Extension<MessageType, Type> extension);
+    /** Check if a singular extension is present. */
+    <Type> boolean hasExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        Extension<MessageType, List<Type>> extension);
+    /** Get the number of elements in a repeated extension. */
+    <Type> int getExtensionCount(
+        GeneratedExtension<MessageType, List<Type>> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, Type> extension);
+    /** Get the value of an extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, Type> extension);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        Extension<MessageType, List<Type>> extension,
+        int index);
+    /** Get one element of a repeated extension. */
+    <Type> Type getExtension(
+        GeneratedExtension<MessageType, List<Type>> extension,
+        int index);
   }
 
   /**
@@ -881,6 +909,53 @@
           extensions.getRepeatedField(descriptor, index));
     }
 
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get one element of a repeated extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+
     /** Called by subclasses to check if all extensions are initialized. */
     protected boolean extensionsAreInitialized() {
       return extensions.isInitialized();
@@ -1269,6 +1344,95 @@
       return (BuilderType) this;
     }
 
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Check if a singular extension is present. */
+    @Override
+    public final <Type> boolean hasExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return hasExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final Extension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the number of elements in a repeated extension. */
+    @Override
+    public final <Type> int getExtensionCount(
+        final GeneratedExtension<MessageType, List<Type>> extension) {
+      return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, Type> extension) {
+      return getExtension((ExtensionLite<MessageType, Type>) extension);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final Extension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Get the value of an extension. */
+    @Override
+    public final <Type> Type getExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
+      return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
+    }
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of an extension. */
+    public final <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, Type> extension, final Type value) {
+      return setExtension((ExtensionLite<MessageType, Type>) extension, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final Extension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Set the value of one element of a repeated extension. */
+    public final <Type> BuilderType setExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension,
+        final int index, final Type value) {
+      return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
+    }
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final Extension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Append a value to a repeated extension. */
+    public final <Type> BuilderType addExtension(
+        final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
+      return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
+    }
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final Extension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+    /** Clear an extension. */
+    public final <Type> BuilderType clearExtension(
+        final GeneratedExtension<MessageType, ?> extension) {
+      return clearExtension((ExtensionLite<MessageType, ?>) extension);
+    }
+
     /** Called by subclasses to check if all extensions are initialized. */
     protected boolean extensionsAreInitialized() {
       return extensions.isInitialized();
diff --git a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
index c5adc5a..214971b 100644
--- a/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
+++ b/java/core/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -59,15 +59,15 @@
  */
 public abstract class GeneratedMessageLite<
     MessageType extends GeneratedMessageLite<MessageType, BuilderType>,
-    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>> 
+    BuilderType extends GeneratedMessageLite.Builder<MessageType, BuilderType>>
         extends AbstractMessageLite<MessageType, BuilderType> {
 
   /** For use by generated code only. Lazily initialized to reduce allocations. */
   protected UnknownFieldSetLite unknownFields = UnknownFieldSetLite.getDefaultInstance();
-  
+
   /** For use by generated code only.  */
   protected int memoizedSerializedSize = -1;
-  
+
   @Override
   @SuppressWarnings("unchecked") // Guaranteed by runtime.
   public final Parser<MessageType> getParserForType() {
@@ -113,7 +113,7 @@
     }
     return memoizedHashCode;
   }
-  
+
   @SuppressWarnings("unchecked") // Guaranteed by runtime
   int hashCode(HashCodeVisitor visitor) {
     if (memoizedHashCode == 0) {
@@ -125,18 +125,18 @@
     }
     return memoizedHashCode;
   }
-  
+
   @SuppressWarnings("unchecked") // Guaranteed by isInstance + runtime
   @Override
   public boolean equals(Object other) {
     if (this == other) {
       return true;
     }
-    
+
     if (!getDefaultInstanceForType().getClass().isInstance(other)) {
       return false;
     }
-    
+
     try {
       visit(EqualsVisitor.INSTANCE, (MessageType) other);
     } catch (NotEqualsException e) {
@@ -144,7 +144,7 @@
     }
     return true;
   }
-  
+
   /**
    * Same as {@link #equals(Object)} but throws {@code NotEqualsException}.
    */
@@ -153,7 +153,7 @@
     if (this == other) {
       return true;
     }
-    
+
     if (!getDefaultInstanceForType().getClass().isInstance(other)) {
       return false;
     }
@@ -161,7 +161,7 @@
     visit(visitor, (MessageType) other);
     return true;
   }
-  
+
   // The general strategy for unknown fields is to use an UnknownFieldSetLite that is treated as
   // mutable during the parsing constructor and immutable after. This allows us to avoid
   // any unnecessary intermediary allocations while reducing the generated code size.
@@ -174,10 +174,10 @@
       unknownFields = UnknownFieldSetLite.newInstance();
     }
   }
-  
+
   /**
    * Called by subclasses to parse an unknown field. For use by generated code only.
-   * 
+   *
    * @return {@code true} unless the tag is an end-group tag.
    */
   protected boolean parseUnknownField(int tag, CodedInputStream input) throws IOException {
@@ -185,7 +185,7 @@
     if (WireFormat.getTagWireType(tag) == WireFormat.WIRETYPE_END_GROUP) {
       return false;
     }
-    
+
     ensureUnknownFieldsInitialized();
     return unknownFields.mergeFieldFrom(tag, input);
   }
@@ -197,7 +197,7 @@
     ensureUnknownFieldsInitialized();
     unknownFields.mergeVarintField(tag, value);
   }
-  
+
   /**
    * Called by subclasses to parse an unknown field. For use by generated code only.
    */
@@ -205,7 +205,7 @@
     ensureUnknownFieldsInitialized();
     unknownFields.mergeLengthDelimitedField(fieldNumber, value);
   }
-  
+
   /**
    * Called by subclasses to complete parsing. For use by generated code only.
    */
@@ -292,7 +292,7 @@
     dynamicMethod(MethodToInvoke.VISIT, visitor, other);
     unknownFields = visitor.visitUnknownFields(unknownFields, other.unknownFields);
   }
-  
+
   /**
    * Merge some unknown fields into the {@link UnknownFieldSetLite} for this
    * message.
@@ -359,9 +359,9 @@
       if (isBuilt) {
         return instance;
       }
-      
+
       instance.makeImmutable();
-      
+
       isBuilt = true;
       return instance;
     }
@@ -374,24 +374,24 @@
       }
       return result;
     }
-    
+
     @Override
     protected BuilderType internalMergeFrom(MessageType message) {
       return mergeFrom(message);
     }
-    
+
     /** All subclasses implement this. */
     public BuilderType mergeFrom(MessageType message) {
       copyOnWrite();
       instance.visit(MergeFromVisitor.INSTANCE, message);
       return (BuilderType) this;
     }
-    
+
     @Override
     public MessageType getDefaultInstanceForType() {
       return defaultInstance;
     }
-    
+
     @Override
     public BuilderType mergeFrom(
         com.google.protobuf.CodedInputStream input,
@@ -466,12 +466,12 @@
       super.visit(visitor, other);
       extensions = visitor.visitExtensions(extensions, other.extensions);
     }
-    
+
     /**
      * Parse an unknown field or an extension. For use by generated code only.
-     * 
+     *
      * <p>For use by generated code only.
-     * 
+     *
      * @return {@code true} unless the tag is an end-group tag.
      */
     protected <MessageType extends MessageLite> boolean parseUnknownField(
@@ -590,7 +590,7 @@
 
       return true;
     }
-    
+
     private void verifyExtensionContainingType(
         final GeneratedExtension<MessageType, ?> extension) {
       if (extension.getContainingTypeDefaultInstance() !=
@@ -607,7 +607,7 @@
     public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extension) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       return extensions.hasField(extensionLite.descriptor);
     }
@@ -618,7 +618,7 @@
         final ExtensionLite<MessageType, List<Type>> extension) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       return extensions.getRepeatedFieldCount(extensionLite.descriptor);
     }
@@ -629,7 +629,7 @@
     public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extension) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       final Object value = extensions.getField(extensionLite.descriptor);
       if (value == null) {
@@ -660,7 +660,7 @@
     @Override
     protected final void makeImmutable() {
       super.makeImmutable();
-      
+
       extensions.makeImmutable();
     }
 
@@ -734,7 +734,7 @@
       implements ExtendableMessageOrBuilder<MessageType, BuilderType> {
     protected ExtendableBuilder(MessageType defaultInstance) {
       super(defaultInstance);
-      
+
       // TODO(dweis): This is kind of an unnecessary clone since we construct a
       //     new instance in the parent constructor which makes the extensions
       //     immutable. This extra allocation shouldn't matter in practice
@@ -753,7 +753,7 @@
       if (!isBuilt) {
         return;
       }
-      
+
       super.copyOnWrite();
       instance.extensions = instance.extensions.clone();
     }
@@ -814,14 +814,14 @@
     public BuilderType clone() {
       return super.clone();
     }
-    
+
     /** Set the value of an extension. */
     public final <Type> BuilderType setExtension(
         final ExtensionLite<MessageType, Type> extension,
         final Type value) {
       GeneratedExtension<MessageType, Type> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       instance.extensions.setField(extensionLite.descriptor, extensionLite.toFieldSetType(value));
@@ -834,7 +834,7 @@
         final int index, final Type value) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       instance.extensions.setRepeatedField(
@@ -848,7 +848,7 @@
         final Type value) {
       GeneratedExtension<MessageType, List<Type>> extensionLite =
           checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       instance.extensions.addRepeatedField(
@@ -860,7 +860,7 @@
     public final <Type> BuilderType clearExtension(
         final ExtensionLite<MessageType, ?> extension) {
       GeneratedExtension<MessageType, ?> extensionLite = checkIsLite(extension);
-      
+
       verifyExtensionContainingType(extensionLite);
       copyOnWrite();
       instance.extensions.clearField(extensionLite.descriptor);
@@ -1157,7 +1157,7 @@
     public static SerializedForm of(MessageLite message) {
       return new SerializedForm(message);
     }
-    
+
     private static final long serialVersionUID = 0L;
 
     private final String messageClassName;
@@ -1191,7 +1191,7 @@
       } catch (ClassNotFoundException e) {
         throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
       } catch (NoSuchFieldException e) {
-        throw new RuntimeException("Unable to find DEFAULT_INSTANCE in " + messageClassName, e);
+        return readResolveFallback();
       } catch (SecurityException e) {
         throw new RuntimeException("Unable to call DEFAULT_INSTANCE in " + messageClassName, e);
       } catch (IllegalAccessException e) {
@@ -1200,8 +1200,35 @@
         throw new RuntimeException("Unable to understand proto buffer", e);
       }
     }
+
+    /**
+     * @deprecated from v3.0.0-beta-3+, for compatibility with v2.5.0 and v2.6.1 generated code.
+     */
+    @Deprecated
+    private Object readResolveFallback() throws ObjectStreamException {
+      try {
+        Class<?> messageClass = Class.forName(messageClassName);
+        java.lang.reflect.Field defaultInstanceField =
+            messageClass.getDeclaredField("defaultInstance");
+        defaultInstanceField.setAccessible(true);
+        MessageLite defaultInstance = (MessageLite) defaultInstanceField.get(null);
+        return defaultInstance.newBuilderForType()
+            .mergeFrom(asBytes)
+            .buildPartial();
+      } catch (ClassNotFoundException e) {
+        throw new RuntimeException("Unable to find proto buffer class: " + messageClassName, e);
+      } catch (NoSuchFieldException e) {
+        throw new RuntimeException("Unable to find defaultInstance in " + messageClassName, e);
+      } catch (SecurityException e) {
+        throw new RuntimeException("Unable to call defaultInstance in " + messageClassName, e);
+      } catch (IllegalAccessException e) {
+        throw new RuntimeException("Unable to call parsePartialFrom", e);
+      } catch (InvalidProtocolBufferException e) {
+        throw new RuntimeException("Unable to understand proto buffer", e);
+      }
+    }
   }
-  
+
   /**
    * Checks that the {@link Extension} is Lite and returns it as a
    * {@link GeneratedExtension}.
@@ -1215,7 +1242,7 @@
     if (!extension.isLite()) {
       throw new IllegalArgumentException("Expected a lite extension.");
     }
-    
+
     return (GeneratedExtension<MessageType, T>) extension;
   }
 
@@ -1227,8 +1254,8 @@
   protected static final <T extends GeneratedMessageLite<T, ?>> boolean isInitialized(
       T message, boolean shouldMemoize) {
     return message.dynamicMethod(MethodToInvoke.IS_INITIALIZED, shouldMemoize) != null;
-  } 
-  
+  }
+
   protected static final <T extends GeneratedMessageLite<T, ?>> void makeImmutable(T message) {
     message.dynamicMethod(MethodToInvoke.MAKE_IMMUTABLE);
   }
@@ -1246,7 +1273,7 @@
   protected static LongList emptyLongList() {
     return LongArrayList.emptyList();
   }
-  
+
   protected static LongList mutableCopy(LongList list) {
     int size = list.size();
     return list.mutableCopyWithCapacity(
@@ -1256,7 +1283,7 @@
   protected static FloatList emptyFloatList() {
     return FloatArrayList.emptyList();
   }
-  
+
   protected static FloatList mutableCopy(FloatList list) {
     int size = list.size();
     return list.mutableCopyWithCapacity(
@@ -1266,7 +1293,7 @@
   protected static DoubleList emptyDoubleList() {
     return DoubleArrayList.emptyList();
   }
-  
+
   protected static DoubleList mutableCopy(DoubleList list) {
     int size = list.size();
     return list.mutableCopyWithCapacity(
@@ -1276,7 +1303,7 @@
   protected static BooleanList emptyBooleanList() {
     return BooleanArrayList.emptyList();
   }
-  
+
   protected static BooleanList mutableCopy(BooleanList list) {
     int size = list.size();
     return list.mutableCopyWithCapacity(
@@ -1286,7 +1313,7 @@
   protected static <E> ProtobufList<E> emptyProtobufList() {
     return ProtobufArrayList.emptyList();
   }
-  
+
   protected static <E> ProtobufList<E> mutableCopy(ProtobufList<E> list) {
     int size = list.size();
     return list.mutableCopyWithCapacity(
@@ -1300,20 +1327,20 @@
    */
   protected static class DefaultInstanceBasedParser<T extends GeneratedMessageLite<T, ?>>
       extends AbstractParser<T> {
-    
+
     private T defaultInstance;
-    
+
     public DefaultInstanceBasedParser(T defaultInstance) {
       this.defaultInstance = defaultInstance;
     }
-    
+
     @Override
     public T parsePartialFrom(CodedInputStream input, ExtensionRegistryLite extensionRegistry)
         throws InvalidProtocolBufferException {
       return GeneratedMessageLite.parsePartialFrom(defaultInstance, input, extensionRegistry);
     }
   }
-  
+
   /**
    * A static helper method for parsing a partial from input using the extension registry and the
    * instance.
@@ -1335,14 +1362,14 @@
     }
     return result;
   }
-  
+
   protected static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
       T defaultInstance,
       CodedInputStream input)
       throws InvalidProtocolBufferException {
     return parsePartialFrom(defaultInstance, input, ExtensionRegistryLite.getEmptyRegistry());
   }
-  
+
   /**
    * Helper method to check if message is initialized.
    *
@@ -1373,7 +1400,7 @@
       throws InvalidProtocolBufferException {
     return checkMessageInitialized(parsePartialFrom(defaultInstance, data, extensionRegistry));
   }
-  
+
   // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
   // ByteString.
   private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
@@ -1393,7 +1420,7 @@
       throw e;
     }
   }
-  
+
   // This is a special case since we want to verify that the last tag is 0. We assume we exhaust the
   // ByteString.
   private static <T extends GeneratedMessageLite<T, ?>> T parsePartialFrom(
@@ -1477,7 +1504,7 @@
     return checkMessageInitialized(
         parsePartialDelimitedFrom(defaultInstance, input, extensionRegistry));
   }
-  
+
   private static <T extends GeneratedMessageLite<T, ?>> T parsePartialDelimitedFrom(
       T defaultInstance,
       InputStream input,
@@ -1530,13 +1557,12 @@
     Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other);
     Object visitOneofMessage(boolean minePresent, Object mine, Object other);
     void visitOneofNotSet(boolean minePresent);
-    
+
     /**
      * Message fields use null sentinals.
      */
     <T extends MessageLite> T visitMessage(T mine, T other);
-    LazyFieldLite visitLazyMessage(
-        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other);
+    LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other);
 
     <T> ProtobufList<T> visitList(ProtobufList<T> mine, ProtobufList<T> other);
     BooleanList visitBooleanList(BooleanList mine, BooleanList other);
@@ -1686,7 +1712,7 @@
       }
       throw NOT_EQUALS;
     }
-    
+
     @Override
     public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
       if (minePresent && ((GeneratedMessageLite<?, ?>) mine).equals(this, (MessageLite) other)) {
@@ -1694,7 +1720,7 @@
       }
       throw NOT_EQUALS;
     }
-    
+
     @Override
     public void visitOneofNotSet(boolean minePresent) {
       if (minePresent) {
@@ -1716,13 +1742,17 @@
 
       return mine;
     }
-    
+
     @Override
     public LazyFieldLite visitLazyMessage(
-        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
-      if (!minePresent && !otherPresent) {
-        return mine;
-      } else if (minePresent && otherPresent && mine.equals(other)) {
+        LazyFieldLite mine, LazyFieldLite other) {
+      if (mine == null && other == null) {
+        return null;
+      }
+      if (mine == null || other == null) {
+        throw NOT_EQUALS;
+      }
+      if (mine.equals(other)) {
         return mine;
       }
       throw NOT_EQUALS;
@@ -1813,7 +1843,7 @@
     // The caller must ensure that the visitor is invoked parameterized with this and this such that
     // other is this. This is required due to how oneof cases are handled. See the class comment
     // on Visitor for more information.
-    
+
     private int hashCode = 0;
 
     @Override
@@ -1909,7 +1939,7 @@
       hashCode = (53 * hashCode) + mine.hashCode();
       return mine;
     }
-    
+
     @Override
     public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
       return visitMessage((MessageLite) mine, (MessageLite) other);
@@ -1918,7 +1948,7 @@
     @Override
     public void visitOneofNotSet(boolean minePresent) {
       if (minePresent) {
-        throw new IllegalStateException(); // Can't happen if other == this. 
+        throw new IllegalStateException(); // Can't happen if other == this.
       }
     }
 
@@ -1939,9 +1969,14 @@
     }
 
     @Override
-    public LazyFieldLite visitLazyMessage(
-        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
-      hashCode = (53 * hashCode) + mine.hashCode();
+    public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
+      final int protoHash;
+      if (mine != null) {
+        protoHash = mine.hashCode();
+      } else {
+        protoHash = 37;
+      }
+      hashCode = (53 * hashCode) + protoHash;
       return mine;
     }
 
@@ -1996,7 +2031,7 @@
       hashCode = (53 * hashCode) + mine.hashCode();
       return mine;
     }
-    
+
     @Override
     public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
       hashCode = (53 * hashCode) + mine.hashCode();
@@ -2064,7 +2099,7 @@
 
     @Override
     public Object visitOneofDouble(boolean minePresent, Object mine, Object other) {
-      return other;      
+      return other;
     }
 
     @Override
@@ -2074,29 +2109,26 @@
 
     @Override
     public Object visitOneofLong(boolean minePresent, Object mine, Object other) {
-      return other;      
+      return other;
     }
 
     @Override
     public Object visitOneofString(boolean minePresent, Object mine, Object other) {
-      return other;      
+      return other;
     }
 
     @Override
     public Object visitOneofByteString(boolean minePresent, Object mine, Object other) {
-      return other;      
+      return other;
     }
 
     @Override
     public Object visitOneofLazyMessage(boolean minePresent, Object mine, Object other) {
-      if (minePresent) {
-        LazyFieldLite lazy = (LazyFieldLite) mine;
-        lazy.merge((LazyFieldLite) other);
-        return lazy;
-      }
-      return other;
+      LazyFieldLite lazy = minePresent ? (LazyFieldLite) mine : new LazyFieldLite();
+      lazy.merge((LazyFieldLite) other);
+      return lazy;
     }
-    
+
     @Override
     public Object visitOneofMessage(boolean minePresent, Object mine, Object other) {
       if (minePresent) {
@@ -2104,7 +2136,7 @@
       }
       return other;
     }
-    
+
     @Override
     public void visitOneofNotSet(boolean minePresent) {
       return;
@@ -2121,12 +2153,13 @@
     }
 
     @Override
-    public LazyFieldLite visitLazyMessage(
-        boolean minePresent, LazyFieldLite mine, boolean otherPresent, LazyFieldLite other) {
-      // LazyFieldLite's are never null so we can just copy across. Necessary to avoid leakage
-      // from builder into immutable message.
-      // TODO(dweis): Change to null sentinels?
-      mine.merge(other);
+    public LazyFieldLite visitLazyMessage(LazyFieldLite mine, LazyFieldLite other) {
+      if (other != null) {
+        if (mine == null) {
+          mine = new LazyFieldLite();
+        }
+        mine.merge(other);
+      }
       return mine;
     }
 
@@ -2140,7 +2173,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2154,7 +2187,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2168,7 +2201,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2182,7 +2215,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2196,7 +2229,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2210,7 +2243,7 @@
         }
         mine.addAll(other);
       }
-      
+
       return size > 0 ? mine : other;
     }
 
@@ -2232,10 +2265,15 @@
       return other == UnknownFieldSetLite.getDefaultInstance()
           ? mine : UnknownFieldSetLite.mutableCopyOf(mine, other);
     }
-    
+
     @Override
     public <K, V> MapFieldLite<K, V> visitMap(MapFieldLite<K, V> mine, MapFieldLite<K, V> other) {
-      mine.mergeFrom(other);
+      if (!other.isEmpty()) {
+        if (!mine.isMutable()) {
+          mine = mine.mutableCopy();
+        }
+        mine.mergeFrom(other);
+      }
       return mine;
     }
   }
diff --git a/java/core/src/main/java/com/google/protobuf/IntArrayList.java b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
index 6d6ece5..2f526e3 100644
--- a/java/core/src/main/java/com/google/protobuf/IntArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/IntArrayList.java
@@ -38,25 +38,27 @@
 
 /**
  * An implementation of {@link IntList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class IntArrayList extends AbstractProtobufList<Integer> implements IntList, RandomAccess {
-  
+final class IntArrayList
+    extends AbstractProtobufList<Integer>
+    implements IntList, RandomAccess {
+
   private static final IntArrayList EMPTY_LIST = new IntArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static IntArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private int[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -71,13 +73,14 @@
   }
 
   /**
-   * Constructs a new mutable {@code IntArrayList} containing the same elements as {@code other}.
+   * Constructs a new mutable {@code IntArrayList}
+   * containing the same elements as {@code other}.
    */
-  private IntArrayList(int[] array, int size) {
-    this.array = array;
+  private IntArrayList(int[] other, int size) {
+    array = other;
     this.size = size;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
@@ -90,14 +93,14 @@
     if (size != other.size) {
       return false;
     }
-    
+
     final int[] arr = other.array;
     for (int i = 0; i < size; i++) {
       if (array[i] != arr[i]) {
         return false;
       }
     }
-    
+
     return true;
   }
 
@@ -117,7 +120,7 @@
     }
     return new IntArrayList(Arrays.copyOf(array, capacity), size);
   }
-  
+
   @Override
   public Integer get(int index) {
     return getInt(index);
@@ -169,7 +172,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -177,10 +180,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       int[] newArray = new int[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -194,38 +197,38 @@
   @Override
   public boolean addAll(Collection<? extends Integer> collection) {
     ensureIsMutable();
-    
+
     if (collection == null) {
       throw new NullPointerException();
     }
-    
+
     // We specialize when adding another IntArrayList to avoid boxing elements.
     if (!(collection instanceof IntArrayList)) {
       return super.addAll(collection);
     }
-    
+
     IntArrayList list = (IntArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -254,7 +257,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/LongArrayList.java b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
index bc4475d..5a772e3 100644
--- a/java/core/src/main/java/com/google/protobuf/LongArrayList.java
+++ b/java/core/src/main/java/com/google/protobuf/LongArrayList.java
@@ -38,25 +38,27 @@
 
 /**
  * An implementation of {@link LongList} on top of a primitive array.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
-final class LongArrayList extends AbstractProtobufList<Long> implements LongList, RandomAccess {
-  
+final class LongArrayList
+    extends AbstractProtobufList<Long>
+    implements LongList, RandomAccess {
+
   private static final LongArrayList EMPTY_LIST = new LongArrayList();
   static {
     EMPTY_LIST.makeImmutable();
   }
-  
+
   public static LongArrayList emptyList() {
     return EMPTY_LIST;
   }
-  
+
   /**
    * The backing store for the list.
    */
   private long[] array;
-  
+
   /**
    * The size of the list distinct from the length of the array. That is, it is the number of
    * elements set in the list.
@@ -71,33 +73,34 @@
   }
 
   /**
-   * Constructs a new mutable {@code LongArrayList} containing the same elements as {@code other}.
+   * Constructs a new mutable {@code LongArrayList}
+   * containing the same elements as {@code other}.
    */
-  private LongArrayList(long[] array, int size) {
-    this.array = array;
+  private LongArrayList(long[] other, int size) {
+    array = other;
     this.size = size;
   }
-  
+
   @Override
   public boolean equals(Object o) {
     if (this == o) {
       return true;
     }
-    if (!(o instanceof IntArrayList)) {
+    if (!(o instanceof LongArrayList)) {
       return super.equals(o);
     }
     LongArrayList other = (LongArrayList) o;
     if (size != other.size) {
       return false;
     }
-    
+
     final long[] arr = other.array;
     for (int i = 0; i < size; i++) {
       if (array[i] != arr[i]) {
         return false;
       }
     }
-    
+
     return true;
   }
 
@@ -117,7 +120,7 @@
     }
     return new LongArrayList(Arrays.copyOf(array, capacity), size);
   }
-  
+
   @Override
   public Long get(int index) {
     return getLong(index);
@@ -169,7 +172,7 @@
     if (index < 0 || index > size) {
       throw new IndexOutOfBoundsException(makeOutOfBoundsExceptionMessage(index));
     }
-    
+
     if (size < array.length) {
       // Shift everything over to make room
       System.arraycopy(array, index, array, index + 1, size - index);
@@ -177,10 +180,10 @@
       // Resize to 1.5x the size
       int length = ((size * 3) / 2) + 1;
       long[] newArray = new long[length];
-      
+
       // Copy the first part directly
       System.arraycopy(array, 0, newArray, 0, index);
-      
+
       // Copy the rest shifted over by one to make room
       System.arraycopy(array, index, newArray, index + 1, size - index);
       array = newArray;
@@ -194,38 +197,38 @@
   @Override
   public boolean addAll(Collection<? extends Long> collection) {
     ensureIsMutable();
-    
+
     if (collection == null) {
       throw new NullPointerException();
     }
-    
+
     // We specialize when adding another LongArrayList to avoid boxing elements.
     if (!(collection instanceof LongArrayList)) {
       return super.addAll(collection);
     }
-    
+
     LongArrayList list = (LongArrayList) collection;
     if (list.size == 0) {
       return false;
     }
-    
+
     int overflow = Integer.MAX_VALUE - size;
     if (overflow < list.size) {
       // We can't actually represent a list this large.
       throw new OutOfMemoryError();
     }
-    
+
     int newSize = size + list.size;
     if (newSize > array.length) {
       array = Arrays.copyOf(array, newSize);
     }
-    
+
     System.arraycopy(list.array, 0, array, size, list.size);
     size = newSize;
     modCount++;
     return true;
   }
-  
+
   @Override
   public boolean remove(Object o) {
     ensureIsMutable();
@@ -254,7 +257,7 @@
   /**
    * Ensures that the provided {@code index} is within the range of {@code [0, size]}. Throws an
    * {@link IndexOutOfBoundsException} if it is not.
-   * 
+   *
    * @param index the index to verify is in range
    */
   private void ensureIndexInRange(int index) {
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntry.java b/java/core/src/main/java/com/google/protobuf/MapEntry.java
index 31414bb..117cd91 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntry.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntry.java
@@ -41,63 +41,83 @@
 
 /**
  * Implements MapEntry messages.
- * 
+ *
  * In reflection API, map fields will be treated as repeated message fields and
  * each map entry is accessed as a message. This MapEntry class is used to
  * represent these map entry messages in reflection API.
- * 
+ *
  * Protobuf internal. Users shouldn't use this class.
  */
 public final class MapEntry<K, V> extends AbstractMessage {
-  private static class Metadata<K, V> {
-    public final Descriptor descriptor;  
-    public final MapEntry<K, V> defaultInstance;
-    public final AbstractParser<MapEntry<K, V>> parser;
-    
+
+  private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> {
+
+    public final Descriptor descriptor;
+    public final Parser<MapEntry<K, V>> parser;
+
     public Metadata(
-        final Descriptor descriptor, final MapEntry<K, V> defaultInstance) {
+        Descriptor descriptor,
+        MapEntry<K, V> defaultInstance,
+        WireFormat.FieldType keyType,
+        WireFormat.FieldType valueType) {
+      super(keyType, defaultInstance.key, valueType, defaultInstance.value);
       this.descriptor = descriptor;
-      this.defaultInstance = defaultInstance;
-      final Metadata<K, V> thisMetadata = this;
       this.parser = new AbstractParser<MapEntry<K, V>>() {
-        private final Parser<MapEntryLite<K, V>> dataParser =
-            defaultInstance.data.getParserForType();
+
         @Override
         public MapEntry<K, V> parsePartialFrom(
             CodedInputStream input, ExtensionRegistryLite extensionRegistry)
             throws InvalidProtocolBufferException {
-          MapEntryLite<K, V> data =
-              dataParser.parsePartialFrom(input, extensionRegistry);
-          return new MapEntry<K, V>(thisMetadata, data);
+          return new MapEntry<K, V>(Metadata.this, input, extensionRegistry);
         }
-        
       };
     }
   }
-  
+
+  private final K key;
+  private final V value;
   private final Metadata<K, V> metadata;
-  private final MapEntryLite<K, V> data;
-  
+
   /** Create a default MapEntry instance. */
-  private MapEntry(Descriptor descriptor,
+  private MapEntry(
+      Descriptor descriptor,
       WireFormat.FieldType keyType, K defaultKey,
       WireFormat.FieldType valueType, V defaultValue) {
-    this.data = MapEntryLite.newDefaultInstance(
-        keyType, defaultKey, valueType, defaultValue);
-    this.metadata = new Metadata<K, V>(descriptor, this); 
+    this.key = defaultKey;
+    this.value = defaultValue;
+    this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType);
   }
-  
-  /** Create a new MapEntry message. */
-  private MapEntry(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+
+  /** Create a MapEntry with the provided key and value. */
+  private MapEntry(Metadata metadata, K key, V value) {
+    this.key = key;
+    this.value = value;
     this.metadata = metadata;
-    this.data = data;
   }
-  
+
+  /** Parsing constructor. */
+  private MapEntry(
+      Metadata<K, V> metadata,
+      CodedInputStream input,
+      ExtensionRegistryLite extensionRegistry)
+      throws InvalidProtocolBufferException {
+    try {
+      this.metadata = metadata;
+      Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry);
+      this.key = entry.getKey();
+      this.value = entry.getValue();
+    } catch (InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (IOException e) {
+      throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(this);
+    }
+  }
+
   /**
    * Create a default MapEntry instance. A default MapEntry instance should be
    * created only once for each map entry message type. Generated code should
    * store the created default instance and use it later to create new MapEntry
-   * messages of the same type. 
+   * messages of the same type.
    */
   public static <K, V> MapEntry<K, V> newDefaultInstance(
       Descriptor descriptor,
@@ -106,30 +126,38 @@
     return new MapEntry<K, V>(
         descriptor, keyType, defaultKey, valueType, defaultValue);
   }
-  
+
   public K getKey() {
-    return data.getKey();
+    return key;
   }
-  
+
   public V getValue() {
-    return data.getValue();
+    return value;
   }
-  
+
+  private volatile int cachedSerializedSize = -1;
+
   @Override
   public int getSerializedSize() {
-    return data.getSerializedSize();
+    if (cachedSerializedSize != -1) {
+      return cachedSerializedSize;
+    }
+
+    int size = MapEntryLite.computeSerializedSize(metadata, key, value);
+    cachedSerializedSize = size;
+    return size;
   }
-  
+
   @Override
   public void writeTo(CodedOutputStream output) throws IOException {
-    data.writeTo(output);
+    MapEntryLite.writeTo(output, metadata, key, value);
   }
-  
+
   @Override
   public boolean isInitialized() {
-    return data.isInitialized();
+    return isInitialized(metadata, value);
   }
-  
+
   @Override
   public Parser<MapEntry<K, V>> getParserForType() {
     return metadata.parser;
@@ -139,15 +167,15 @@
   public Builder<K, V> newBuilderForType() {
     return new Builder<K, V>(metadata);
   }
-  
+
   @Override
   public Builder<K, V> toBuilder() {
-    return new Builder<K, V>(metadata, data);
+    return new Builder<K, V>(metadata, key, value);
   }
 
   @Override
   public MapEntry<K, V> getDefaultInstanceForType() {
-    return metadata.defaultInstance;
+    return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
   }
 
   @Override
@@ -157,8 +185,7 @@
 
   @Override
   public Map<FieldDescriptor, Object> getAllFields() {
-    final TreeMap<FieldDescriptor, Object> result =
-        new TreeMap<FieldDescriptor, Object>();
+    TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
     for (final FieldDescriptor field : metadata.descriptor.getFields()) {
       if (hasField(field)) {
         result.put(field, getField(field));
@@ -166,12 +193,12 @@
     }
     return Collections.unmodifiableMap(result);
   }
-  
+
   private void checkFieldDescriptor(FieldDescriptor field) {
     if (field.getContainingType() != metadata.descriptor) {
       throw new RuntimeException(
           "Wrong FieldDescriptor \"" + field.getFullName()
-          + "\" used in message \"" + metadata.descriptor.getFullName()); 
+          + "\" used in message \"" + metadata.descriptor.getFullName());
     }
   }
 
@@ -217,56 +244,44 @@
   public static class Builder<K, V>
       extends AbstractMessage.Builder<Builder<K, V>> {
     private final Metadata<K, V> metadata;
-    private MapEntryLite<K, V> data;
-    private MapEntryLite.Builder<K, V> dataBuilder;
-    
+    private K key;
+    private V value;
+
     private Builder(Metadata<K, V> metadata) {
-      this.metadata = metadata;
-      this.data = metadata.defaultInstance.data;
-      this.dataBuilder = null;
+      this(metadata, metadata.defaultKey, metadata.defaultValue);
     }
-    
-    private Builder(Metadata<K, V> metadata, MapEntryLite<K, V> data) {
+
+    private Builder(Metadata<K, V> metadata, K key, V value) {
       this.metadata = metadata;
-      this.data = data;
-      this.dataBuilder = null;
+      this.key = key;
+      this.value = value;
     }
-    
+
     public K getKey() {
-      return dataBuilder == null ? data.getKey() : dataBuilder.getKey();
+      return key;
     }
-    
+
     public V getValue() {
-      return dataBuilder == null ? data.getValue() : dataBuilder.getValue();
+      return value;
     }
-    
-    private void ensureMutable() {
-      if (dataBuilder == null) {
-        dataBuilder = data.toBuilder();
-      }
-    }
-    
+
     public Builder<K, V> setKey(K key) {
-      ensureMutable();
-      dataBuilder.setKey(key);
+      this.key = key;
       return this;
     }
-    
+
     public Builder<K, V> clearKey() {
-      ensureMutable();
-      dataBuilder.clearKey();
+      this.key = metadata.defaultKey;
       return this;
     }
-    
+
     public Builder<K, V> setValue(V value) {
-      ensureMutable();
-      dataBuilder.setValue(value);
+      this.value = value;
       return this;
     }
-    
+
     public Builder<K, V> clearValue() {
-      ensureMutable();
-      dataBuilder.clearValue();
+      this.value = metadata.defaultValue;
       return this;
     }
 
@@ -281,29 +296,24 @@
 
     @Override
     public MapEntry<K, V> buildPartial() {
-      if (dataBuilder != null) {
-        data = dataBuilder.buildPartial();
-        dataBuilder = null;
-      }
-      return new MapEntry<K, V>(metadata, data);
+      return new MapEntry<K, V>(metadata, key, value);
     }
 
     @Override
     public Descriptor getDescriptorForType() {
       return metadata.descriptor;
     }
-    
+
     private void checkFieldDescriptor(FieldDescriptor field) {
       if (field.getContainingType() != metadata.descriptor) {
         throw new RuntimeException(
             "Wrong FieldDescriptor \"" + field.getFullName()
-            + "\" used in message \"" + metadata.descriptor.getFullName()); 
+            + "\" used in message \"" + metadata.descriptor.getFullName());
       }
     }
 
     @Override
-    public com.google.protobuf.Message.Builder newBuilderForField(
-        FieldDescriptor field) {
+    public Message.Builder newBuilderForField(FieldDescriptor field) {
       checkFieldDescriptor(field);;
       // This method should be called for message fields and in a MapEntry
       // message only the value field can possibly be a message field.
@@ -312,7 +322,7 @@
         throw new RuntimeException(
             "\"" + field.getFullName() + "\" is not a message value field.");
       }
-      return ((Message) data.getValue()).newBuilderForType();
+      return ((Message) value).newBuilderForType();
     }
 
     @SuppressWarnings("unchecked")
@@ -362,22 +372,17 @@
 
     @Override
     public MapEntry<K, V> getDefaultInstanceForType() {
-      return metadata.defaultInstance;
+      return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue);
     }
 
     @Override
     public boolean isInitialized() {
-      if (dataBuilder != null) {
-        return dataBuilder.isInitialized();
-      } else {
-        return data.isInitialized();
-      }
+      return MapEntry.isInitialized(metadata, value);
     }
 
     @Override
     public Map<FieldDescriptor, Object> getAllFields() {
-      final TreeMap<FieldDescriptor, Object> result =
-          new TreeMap<FieldDescriptor, Object>();
+      final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>();
       for (final FieldDescriptor field : metadata.descriptor.getFields()) {
         if (hasField(field)) {
           result.put(field, getField(field));
@@ -398,8 +403,7 @@
       Object result = field.getNumber() == 1 ? getKey() : getValue();
       // Convert enums to EnumValueDescriptor.
       if (field.getType() == FieldDescriptor.Type.ENUM) {
-        result = field.getEnumType().findValueByNumberCreatingIfUnknown(
-            (java.lang.Integer) result);
+        result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result);
       }
       return result;
     }
@@ -409,13 +413,13 @@
       throw new RuntimeException(
           "There is no repeated field in a map entry message.");
     }
-    
+
     @Override
     public Object getRepeatedField(FieldDescriptor field, int index) {
       throw new RuntimeException(
           "There is no repeated field in a map entry message.");
     }
-    
+
     @Override
     public UnknownFieldSet getUnknownFields() {
       return UnknownFieldSet.getDefaultInstance();
@@ -423,11 +427,14 @@
 
     @Override
     public Builder<K, V> clone() {
-      if (dataBuilder == null) {
-        return new Builder<K, V>(metadata, data);
-      } else {
-        return new Builder<K, V>(metadata, dataBuilder.build());
-      }
+      return new Builder(metadata, key, value);
     }
   }
+
+  private static <V> boolean isInitialized(Metadata metadata, V value) {
+    if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
+      return ((MessageLite) value).isInitialized();
+    }
+    return true;
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
index 12c64ab..22aef8f 100644
--- a/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapEntryLite.java
@@ -31,80 +31,74 @@
 package com.google.protobuf;
 
 import java.io.IOException;
+import java.util.AbstractMap;
+import java.util.Map;
 
 /**
  * Implements the lite version of map entry messages.
- * 
+ *
  * This class serves as an utility class to help do serialization/parsing of
  * map entries. It's used in generated code and also in the full version
  * MapEntry message.
- * 
+ *
  * Protobuf internal. Users shouldn't use.
  */
-public class MapEntryLite<K, V>
-    extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> {
-  private static class Metadata<K, V> {
-    public final MapEntryLite<K, V> defaultInstance;
+public class MapEntryLite<K, V> {
+
+  static class Metadata<K, V> {
     public final WireFormat.FieldType keyType;
+    public final K defaultKey;
     public final WireFormat.FieldType valueType;
-    public final Parser<MapEntryLite<K, V>> parser;
+    public final V defaultValue;
+
     public Metadata(
-        MapEntryLite<K, V> defaultInstance,
-        WireFormat.FieldType keyType,
-        WireFormat.FieldType valueType) {
-      this.defaultInstance = defaultInstance; 
+        WireFormat.FieldType keyType, K defaultKey,
+        WireFormat.FieldType valueType, V defaultValue) {
       this.keyType = keyType;
+      this.defaultKey = defaultKey;
       this.valueType = valueType;
-      final Metadata<K, V> finalThis = this;
-      this.parser = new AbstractParser<MapEntryLite<K, V>>() {
-        @Override
-        public MapEntryLite<K, V> parsePartialFrom(
-            CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-            throws InvalidProtocolBufferException {
-          return new MapEntryLite<K, V>(finalThis, input, extensionRegistry);
-        }
-      };
+      this.defaultValue = defaultValue;
     }
   }
-  
+
   private static final int KEY_FIELD_NUMBER = 1;
   private static final int VALUE_FIELD_NUMBER = 2;
-  
+
   private final Metadata<K, V> metadata;
   private final K key;
   private final V value;
-  
+
   /** Creates a default MapEntryLite message instance. */
   private MapEntryLite(
       WireFormat.FieldType keyType, K defaultKey,
       WireFormat.FieldType valueType, V defaultValue) {
-    this.metadata = new Metadata<K, V>(this, keyType, valueType);
+    this.metadata = new Metadata<K, V>(keyType, defaultKey, valueType, defaultValue);
     this.key = defaultKey;
     this.value = defaultValue;
   }
-  
+
   /** Creates a new MapEntryLite message. */
   private MapEntryLite(Metadata<K, V> metadata, K key, V value) {
     this.metadata = metadata;
     this.key = key;
     this.value = value;
   }
-  
+
   public K getKey() {
     return key;
   }
-  
+
   public V getValue() {
     return value;
   }
 
   /**
    * Creates a default MapEntryLite message instance.
-   * 
+   *
    * This method is used by generated code to create the default instance for
    * a map entry message. The created default instance should be used to create
    * new map entry messages of the same type. For each map entry message, only
-   * one default instance should be created. 
+   * one default instance should be created.
    */
   public static <K, V> MapEntryLite<K, V> newDefaultInstance(
       WireFormat.FieldType keyType, K defaultKey,
@@ -112,80 +106,20 @@
     return new MapEntryLite<K, V>(
         keyType, defaultKey, valueType, defaultValue);
   }
-  
-  @Override
-  public void writeTo(CodedOutputStream output) throws IOException {
-    writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output);
-    writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output);
+
+  static <K, V> void writeTo(CodedOutputStream output, Metadata<K, V> metadata, K key, V value)
+      throws IOException {
+    FieldSet.writeElement(output, metadata.keyType, KEY_FIELD_NUMBER, key);
+    FieldSet.writeElement(output, metadata.valueType, VALUE_FIELD_NUMBER, value);
   }
 
-  private void writeField(
-      int number, WireFormat.FieldType type, Object value,
-      CodedOutputStream output) throws IOException {
-    output.writeTag(number, type.getWireType());
-    FieldSet.writeElementNoTag(output, type, value);
+  static <K, V> int computeSerializedSize(Metadata<K, V> metadata, K key, V value) {
+    return FieldSet.computeElementSize(metadata.keyType, KEY_FIELD_NUMBER, key)
+        + FieldSet.computeElementSize(metadata.valueType, VALUE_FIELD_NUMBER, value);
   }
 
-  private volatile int cachedSerializedSize = -1;
-  @Override
-  public int getSerializedSize() {
-    if (cachedSerializedSize != -1) {
-      return cachedSerializedSize;
-    }
-    int size = 0;
-    size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key);
-    size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value);
-    cachedSerializedSize = size;
-    return size;
-  }
-
-  private int getFieldSize(
-      int number, WireFormat.FieldType type, Object value) {
-    return CodedOutputStream.computeTagSize(number)
-        + FieldSet.computeElementSizeNoTag(type, value);
-  }
-  
-  /** Parsing constructor. */
-  private MapEntryLite(
-      Metadata<K, V> metadata,
-      CodedInputStream input,
-      ExtensionRegistryLite extensionRegistry)
-      throws InvalidProtocolBufferException {
-    try {
-      K key = metadata.defaultInstance.key;
-      V value = metadata.defaultInstance.value;
-      while (true) {
-        int tag = input.readTag();
-        if (tag == 0) {
-          break;
-        }
-        if (tag == WireFormat.makeTag(
-                KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
-          key = mergeField(
-              input, extensionRegistry, metadata.keyType, key);
-        } else if (tag == WireFormat.makeTag(
-                       VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
-          value = mergeField(
-              input, extensionRegistry, metadata.valueType, value);
-        } else {
-          if (!input.skipField(tag)) {
-            break;
-          }
-        }
-      }
-      this.metadata = metadata;
-      this.key = key;
-      this.value = value;
-    } catch (InvalidProtocolBufferException e) {
-      throw e.setUnfinishedMessage(this);
-    } catch (IOException e) {
-      throw new InvalidProtocolBufferException(e.getMessage())
-          .setUnfinishedMessage(this);
-    }
-  }
-  
   @SuppressWarnings("unchecked")
-  private <T> T mergeField(
+  static <T> T parseField(
       CodedInputStream input, ExtensionRegistryLite extensionRegistry,
       WireFormat.FieldType type, T value) throws IOException {
     switch (type) {
@@ -202,136 +136,91 @@
     }
   }
 
-  @Override
-  public Parser<MapEntryLite<K, V>> getParserForType() {
-    return metadata.parser;
-  }
-
-  @Override
-  public Builder<K, V> newBuilderForType() {
-    return new Builder<K, V>(metadata);
-  }
-
-  @Override
-  public Builder<K, V> toBuilder() {
-    return new Builder<K, V>(metadata, key, value);
-  }
-
-  @Override
-  public MapEntryLite<K, V> getDefaultInstanceForType() {
-    return metadata.defaultInstance;
-  }
-
-  @Override
-  public boolean isInitialized() {
-    if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
-      return ((MessageLite) value).isInitialized();
-    }
-    return true;
+  /**
+   * Serializes the provided key and value as though they were wrapped by a {@link MapEntryLite}
+   * to the output stream. This helper method avoids allocation of a {@link MapEntryLite}
+   * built with a key and value and is called from generated code directly.
+   */
+  public void serializeTo(CodedOutputStream output, int fieldNumber, K key, V value)
+      throws IOException {
+    output.writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+    output.writeUInt32NoTag(computeSerializedSize(metadata, key, value));
+    writeTo(output, metadata, key, value);
   }
 
   /**
-   * Builder used to create {@link MapEntryLite} messages.
+   * Computes the message size for the provided key and value as though they were wrapped
+   * by a {@link MapEntryLite}. This helper method avoids allocation of a {@link MapEntryLite}
+   * built with a key and value and is called from generated code directly.
    */
-  public static class Builder<K, V>
-      extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> {
-    private final Metadata<K, V> metadata;
-    private K key;
-    private V value;
-    
-    private Builder(Metadata<K, V> metadata) {
-      this.metadata = metadata;
-      this.key = metadata.defaultInstance.key;
-      this.value = metadata.defaultInstance.value;
-    }
-    
-    public K getKey() {
-      return key;
-    }
-    
-    public V getValue() {
-      return value;
-    }
-    
-    public Builder<K, V> setKey(K key) {
-      this.key = key;
-      return this;
-    }
-    
-    public Builder<K, V> setValue(V value) {
-      this.value = value;
-      return this;
-    }
-    
-    public Builder<K, V> clearKey() {
-      this.key = metadata.defaultInstance.key;
-      return this;
-    }
-    
-    public Builder<K, V> clearValue() {
-      this.value = metadata.defaultInstance.value;
-      return this;
-    }
+  public int computeMessageSize(int fieldNumber, K key, V value) {
+    return CodedOutputStream.computeTagSize(fieldNumber)
+        + CodedOutputStream.computeLengthDelimitedFieldSize(
+            computeSerializedSize(metadata, key, value));
+  }
 
-    @Override
-    public Builder<K, V> clear() {
-      this.key = metadata.defaultInstance.key;
-      this.value = metadata.defaultInstance.value;
-      return this;
-    }
+  /**
+   * Parses an entry off of the input as a {@link Map.Entry}. This helper requires an allocation
+   * so using {@link #parseInto} is preferred if possible.
+   */
+  public Map.Entry<K, V> parseEntry(ByteString bytes, ExtensionRegistryLite extensionRegistry)
+      throws IOException {
+    return parseEntry(bytes.newCodedInput(), metadata, extensionRegistry);
+  }
 
-    @Override
-    public MapEntryLite<K, V> build() {
-      MapEntryLite<K, V> result = buildPartial();
-      if (!result.isInitialized()) {
-        throw newUninitializedMessageException(result);
+  static <K, V> Map.Entry<K, V> parseEntry(
+      CodedInputStream input, Metadata<K, V> metadata, ExtensionRegistryLite extensionRegistry)
+          throws IOException{
+    K key = metadata.defaultKey;
+    V value = metadata.defaultValue;
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
       }
-      return result;
-    }
-
-    @Override
-    public MapEntryLite<K, V> buildPartial() {
-      return new MapEntryLite<K, V>(metadata, key, value);
-    }
-
-    @Override
-    public MessageLite getDefaultInstanceForType() {
-      return metadata.defaultInstance;
-    }
-
-    @Override
-    public boolean isInitialized() {
-      if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) {
-        return ((MessageLite) value).isInitialized();
+      if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
+        key = parseField(input, extensionRegistry, metadata.keyType, key);
+      } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
+        value = parseField(input, extensionRegistry, metadata.valueType, value);
+      } else {
+        if (!input.skipField(tag)) {
+          break;
+        }
       }
-      return true;
+    }
+    return new AbstractMap.SimpleImmutableEntry<K, V>(key, value);
+  }
+
+  /**
+   * Parses an entry off of the input into the map. This helper avoids allocaton of a
+   * {@link MapEntryLite} by parsing directly into the provided {@link MapFieldLite}.
+   */
+  public void parseInto(
+      MapFieldLite<K, V> map, CodedInputStream input, ExtensionRegistryLite extensionRegistry)
+          throws IOException {
+    int length = input.readRawVarint32();
+    final int oldLimit = input.pushLimit(length);
+    K key = metadata.defaultKey;
+    V value = metadata.defaultValue;
+
+    while (true) {
+      int tag = input.readTag();
+      if (tag == 0) {
+        break;
+      }
+      if (tag == WireFormat.makeTag(KEY_FIELD_NUMBER, metadata.keyType.getWireType())) {
+        key = parseField(input, extensionRegistry, metadata.keyType, key);
+      } else if (tag == WireFormat.makeTag(VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) {
+        value = parseField(input, extensionRegistry, metadata.valueType, value);
+      } else {
+        if (!input.skipField(tag)) {
+          break;
+        }
+      }
     }
 
-    private Builder(Metadata<K, V> metadata, K key, V value) {
-      this.metadata = metadata;
-      this.key = key;
-      this.value = value;
-    }
-    
-    @Override
-    public Builder<K, V> clone() {
-      return new Builder<K, V>(metadata, key, value);
-    }
-
-    @Override
-    public Builder<K, V> mergeFrom(
-        CodedInputStream input, ExtensionRegistryLite extensionRegistry)
-        throws IOException {
-      MapEntryLite<K, V> entry =
-          new MapEntryLite<K, V>(metadata, input, extensionRegistry);
-      this.key = entry.key;
-      this.value = entry.value;
-      return this;
-    }
-
-    @Override
-    protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) {
-      throw new UnsupportedOperationException();
-    }
+    input.checkLastTagWas(0);
+    input.popLimit(oldLimit);
+    map.put(key, value);
   }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapField.java b/java/core/src/main/java/com/google/protobuf/MapField.java
index 907f0f7..a6109f9 100644
--- a/java/core/src/main/java/com/google/protobuf/MapField.java
+++ b/java/core/src/main/java/com/google/protobuf/MapField.java
@@ -30,25 +30,26 @@
 
 package com.google.protobuf;
 
-import com.google.protobuf.MapFieldLite.MutatabilityAwareMap;
-
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Internal representation of map fields in generated messages.
- * 
+ *
  * This class supports accessing the map field as a {@link Map} to be used in
  * generated API and also supports accessing the field as a {@link List} to be
  * used in reflection API. It keeps track of where the data is currently stored
- * and do necessary conversions between map and list.  
- * 
+ * and do necessary conversions between map and list.
+ *
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
- * 
+ *
  * THREAD-SAFETY NOTE: Read-only access is thread-safe. Users can call getMap()
  * and getList() concurrently in multiple threads. If write-access is needed,
  * all access must be synchronized.
@@ -56,21 +57,21 @@
 public class MapField<K, V> implements MutabilityOracle {
   /**
    * Indicates where the data of this map field is currently stored.
-   * 
+   *
    * MAP: Data is stored in mapData.
    * LIST: Data is stored in listData.
    * BOTH: mapData and listData have the same data.
    *
    * When the map field is accessed (through generated API or reflection API),
    * it will shift between these 3 modes:
-   * 
+   *
    *          getMap()   getList()   getMutableMap()   getMutableList()
    *   MAP      MAP        BOTH          MAP               LIST
    *   LIST     BOTH       LIST          MAP               LIST
    *   BOTH     BOTH       BOTH          MAP               LIST
-   *   
+   *
    * As the map field changes its mode, the list/map reference returned in a
-   * previous method call may be invalidated. 
+   * previous method call may be invalidated.
    */
   private enum StorageMode {MAP, LIST, BOTH}
 
@@ -78,26 +79,26 @@
   private volatile StorageMode mode;
   private MutatabilityAwareMap<K, V> mapData;
   private List<Message> listData;
-  
+
   // Convert between a map entry Message and a key-value pair.
   private static interface Converter<K, V> {
     Message convertKeyAndValueToMessage(K key, V value);
     void convertMessageToKeyAndValue(Message message, Map<K, V> map);
-    
+
     Message getMessageDefaultInstance();
   }
-  
+
   private static class ImmutableMessageConverter<K, V> implements Converter<K, V> {
     private final MapEntry<K, V> defaultEntry;
     public ImmutableMessageConverter(MapEntry<K, V> defaultEntry) {
       this.defaultEntry = defaultEntry;
     }
-    
+
     @Override
     public Message convertKeyAndValueToMessage(K key, V value) {
       return defaultEntry.newBuilderForType().setKey(key).setValue(value).buildPartial();
     }
-    
+
     @Override
     public void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
       MapEntry<K, V> entry = (MapEntry<K, V>) message;
@@ -109,10 +110,10 @@
       return defaultEntry;
     }
   }
-  
+
 
   private final Converter<K, V> converter;
-  
+
   private MapField(
       Converter<K, V> converter,
       StorageMode mode,
@@ -123,34 +124,34 @@
     this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
     this.listData = null;
   }
-    
+
   private MapField(
       MapEntry<K, V> defaultEntry,
       StorageMode mode,
       Map<K, V> mapData) {
     this(new ImmutableMessageConverter<K, V>(defaultEntry), mode, mapData);
   }
-  
-  
+
+
   /** Returns an immutable empty MapField. */
   public static <K, V> MapField<K, V> emptyMapField(
       MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
         defaultEntry, StorageMode.MAP, Collections.<K, V>emptyMap());
   }
-  
-  
+
+
   /** Creates a new mutable empty MapField. */
   public static <K, V> MapField<K, V> newMapField(MapEntry<K, V> defaultEntry) {
     return new MapField<K, V>(
         defaultEntry, StorageMode.MAP, new LinkedHashMap<K, V>());
   }
-  
-  
+
+
   private Message convertKeyAndValueToMessage(K key, V value) {
     return converter.convertKeyAndValueToMessage(key, value);
   }
-  
+
   @SuppressWarnings("unchecked")
   private void convertMessageToKeyAndValue(Message message, Map<K, V> map) {
     converter.convertMessageToKeyAndValue(message, map);
@@ -173,7 +174,7 @@
     }
     return new MutatabilityAwareMap<K, V>(this, mapData);
   }
-  
+
   /** Returns the content of this MapField as a read-only Map. */
   public Map<K, V> getMap() {
     if (mode == StorageMode.LIST) {
@@ -186,7 +187,7 @@
     }
     return Collections.unmodifiableMap(mapData);
   }
-  
+
   /** Gets a mutable Map view of this MapField. */
   public Map<K, V> getMutableMap() {
     if (mode != StorageMode.MAP) {
@@ -194,20 +195,20 @@
         mapData = convertListToMap(listData);
       }
       listData = null;
-      mode = StorageMode.MAP; 
+      mode = StorageMode.MAP;
     }
     return mapData;
   }
-  
+
   public void mergeFrom(MapField<K, V> other) {
     getMutableMap().putAll(MapFieldLite.copy(other.getMap()));
   }
-  
+
   public void clear() {
     mapData = new MutatabilityAwareMap<K, V>(this, new LinkedHashMap<K, V>());
     mode = StorageMode.MAP;
   }
-  
+
   @SuppressWarnings("unchecked")
   @Override
   public boolean equals(Object object) {
@@ -217,18 +218,18 @@
     MapField<K, V> other = (MapField<K, V>) object;
     return MapFieldLite.<K, V>equals(getMap(), other.getMap());
   }
-  
+
   @Override
   public int hashCode() {
     return MapFieldLite.<K, V>calculateHashCodeForMap(getMap());
   }
-  
+
   /** Returns a deep copy of this MapField. */
   public MapField<K, V> copy() {
     return new MapField<K, V>(
         converter, StorageMode.MAP, MapFieldLite.copy(getMap()));
   }
-  
+
   /** Gets the content of this MapField as a read-only List. */
   List<Message> getList() {
     if (mode == StorageMode.MAP) {
@@ -241,7 +242,7 @@
     }
     return Collections.unmodifiableList(listData);
   }
-  
+
   /** Gets a mutable List view of this MapField. */
   List<Message> getMutableList() {
     if (mode != StorageMode.LIST) {
@@ -253,7 +254,7 @@
     }
     return listData;
   }
-  
+
   /**
    * Gets the default instance of the message stored in the list view of this
    * map field.
@@ -261,7 +262,7 @@
   Message getMapEntryMessageDefaultInstance() {
     return converter.getMessageDefaultInstance();
   }
-  
+
   /**
    * Makes this list immutable. All subsequent modifications will throw an
    * {@link UnsupportedOperationException}.
@@ -269,14 +270,14 @@
   public void makeImmutable() {
     isMutable = false;
   }
-  
+
   /**
    * Returns whether this field can be modified.
    */
   public boolean isMutable() {
     return isMutable;
   }
-  
+
   /* (non-Javadoc)
    * @see com.google.protobuf.MutabilityOracle#ensureMutable()
    */
@@ -286,4 +287,338 @@
       throw new UnsupportedOperationException();
     }
   }
+
+  /**
+   * An internal map that checks for mutability before delegating.
+   */
+  private static class MutatabilityAwareMap<K, V> implements Map<K, V> {
+    private final MutabilityOracle mutabilityOracle;
+    private final Map<K, V> delegate;
+
+    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
+      this.mutabilityOracle = mutabilityOracle;
+      this.delegate = delegate;
+    }
+
+    @Override
+    public int size() {
+      return delegate.size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+      return delegate.isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+      return delegate.containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+      return delegate.containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+      return delegate.get(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+      mutabilityOracle.ensureMutable();
+      return delegate.put(key, value);
+    }
+
+    @Override
+    public V remove(Object key) {
+      mutabilityOracle.ensureMutable();
+      return delegate.remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+      mutabilityOracle.ensureMutable();
+      delegate.putAll(m);
+    }
+
+    @Override
+    public void clear() {
+      mutabilityOracle.ensureMutable();
+      delegate.clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
+    }
+
+    @Override
+    public Collection<V> values() {
+      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+      return delegate.equals(o);
+    }
+
+    @Override
+    public int hashCode() {
+      return delegate.hashCode();
+    }
+
+    @Override
+    public String toString() {
+      return delegate.toString();
+    }
+
+    /**
+     * An internal collection that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareCollection<E> implements Collection<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Collection<E> delegate;
+
+      MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public int size() {
+        return delegate.size();
+      }
+
+      @Override
+      public boolean isEmpty() {
+        return delegate.isEmpty();
+      }
+
+      @Override
+      public boolean contains(Object o) {
+        return delegate.contains(o);
+      }
+
+      @Override
+      public Iterator<E> iterator() {
+        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+      }
+
+      @Override
+      public Object[] toArray() {
+        return delegate.toArray();
+      }
+
+      @Override
+      public <T> T[] toArray(T[] a) {
+        return delegate.toArray(a);
+      }
+
+      @Override
+      public boolean add(E e) {
+        // Unsupported operation in the delegate.
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public boolean remove(Object o) {
+        mutabilityOracle.ensureMutable();
+        return delegate.remove(o);
+      }
+
+      @Override
+      public boolean containsAll(Collection<?> c) {
+        return delegate.containsAll(c);
+      }
+
+      @Override
+      public boolean addAll(Collection<? extends E> c) {
+        // Unsupported operation in the delegate.
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public boolean removeAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.removeAll(c);
+      }
+
+      @Override
+      public boolean retainAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.retainAll(c);
+      }
+
+      @Override
+      public void clear() {
+        mutabilityOracle.ensureMutable();
+        delegate.clear();
+      }
+
+      @Override
+      public boolean equals(Object o) {
+        return delegate.equals(o);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+
+    /**
+     * An internal set that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareSet<E> implements Set<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Set<E> delegate;
+
+      MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public int size() {
+        return delegate.size();
+      }
+
+      @Override
+      public boolean isEmpty() {
+        return delegate.isEmpty();
+      }
+
+      @Override
+      public boolean contains(Object o) {
+        return delegate.contains(o);
+      }
+
+      @Override
+      public Iterator<E> iterator() {
+        return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
+      }
+
+      @Override
+      public Object[] toArray() {
+        return delegate.toArray();
+      }
+
+      @Override
+      public <T> T[] toArray(T[] a) {
+        return delegate.toArray(a);
+      }
+
+      @Override
+      public boolean add(E e) {
+        mutabilityOracle.ensureMutable();
+        return delegate.add(e);
+      }
+
+      @Override
+      public boolean remove(Object o) {
+        mutabilityOracle.ensureMutable();
+        return delegate.remove(o);
+      }
+
+      @Override
+      public boolean containsAll(Collection<?> c) {
+        return delegate.containsAll(c);
+      }
+
+      @Override
+      public boolean addAll(Collection<? extends E> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.addAll(c);
+      }
+
+      @Override
+      public boolean retainAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.retainAll(c);
+      }
+
+      @Override
+      public boolean removeAll(Collection<?> c) {
+        mutabilityOracle.ensureMutable();
+        return delegate.removeAll(c);
+      }
+
+      @Override
+      public void clear() {
+        mutabilityOracle.ensureMutable();
+        delegate.clear();
+      }
+
+      @Override
+      public boolean equals(Object o) {
+        return delegate.equals(o);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+
+    /**
+     * An internal iterator that checks for mutability before delegating.
+     */
+    private static class MutatabilityAwareIterator<E> implements Iterator<E> {
+      private final MutabilityOracle mutabilityOracle;
+      private final Iterator<E> delegate;
+
+      MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
+        this.mutabilityOracle = mutabilityOracle;
+        this.delegate = delegate;
+      }
+
+      @Override
+      public boolean hasNext() {
+        return delegate.hasNext();
+      }
+
+      @Override
+      public E next() {
+        return delegate.next();
+      }
+
+      @Override
+      public void remove() {
+        mutabilityOracle.ensureMutable();
+        delegate.remove();
+      }
+
+      @Override
+      public boolean equals(Object obj) {
+        return delegate.equals(obj);
+      }
+
+      @Override
+      public int hashCode() {
+        return delegate.hashCode();
+      }
+
+      @Override
+      public String toString() {
+        return delegate.toString();
+      }
+    }
+  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
index 960b633..3c0ad89 100644
--- a/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
+++ b/java/core/src/main/java/com/google/protobuf/MapFieldLite.java
@@ -33,71 +33,85 @@
 import com.google.protobuf.Internal.EnumLite;
 
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.Map;
 import java.util.Set;
 
 /**
  * Internal representation of map fields in generated lite-runtime messages.
- * 
+ *
  * This class is a protobuf implementation detail. Users shouldn't use this
  * class directly.
  */
-public final class MapFieldLite<K, V> implements MutabilityOracle {
-  private MutatabilityAwareMap<K, V> mapData;
+public final class MapFieldLite<K, V> extends LinkedHashMap<K, V> {
+
   private boolean isMutable;
-  
-  private MapFieldLite(Map<K, V> mapData) {
-    this.mapData = new MutatabilityAwareMap<K, V>(this, mapData);
+
+  private MapFieldLite() {
     this.isMutable = true;
   }
-  
+
+  private MapFieldLite(Map<K, V> mapData) {
+    super(mapData);
+    this.isMutable = true;
+  }
+
   @SuppressWarnings({"rawtypes", "unchecked"})
-  private static final MapFieldLite EMPTY_MAP_FIELD =
-      new MapFieldLite(Collections.emptyMap());
+  private static final MapFieldLite EMPTY_MAP_FIELD = new MapFieldLite(Collections.emptyMap());
   static {
     EMPTY_MAP_FIELD.makeImmutable();
   }
-  
+
   /** Returns an singleton immutable empty MapFieldLite instance. */
   @SuppressWarnings({"unchecked", "cast"})
   public static <K, V> MapFieldLite<K, V> emptyMapField() {
     return (MapFieldLite<K, V>) EMPTY_MAP_FIELD;
   }
-  
-  /** Creates a new MapFieldLite instance. */
-  public static <K, V> MapFieldLite<K, V> newMapField() {
-    return new MapFieldLite<K, V>(new LinkedHashMap<K, V>());
-  }
-  
-  /** Gets the content of this MapField as a read-only Map. */
-  public Map<K, V> getMap() {
-    return Collections.unmodifiableMap(mapData);
-  }
-  
-  /** Gets a mutable Map view of this MapField. */
-  public Map<K, V> getMutableMap() {
-    return mapData;
-  }
-  
+
   public void mergeFrom(MapFieldLite<K, V> other) {
-    mapData.putAll(copy(other.mapData));
+    ensureMutable();
+    if (!other.isEmpty()) {
+      putAll(other);
+    }
   }
-  
-  public void clear() {
-    mapData.clear();
+
+  @SuppressWarnings({"unchecked", "cast"})
+  @Override public Set<Map.Entry<K, V>> entrySet() {
+    return isEmpty() ? Collections.<Map.Entry<K, V>>emptySet() : super.entrySet();
   }
-  
+
+  @Override public void clear() {
+    ensureMutable();
+    clear();
+  }
+
+  @Override public V put(K key, V value) {
+    ensureMutable();
+    return super.put(key, value);
+  }
+
+  public V put(Map.Entry<K, V> entry) {
+    return put(entry.getKey(), entry.getValue());
+  }
+
+  @Override public void putAll(Map<? extends K, ? extends V> m) {
+    ensureMutable();
+    super.putAll(m);
+  }
+
+  @Override public V remove(Object key) {
+    ensureMutable();
+    return super.remove(key);
+  }
+
   private static boolean equals(Object a, Object b) {
     if (a instanceof byte[] && b instanceof byte[]) {
       return Arrays.equals((byte[]) a, (byte[]) b);
     }
     return a.equals(b);
   }
-  
+
   /**
    * Checks whether two {@link Map}s are equal. We don't use the default equals
    * method of {@link Map} because it compares by identity not by content for
@@ -120,20 +134,16 @@
     }
     return true;
   }
-  
+
   /**
    * Checks whether two map fields are equal.
    */
   @SuppressWarnings("unchecked")
   @Override
   public boolean equals(Object object) {
-    if (!(object instanceof MapFieldLite)) {
-      return false;
-    }
-    MapFieldLite<K, V> other = (MapFieldLite<K, V>) object;
-    return equals(mapData, other.mapData);
+    return (object instanceof Map) && equals(this, (Map<K, V>) object);
   }
-  
+
   private static int calculateHashCodeForObject(Object a) {
     if (a instanceof byte[]) {
       return Internal.hashCode((byte[]) a);
@@ -156,14 +166,14 @@
       result += calculateHashCodeForObject(entry.getKey())
           ^ calculateHashCodeForObject(entry.getValue());
     }
-    return result;    
+    return result;
   }
-  
+
   @Override
   public int hashCode() {
-    return calculateHashCodeForMap(mapData);
+    return calculateHashCodeForMap(this);
   }
-  
+
   private static Object copy(Object object) {
     if (object instanceof byte[]) {
       byte[] data = (byte[]) object;
@@ -171,7 +181,7 @@
     }
     return object;
   }
-  
+
   /**
    * Makes a deep copy of a {@link Map}. Immutable objects in the map will be
    * shared (e.g., integers, strings, immutable messages) and mutable ones will
@@ -185,12 +195,12 @@
     }
     return result;
   }
-  
+
   /** Returns a deep copy of this map field. */
-  public MapFieldLite<K, V> copy() {
-    return new MapFieldLite<K, V>(copy(mapData));
+  public MapFieldLite<K, V> mutableCopy() {
+    return isEmpty() ? new MapFieldLite<K, V>() : new MapFieldLite<K, V>(this);
   }
-  
+
   /**
    * Makes this field immutable. All subsequent modifications will throw an
    * {@link UnsupportedOperationException}.
@@ -198,352 +208,17 @@
   public void makeImmutable() {
     isMutable = false;
   }
-  
+
   /**
    * Returns whether this field can be modified.
    */
   public boolean isMutable() {
     return isMutable;
   }
-  
-  @Override
-  public void ensureMutable() {
+
+  private void ensureMutable() {
     if (!isMutable()) {
       throw new UnsupportedOperationException();
     }
   }
-
-  /**
-   * An internal map that checks for mutability before delegating.
-   */
-  static class MutatabilityAwareMap<K, V> implements Map<K, V> {    
-    private final MutabilityOracle mutabilityOracle;
-    private final Map<K, V> delegate;
-    
-    MutatabilityAwareMap(MutabilityOracle mutabilityOracle, Map<K, V> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean containsKey(Object key) {
-      return delegate.containsKey(key);
-    }
-
-    @Override
-    public boolean containsValue(Object value) {
-      return delegate.containsValue(value);
-    }
-
-    @Override
-    public V get(Object key) {
-      return delegate.get(key);
-    }
-
-    @Override
-    public V put(K key, V value) {
-      mutabilityOracle.ensureMutable();
-      return delegate.put(key, value);
-    }
-
-    @Override
-    public V remove(Object key) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(key);
-    }
-
-    @Override
-    public void putAll(Map<? extends K, ? extends V> m) {
-      mutabilityOracle.ensureMutable();
-      delegate.putAll(m);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public Set<K> keySet() {
-      return new MutatabilityAwareSet<K>(mutabilityOracle, delegate.keySet());
-    }
-
-    @Override
-    public Collection<V> values() {
-      return new MutatabilityAwareCollection<V>(mutabilityOracle, delegate.values());
-    }
-
-    @Override
-    public Set<java.util.Map.Entry<K, V>> entrySet() {
-      return new MutatabilityAwareSet<Entry<K, V>>(mutabilityOracle, delegate.entrySet());
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-
-  /**
-   * An internal collection that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareCollection<E> implements Collection<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Collection<E> delegate;
-    
-    MutatabilityAwareCollection(MutabilityOracle mutabilityOracle, Collection<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-      return delegate.contains(o);
-    }
-
-    @Override
-    public Iterator<E> iterator() {
-      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
-    }
-
-    @Override
-    public Object[] toArray() {
-      return delegate.toArray();
-    }
-
-    @Override
-    public <T> T[] toArray(T[] a) {
-      return delegate.toArray(a);
-    }
-
-    @Override
-    public boolean add(E e) {
-      // Unsupported operation in the delegate.
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(o);
-    }
-
-    @Override
-    public boolean containsAll(Collection<?> c) {
-      return delegate.containsAll(c);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends E> c) {
-      // Unsupported operation in the delegate.
-      throw new UnsupportedOperationException();
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.removeAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.retainAll(c);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-    
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-
-  /**
-   * An internal set that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareSet<E> implements Set<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Set<E> delegate;
-    
-    MutatabilityAwareSet(MutabilityOracle mutabilityOracle, Set<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public int size() {
-      return delegate.size();
-    }
-
-    @Override
-    public boolean isEmpty() {
-      return delegate.isEmpty();
-    }
-
-    @Override
-    public boolean contains(Object o) {
-      return delegate.contains(o);
-    }
-
-    @Override
-    public Iterator<E> iterator() {
-      return new MutatabilityAwareIterator<E>(mutabilityOracle, delegate.iterator());
-    }
-
-    @Override
-    public Object[] toArray() {
-      return delegate.toArray();
-    }
-
-    @Override
-    public <T> T[] toArray(T[] a) {
-      return delegate.toArray(a);
-    }
-
-    @Override
-    public boolean add(E e) {
-      mutabilityOracle.ensureMutable();
-      return delegate.add(e);
-    }
-
-    @Override
-    public boolean remove(Object o) {
-      mutabilityOracle.ensureMutable();
-      return delegate.remove(o);
-    }
-
-    @Override
-    public boolean containsAll(Collection<?> c) {
-      return delegate.containsAll(c);
-    }
-
-    @Override
-    public boolean addAll(Collection<? extends E> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.addAll(c);
-    }
-
-    @Override
-    public boolean retainAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.retainAll(c);
-    }
-
-    @Override
-    public boolean removeAll(Collection<?> c) {
-      mutabilityOracle.ensureMutable();
-      return delegate.removeAll(c);
-    }
-
-    @Override
-    public void clear() {
-      mutabilityOracle.ensureMutable();
-      delegate.clear();
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      return delegate.equals(o);
-    }
-
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
-  
-  /**
-   * An internal iterator that checks for mutability before delegating.
-   */
-  private static class MutatabilityAwareIterator<E> implements Iterator<E> {
-    private final MutabilityOracle mutabilityOracle;
-    private final Iterator<E> delegate;
-    
-    MutatabilityAwareIterator(MutabilityOracle mutabilityOracle, Iterator<E> delegate) {
-      this.mutabilityOracle = mutabilityOracle;
-      this.delegate = delegate;
-    }
-
-    @Override
-    public boolean hasNext() {
-      return delegate.hasNext();
-    }
-
-    @Override
-    public E next() {
-      return delegate.next();
-    }
-
-    @Override
-    public void remove() {
-      mutabilityOracle.ensureMutable();
-      delegate.remove();
-    }
-    
-    @Override
-    public boolean equals(Object obj) {
-      return delegate.equals(obj);
-    }
-    
-    @Override
-    public int hashCode() {
-      return delegate.hashCode();
-    }
-
-    @Override
-    public String toString() {
-      return delegate.toString();
-    }
-  }
 }
diff --git a/java/core/src/main/java/com/google/protobuf/MessageReflection.java b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
index 7b791d9..3d73efb 100644
--- a/java/core/src/main/java/com/google/protobuf/MessageReflection.java
+++ b/java/core/src/main/java/com/google/protobuf/MessageReflection.java
@@ -364,7 +364,6 @@
      * Finishes the merge and returns the underlying object.
      */
     Object finish();
-    
   }
 
   static class BuilderAdapter implements MergeTarget {
@@ -549,7 +548,6 @@
     public Object finish() {
       return builder.buildPartial();
     }
-    
   }
 
 
@@ -713,7 +711,6 @@
       throw new UnsupportedOperationException(
           "finish() called on FieldSet object");
     }
-    
   }
 
   /**
diff --git a/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
new file mode 100644
index 0000000..77b61b5
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.java
@@ -0,0 +1,708 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.AbstractList;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * {@code RepeatedFieldBuilderV3} implements a structure that a protocol
+ * message uses to hold a repeated field of other protocol messages. It supports
+ * the classical use case of adding immutable {@link Message}'s to the
+ * repeated field and is highly optimized around this (no extra memory
+ * allocations and sharing of immutable arrays).
+ * <br>
+ * It also supports the additional use case of adding a {@link Message.Builder}
+ * to the repeated field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class RepeatedFieldBuilderV3
+    <MType extends AbstractMessage,
+     BType extends AbstractMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements AbstractMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private AbstractMessage.BuilderParent parent;
+
+  // List of messages. Never null. It may be immutable, in which case
+  // isMessagesListMutable will be false. See note below.
+  private List<MType> messages;
+
+  // Whether messages is an mutable array that can be modified.
+  private boolean isMessagesListMutable;
+
+  // List of builders. May be null, in which case, no nested builders were
+  // created. If not null, entries represent the builder for that index.
+  private List<SingleFieldBuilderV3<MType, BType, IType>> builders;
+
+  // Here are the invariants for messages and builders:
+  // 1. messages is never null and its count corresponds to the number of items
+  //    in the repeated field.
+  // 2. If builders is non-null, messages and builders MUST always
+  //    contain the same number of items.
+  // 3. Entries in either array can be null, but for any index, there MUST be
+  //    either a Message in messages or a builder in builders.
+  // 4. If the builder at an index is non-null, the builder is
+  //    authoritative. This is the case where a Builder was set on the index.
+  //    Any message in the messages array MUST be ignored.
+  // t. If the builder at an index is null, the message in the messages
+  //    list is authoritative. This is the case where a Message (not a Builder)
+  //    was set directly for an index.
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
+  private boolean isClean;
+
+  // A view of this builder that exposes a List interface of messages. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a message if it
+  // was a builder.
+  private MessageExternalList<MType, BType, IType> externalMessageList;
+
+  // A view of this builder that exposes a List interface of builders. This is
+  // initialized on demand. This is fully backed by this object and all changes
+  // are reflected in it. Access to any item converts it to a builder if it
+  // was a message.
+  private BuilderExternalList<MType, BType, IType> externalBuilderList;
+
+  // A view of this builder that exposes a List interface of the interface
+  // implemented by messages and builders. This is initialized on demand. This
+  // is fully backed by this object and all changes are reflected in it.
+  // Access to any item returns either a builder or message depending on
+  // what is most efficient.
+  private MessageOrBuilderExternalList<MType, BType, IType>
+      externalMessageOrBuilderList;
+
+  /**
+   * Constructs a new builder with an empty list of messages.
+   *
+   * @param messages the current list of messages
+   * @param isMessagesListMutable Whether the messages list is mutable
+   * @param parent a listener to notify of changes
+   * @param isClean whether the builder is initially marked clean
+   */
+  public RepeatedFieldBuilderV3(
+      List<MType> messages,
+      boolean isMessagesListMutable,
+      AbstractMessage.BuilderParent parent,
+      boolean isClean) {
+    this.messages = messages;
+    this.isMessagesListMutable = isMessagesListMutable;
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Ensures that the list of messages is mutable so it can be updated. If it's
+   * immutable, a copy is made.
+   */
+  private void ensureMutableMessageList() {
+    if (!isMessagesListMutable) {
+      messages = new ArrayList<MType>(messages);
+      isMessagesListMutable = true;
+    }
+  }
+
+  /**
+   * Ensures that the list of builders is not null. If it's null, the list is
+   * created and initialized to be the same size as the messages list with
+   * null entries.
+   */
+  private void ensureBuilders() {
+    if (this.builders == null) {
+      this.builders =
+          new ArrayList<SingleFieldBuilderV3<MType, BType, IType>>(
+              messages.size());
+      for (int i = 0; i < messages.size(); i++) {
+        builders.add(null);
+      }
+    }
+  }
+
+  /**
+   * Gets the count of items in the list.
+   *
+   * @return the count of items in the list.
+   */
+  public int getCount() {
+    return messages.size();
+  }
+
+  /**
+   * Gets whether the list is empty.
+   *
+   * @return whether the list is empty
+   */
+  public boolean isEmpty() {
+    return messages.isEmpty();
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @return the message for the specified index
+   */
+  public MType getMessage(int index) {
+    return getMessage(index, false);
+  }
+
+  /**
+   * Get the message at the specified index. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it.
+   *
+   * @param index the index of the message to get
+   * @param forBuild this is being called for build so we want to make sure
+   *     we SingleFieldBuilderV3.build to send dirty invalidations
+   * @return the message for the specified index
+   */
+  private MType getMessage(int index, boolean forBuild) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return messages.get(index);
+    }
+
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return messages.get(index);
+
+    } else {
+      return forBuild ? builder.build() : builder.getMessage();
+    }
+  }
+
+  /**
+   * Gets a builder for the specified index. If no builder has been created for
+   * that index, a builder is created on demand by calling
+   * {@link Message#toBuilder}.
+   *
+   * @param index the index of the message to get
+   * @return The builder for that index
+   */
+  public BType getBuilder(int index) {
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      MType message = messages.get(index);
+      builder = new SingleFieldBuilderV3<MType, BType, IType>(
+          message, this, isClean);
+      builders.set(index, builder);
+    }
+    return builder.getBuilder();
+  }
+
+  /**
+   * Gets the base class interface for the specified index. This may either be
+   * a builder or a message. It will return whatever is more efficient.
+   *
+   * @param index the index of the message to get
+   * @return the message or builder for the index as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder(int index) {
+    if (this.builders == null) {
+      // We don't have any builders -- return the current Message.
+      // This is the case where no builder was created, so we MUST have a
+      // Message.
+      return (IType) messages.get(index);
+    }
+
+    SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
+    if (builder == null) {
+      // We don't have a builder -- return the current message.
+      // This is the case where no builder was created for the entry at index,
+      // so we MUST have a message.
+      return (IType) messages.get(index);
+
+    } else {
+      return builder.getMessageOrBuilder();
+    }
+  }
+
+  /**
+   * Sets a  message at the specified index replacing the existing item at
+   * that index.
+   *
+   * @param index the index to set.
+   * @param message the message to set
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
+      int index, MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.set(index, message);
+    if (builders != null) {
+      SingleFieldBuilderV3<MType, BType, IType> entry =
+          builders.set(index, null);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends the specified element to the end of this list.
+   *
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
+      MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.add(message);
+    if (builders != null) {
+      builders.add(null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Inserts the specified message at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the message
+   * @param message the message to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
+      int index, MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    ensureMutableMessageList();
+    messages.add(index, message);
+    if (builders != null) {
+      builders.add(index, null);
+    }
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends all of the messages in the specified collection to the end of
+   * this list, in the order that they are returned by the specified
+   * collection's iterator.
+   *
+   * @param values the messages to add
+   * @return the builder
+   */
+  public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
+      Iterable<? extends MType> values) {
+    for (final MType value : values) {
+      if (value == null) {
+        throw new NullPointerException();
+      }
+    }
+
+    // If we can inspect the size, we can more efficiently add messages.
+    int size = -1;
+    if (values instanceof Collection) {
+      @SuppressWarnings("unchecked") final
+      Collection<MType> collection = (Collection<MType>) values;
+      if (collection.size() == 0) {
+        return this;
+      }
+      size = collection.size();
+    }
+    ensureMutableMessageList();
+
+    if (size >= 0 && messages instanceof ArrayList) {
+      ((ArrayList<MType>) messages)
+          .ensureCapacity(messages.size() + size);
+    }
+
+    for (MType value : values) {
+      addMessage(value);
+    }
+
+    onChanged();
+    incrementModCounts();
+    return this;
+  }
+
+  /**
+   * Appends a new builder to the end of this list and returns the builder.
+   *
+   * @param message the message to add which is the basis of the builder
+   * @return the new builder
+   */
+  public BType addBuilder(MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder =
+        new SingleFieldBuilderV3<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(null);
+    builders.add(builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Inserts a new builder at the specified position in this list.
+   * Shifts the element currently at that position (if any) and any subsequent
+   * elements to the right (adds one to their indices).
+   *
+   * @param index the index at which to insert the builder
+   * @param message the message to add which is the basis of the builder
+   * @return the builder
+   */
+  public BType addBuilder(int index, MType message) {
+    ensureMutableMessageList();
+    ensureBuilders();
+    SingleFieldBuilderV3<MType, BType, IType> builder =
+        new SingleFieldBuilderV3<MType, BType, IType>(
+            message, this, isClean);
+    messages.add(index, null);
+    builders.add(index, builder);
+    onChanged();
+    incrementModCounts();
+    return builder.getBuilder();
+  }
+
+  /**
+   * Removes the element at the specified position in this list. Shifts any
+   * subsequent elements to the left (subtracts one from their indices).
+   * Returns the element that was removed from the list.
+   *
+   * @param index the index at which to remove the message
+   */
+  public void remove(int index) {
+    ensureMutableMessageList();
+    messages.remove(index);
+    if (builders != null) {
+      SingleFieldBuilderV3<MType, BType, IType> entry =
+          builders.remove(index);
+      if (entry != null) {
+        entry.dispose();
+      }
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Removes all of the elements from this list.
+   * The list will be empty after this call returns.
+   */
+  public void clear() {
+    messages = Collections.emptyList();
+    isMessagesListMutable = false;
+    if (builders != null) {
+      for (SingleFieldBuilderV3<MType, BType, IType> entry :
+          builders) {
+        if (entry != null) {
+          entry.dispose();
+        }
+      }
+      builders = null;
+    }
+    onChanged();
+    incrementModCounts();
+  }
+
+  /**
+   * Builds the list of messages from the builder and returns them.
+   *
+   * @return an immutable list of messages
+   */
+  public List<MType> build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+
+    if (!isMessagesListMutable && builders == null) {
+      // We still have an immutable list and we never created a builder.
+      return messages;
+    }
+
+    boolean allMessagesInSync = true;
+    if (!isMessagesListMutable) {
+      // We still have an immutable list. Let's see if any of them are out
+      // of sync with their builders.
+      for (int i = 0; i < messages.size(); i++) {
+        Message message = messages.get(i);
+        SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(i);
+        if (builder != null) {
+          if (builder.build() != message) {
+            allMessagesInSync = false;
+            break;
+          }
+        }
+      }
+      if (allMessagesInSync) {
+        // Immutable list is still in sync.
+        return messages;
+      }
+    }
+
+    // Need to make sure messages is up to date
+    ensureMutableMessageList();
+    for (int i = 0; i < messages.size(); i++) {
+      messages.set(i, getMessage(i, true));
+    }
+
+    // We're going to return our list as immutable so we mark that we can
+    // no longer update it.
+    messages = Collections.unmodifiableList(messages);
+    isMessagesListMutable = false;
+    return messages;
+  }
+
+  /**
+   * Gets a view of the builder as a list of messages. The returned list is live
+   * and will reflect any changes to the underlying builder.
+   *
+   * @return the messages in the list
+   */
+  public List<MType> getMessageList() {
+    if (externalMessageList == null) {
+      externalMessageList =
+          new MessageExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of builders. This returned list is
+   * live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<BType> getBuilderList() {
+    if (externalBuilderList == null) {
+      externalBuilderList =
+          new BuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalBuilderList;
+  }
+
+  /**
+   * Gets a view of the builder as a list of MessageOrBuilders. This returned
+   * list is live and will reflect any changes to the underlying builder.
+   *
+   * @return the builders in the list
+   */
+  public List<IType> getMessageOrBuilderList() {
+    if (externalMessageOrBuilderList == null) {
+      externalMessageOrBuilderList =
+          new MessageOrBuilderExternalList<MType, BType, IType>(this);
+    }
+    return externalMessageOrBuilderList;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+
+  /**
+   * Increments the mod counts so that an ConcurrentModificationException can
+   * be thrown if calling code tries to modify the builder while its iterating
+   * the list.
+   */
+  private void incrementModCounts() {
+    if (externalMessageList != null) {
+      externalMessageList.incrementModCount();
+    }
+    if (externalBuilderList != null) {
+      externalBuilderList.incrementModCount();
+    }
+    if (externalMessageOrBuilderList != null) {
+      externalMessageOrBuilderList.incrementModCount();
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of messages.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<MType> implements List<MType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    MessageExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public MType get(int index) {
+      return builder.getMessage(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class BuilderExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<BType> implements List<BType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    BuilderExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public BType get(int index) {
+      return builder.getBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+
+  /**
+   * Provides a live view of the builder as a list of builders.
+   *
+   * @param <MType> the type of message for the field
+   * @param <BType> the type of builder for the field
+   * @param <IType> the common interface for the message and the builder
+   */
+  private static class MessageOrBuilderExternalList<
+      MType extends AbstractMessage,
+      BType extends AbstractMessage.Builder,
+      IType extends MessageOrBuilder>
+      extends AbstractList<IType> implements List<IType> {
+
+    RepeatedFieldBuilderV3<MType, BType, IType> builder;
+
+    MessageOrBuilderExternalList(
+        RepeatedFieldBuilderV3<MType, BType, IType> builder) {
+      this.builder = builder;
+    }
+
+    @Override
+    public int size() {
+      return this.builder.getCount();
+    }
+
+    @Override
+    public IType get(int index) {
+      return builder.getMessageOrBuilder(index);
+    }
+
+    void incrementModCount() {
+      modCount++;
+    }
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
new file mode 100644
index 0000000..fb1f76a
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/SingleFieldBuilderV3.java
@@ -0,0 +1,241 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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;
+
+/**
+ * {@code SingleFieldBuilderV3} implements a structure that a protocol
+ * message uses to hold a single field of another protocol message. It supports
+ * the classical use case of setting an immutable {@link Message} as the value
+ * of the field and is highly optimized around this.
+ * <br>
+ * It also supports the additional use case of setting a {@link Message.Builder}
+ * as the field and deferring conversion of that {@code Builder}
+ * to an immutable {@code Message}. In this way, it's possible to maintain
+ * a tree of {@code Builder}'s that acts as a fully read/write data
+ * structure.
+ * <br>
+ * Logically, one can think of a tree of builders as converting the entire tree
+ * to messages when build is called on the root or when any method is called
+ * that desires a Message instead of a Builder. In terms of the implementation,
+ * the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
+ * classes cache messages that were created so that messages only need to be
+ * created when some change occurred in its builder or a builder for one of its
+ * descendants.
+ *
+ * @param <MType> the type of message for the field
+ * @param <BType> the type of builder for the field
+ * @param <IType> the common interface for the message and the builder
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class SingleFieldBuilderV3
+    <MType extends AbstractMessage,
+     BType extends AbstractMessage.Builder,
+     IType extends MessageOrBuilder>
+    implements AbstractMessage.BuilderParent {
+
+  // Parent to send changes to.
+  private AbstractMessage.BuilderParent parent;
+
+  // Invariant: one of builder or message fields must be non-null.
+
+  // If set, this is the case where we are backed by a builder. In this case,
+  // message field represents a cached message for the builder (or null if
+  // there is no cached message).
+  private BType builder;
+
+  // If builder is non-null, this represents a cached message from the builder.
+  // If builder is null, this is the authoritative message for the field.
+  private MType message;
+
+  // Indicates that we've built a message and so we are now obligated
+  // to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
+  private boolean isClean;
+
+  public SingleFieldBuilderV3(
+      MType message,
+      AbstractMessage.BuilderParent parent,
+      boolean isClean) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    this.message = message;
+    this.parent = parent;
+    this.isClean = isClean;
+  }
+
+  public void dispose() {
+    // Null out parent so we stop sending it invalidations.
+    parent = null;
+  }
+
+  /**
+   * Get the message for the field. If the message is currently stored
+   * as a {@code Builder}, it is converted to a {@code Message} by
+   * calling {@link Message.Builder#buildPartial} on it. If no message has
+   * been set, returns the default instance of the message.
+   *
+   * @return the message for the field
+   */
+  @SuppressWarnings("unchecked")
+  public MType getMessage() {
+    if (message == null) {
+      // If message is null, the invariant is that we must be have a builder.
+      message = (MType) builder.buildPartial();
+    }
+    return message;
+  }
+
+  /**
+   * Builds the message and returns it.
+   *
+   * @return the message
+   */
+  public MType build() {
+    // Now that build has been called, we are required to dispatch
+    // invalidations.
+    isClean = true;
+    return getMessage();
+  }
+
+  /**
+   * Gets a builder for the field. If no builder has been created yet, a
+   * builder is created on demand by calling {@link Message#toBuilder}.
+   *
+   * @return The builder for the field
+   */
+  @SuppressWarnings("unchecked")
+  public BType getBuilder() {
+    if (builder == null) {
+      // builder.mergeFrom() on a fresh builder
+      // does not create any sub-objects with independent clean/dirty states,
+      // therefore setting the builder itself to clean without actually calling
+      // build() cannot break any invariants.
+      builder = (BType) message.newBuilderForType(this);
+      builder.mergeFrom(message); // no-op if message is the default message
+      builder.markClean();
+    }
+    return builder;
+  }
+
+  /**
+   * Gets the base class interface for the field. This may either be a builder
+   * or a message. It will return whatever is more efficient.
+   *
+   * @return the message or builder for the field as the base class interface
+   */
+  @SuppressWarnings("unchecked")
+  public IType getMessageOrBuilder() {
+    if (builder != null) {
+      return  (IType) builder;
+    } else {
+      return (IType) message;
+    }
+  }
+
+  /**
+   * Sets a  message for the field replacing any existing value.
+   *
+   * @param message the message to set
+   * @return the builder
+   */
+  public SingleFieldBuilderV3<MType, BType, IType> setMessage(
+      MType message) {
+    if (message == null) {
+      throw new NullPointerException();
+    }
+    this.message = message;
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Merges the field from another field.
+   *
+   * @param value the value to merge from
+   * @return the builder
+   */
+  public SingleFieldBuilderV3<MType, BType, IType> mergeFrom(
+      MType value) {
+    if (builder == null && message == message.getDefaultInstanceForType()) {
+      message = value;
+    } else {
+      getBuilder().mergeFrom(value);
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Clears the value of the field.
+   *
+   * @return the builder
+   */
+  @SuppressWarnings("unchecked")
+  public SingleFieldBuilderV3<MType, BType, IType> clear() {
+    message = (MType) (message != null ?
+        message.getDefaultInstanceForType() :
+        builder.getDefaultInstanceForType());
+    if (builder != null) {
+      builder.dispose();
+      builder = null;
+    }
+    onChanged();
+    return this;
+  }
+
+  /**
+   * Called when a the builder or one of its nested children has changed
+   * and any parent should be notified of its invalidation.
+   */
+  private void onChanged() {
+    // If builder is null, this is the case where onChanged is being called
+    // from setMessage or clear.
+    if (builder != null) {
+      message = null;
+    }
+    if (isClean && parent != null) {
+      parent.markDirty();
+
+      // Don't keep dispatching invalidations until build is called again.
+      isClean = false;
+    }
+  }
+
+  @Override
+  public void markDirty() {
+    onChanged();
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/TextFormat.java b/java/core/src/main/java/com/google/protobuf/TextFormat.java
index c1c328f..ff13675 100644
--- a/java/core/src/main/java/com/google/protobuf/TextFormat.java
+++ b/java/core/src/main/java/com/google/protobuf/TextFormat.java
@@ -661,6 +661,14 @@
       nextToken();
     }
 
+    int getPreviousLine() {
+      return previousLine;
+    }
+
+    int getPreviousColumn() {
+      return previousColumn;
+    }
+
     int getLine() {
       return line;
     }
@@ -1374,6 +1382,28 @@
       return text;
     }
 
+    // Check both unknown fields and unknown extensions and log warming messages
+    // or throw exceptions according to the flag.
+    private void checkUnknownFields(final List<String> unknownFields)
+        throws ParseException {
+      if (unknownFields.isEmpty()) {
+        return;
+      }
+
+      StringBuilder msg = new StringBuilder("Input contains unknown fields and/or extensions:");
+      for (String field : unknownFields) {
+        msg.append('\n').append(field);
+      }
+
+      if (allowUnknownFields) {
+          logger.warning(msg.toString());
+      } else {
+        String[] lineColumn = unknownFields.get(0).split(":");
+        throw new ParseException(Integer.valueOf(lineColumn[0]),
+            Integer.valueOf(lineColumn[1]), msg.toString());
+      }
+    }
+
     /**
      * Parse a text-format message from {@code input} and merge the contents
      * into {@code builder}.  Extensions will be recognized if they are
@@ -1387,9 +1417,13 @@
       MessageReflection.BuilderAdapter target =
           new MessageReflection.BuilderAdapter(builder);
 
+      List<String> unknownFields = new ArrayList<String>();
+
       while (!tokenizer.atEnd()) {
-        mergeField(tokenizer, extensionRegistry, target);
+        mergeField(tokenizer, extensionRegistry, target, unknownFields);
       }
+
+      checkUnknownFields(unknownFields);
     }
 
 
@@ -1399,9 +1433,11 @@
      */
     private void mergeField(final Tokenizer tokenizer,
                             final ExtensionRegistry extensionRegistry,
-                            final MessageReflection.MergeTarget target)
+                            final MessageReflection.MergeTarget target,
+                            List<String> unknownFields)
                             throws ParseException {
-      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder);
+      mergeField(tokenizer, extensionRegistry, target, parseInfoTreeBuilder,
+                 unknownFields);
     }
 
     /**
@@ -1411,7 +1447,8 @@
     private void mergeField(final Tokenizer tokenizer,
                             final ExtensionRegistry extensionRegistry,
                             final MessageReflection.MergeTarget target,
-                            TextFormatParseInfoTree.Builder parseTreeBuilder)
+                            TextFormatParseInfoTree.Builder parseTreeBuilder,
+                            List<String> unknownFields)
                             throws ParseException {
       FieldDescriptor field = null;
       int startLine = tokenizer.getLine();
@@ -1432,13 +1469,9 @@
             extensionRegistry, name.toString());
 
         if (extension == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.parseExceptionPreviousToken(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          } else {
-            logger.warning(
-              "Extension \"" + name + "\" not found in the ExtensionRegistry.");
-          }
+          unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" +
+              (tokenizer.getPreviousColumn() + 1) + ":\t" +
+              type.getFullName() + ".[" + name + "]");
         } else {
           if (extension.descriptor.getContainingType() != type) {
             throw tokenizer.parseExceptionPreviousToken(
@@ -1473,16 +1506,9 @@
         }
 
         if (field == null) {
-          if (!allowUnknownFields) {
-            throw tokenizer.unknownFieldParseExceptionPreviousToken(
-              name,
-              "Message type \"" + type.getFullName()
-              + "\" has no field named \"" + name + "\".");
-          } else {
-            logger.warning(
-              "Message type \"" + type.getFullName()
-              + "\" has no field named \"" + name + "\".");
-          }
+          unknownFields.add((tokenizer.getPreviousLine() + 1) + ":" +
+              (tokenizer.getPreviousColumn() + 1) + ":\t" +
+              type.getFullName() + "." + name);
         }
       }
 
@@ -1511,15 +1537,15 @@
           TextFormatParseInfoTree.Builder childParseTreeBuilder =
               parseTreeBuilder.getBuilderForSubMessageField(field);
           consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
-              childParseTreeBuilder);
+              childParseTreeBuilder, unknownFields);
         } else {
           consumeFieldValues(tokenizer, extensionRegistry, target, field, extension,
-              parseTreeBuilder);
+              parseTreeBuilder, unknownFields);
         }
       } else {
         tokenizer.consume(":");  // required
-        consumeFieldValues(
-            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+        consumeFieldValues(tokenizer, extensionRegistry, target, field,
+            extension, parseTreeBuilder, unknownFields);
       }
 
       if (parseTreeBuilder != null) {
@@ -1544,14 +1570,15 @@
         final MessageReflection.MergeTarget target,
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
-        final TextFormatParseInfoTree.Builder parseTreeBuilder)
+        final TextFormatParseInfoTree.Builder parseTreeBuilder,
+        List<String> unknownFields)
         throws ParseException {
       // Support specifying repeated field values as a comma-separated list.
       // Ex."foo: [1, 2, 3]"
       if (field.isRepeated() && tokenizer.tryConsume("[")) {
         while (true) {
           consumeFieldValue(tokenizer, extensionRegistry, target, field, extension,
-              parseTreeBuilder);
+              parseTreeBuilder, unknownFields);
           if (tokenizer.tryConsume("]")) {
             // End of list.
             break;
@@ -1559,8 +1586,8 @@
           tokenizer.consume(",");
         }
       } else {
-        consumeFieldValue(
-            tokenizer, extensionRegistry, target, field, extension, parseTreeBuilder);
+        consumeFieldValue(tokenizer, extensionRegistry, target, field,
+            extension, parseTreeBuilder, unknownFields);
       }
     }
 
@@ -1574,7 +1601,8 @@
         final MessageReflection.MergeTarget target,
         final FieldDescriptor field,
         final ExtensionRegistry.ExtensionInfo extension,
-        final TextFormatParseInfoTree.Builder parseTreeBuilder)
+        final TextFormatParseInfoTree.Builder parseTreeBuilder,
+        List<String> unknownFields)
         throws ParseException {
       Object value = null;
 
@@ -1596,7 +1624,8 @@
             throw tokenizer.parseException(
               "Expected \"" + endToken + "\".");
           }
-          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder);
+          mergeField(tokenizer, extensionRegistry, subField, parseTreeBuilder,
+              unknownFields);
         }
 
         value = subField.finish();
diff --git a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
index c906420..6d33d3a 100644
--- a/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
+++ b/java/core/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -57,6 +57,7 @@
  * @author kenton@google.com Kenton Varda
  */
 public final class UnknownFieldSet implements MessageLite {
+
   private UnknownFieldSet() {}
 
   /** Create a new {@link Builder}. */
@@ -130,7 +131,8 @@
   @Override
   public void writeTo(final CodedOutputStream output) throws IOException {
     for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
-      entry.getValue().writeTo(entry.getKey(), output);
+      Field field = entry.getValue();
+      field.writeTo(entry.getKey(), output);
     }
   }
 
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
index 0fbf4d4..e72a6b4 100644
--- a/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeByteOperations.java
@@ -42,6 +42,23 @@
  * guaranteed that the buffer backing the {@link ByteString} will never change! Mutation of a
  * {@link ByteString} can lead to unexpected and undesirable consequences in your application,
  * and will likely be difficult to debug. Proceed with caution!
+ *
+ * <p>This can have a number of significant side affects that have
+ * spooky-action-at-a-distance-like behavior. In particular, if the bytes value changes out from
+ * under a Protocol Buffer:
+ * <ul>
+ * <li>serialization may throw
+ * <li>serialization may succeed but the wrong bytes may be written out
+ * <li>messages are no longer threadsafe
+ * <li>hashCode may be incorrect
+ *   <ul>
+ *   <li>can result in a permanent memory leak when used as a key in a long-lived HashMap
+ *   <li> the semantics of many programs may be violated if this is the case
+ *   </ul>
+ * </ul>
+ * Each of these issues will occur in parts of the code base that are entirely distinct from the
+ * parts of the code base modifying the buffer. In fact, both parts of the code base may be correct
+ * - it is the bridging with the unsafe operations that was in error!
  */
 @ExperimentalApi
 public final class UnsafeByteOperations {
diff --git a/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
new file mode 100644
index 0000000..6a4787d
--- /dev/null
+++ b/java/core/src/main/java/com/google/protobuf/UnsafeUtil.java
@@ -0,0 +1,210 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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 sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+import java.nio.Buffer;
+import java.nio.ByteBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedExceptionAction;
+
+/**
+ * Utility class for working with unsafe operations.
+ */
+// TODO(nathanmittler): Add support for Android Memory/MemoryBlock
+final class UnsafeUtil {
+  private static final sun.misc.Unsafe UNSAFE = getUnsafe();
+  private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
+      supportsUnsafeByteBufferOperations();
+  private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
+  private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset();
+  private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.class, "address"));
+
+  private UnsafeUtil() {
+  }
+
+  static boolean hasUnsafeArrayOperations() {
+    return HAS_UNSAFE_ARRAY_OPERATIONS;
+  }
+
+  static boolean hasUnsafeByteBufferOperations() {
+    return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
+  }
+
+  static long getArrayBaseOffset() {
+    return ARRAY_BASE_OFFSET;
+  }
+
+  static byte getByte(byte[] target, long offset) {
+    return UNSAFE.getByte(target, offset);
+  }
+
+  static void putByte(byte[] target, long offset, byte value) {
+    UNSAFE.putByte(target, offset, value);
+  }
+
+  static void copyMemory(
+      byte[] src, long srcOffset, byte[] target, long targetOffset, long length) {
+    UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length);
+  }
+
+  static long getLong(byte[] target, long offset) {
+    return UNSAFE.getLong(target, offset);
+  }
+
+  static byte getByte(long address) {
+    return UNSAFE.getByte(address);
+  }
+
+  static void putByte(long address, byte value) {
+    UNSAFE.putByte(address, value);
+  }
+
+  static long getLong(long address) {
+    return UNSAFE.getLong(address);
+  }
+
+  static void copyMemory(long srcAddress, long targetAddress, long length) {
+    UNSAFE.copyMemory(srcAddress, targetAddress, length);
+  }
+
+  /**
+   * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
+   */
+  static long addressOffset(ByteBuffer buffer) {
+    return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
+  }
+
+  /**
+   * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
+   */
+  private static sun.misc.Unsafe getUnsafe() {
+    sun.misc.Unsafe unsafe = null;
+    try {
+      unsafe =
+          AccessController.doPrivileged(
+              new PrivilegedExceptionAction<Unsafe>() {
+                @Override
+                public sun.misc.Unsafe run() throws Exception {
+                  Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
+
+                  for (Field f : k.getDeclaredFields()) {
+                    f.setAccessible(true);
+                    Object x = f.get(null);
+                    if (k.isInstance(x)) {
+                      return k.cast(x);
+                    }
+                  }
+                  // The sun.misc.Unsafe field does not exist.
+                  return null;
+                }
+              });
+    } catch (Throwable e) {
+      // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
+      // for Unsafe.
+    }
+    return unsafe;
+  }
+
+  /**
+   * Indicates whether or not unsafe array operations are supported on this platform.
+   */
+  private static boolean supportsUnsafeArrayOperations() {
+    boolean supported = false;
+    if (UNSAFE != null) {
+      try {
+        Class<?> clazz = UNSAFE.getClass();
+        clazz.getMethod("arrayBaseOffset", Class.class);
+        clazz.getMethod("getByte", Object.class, long.class);
+        clazz.getMethod("putByte", Object.class, long.class, byte.class);
+        clazz.getMethod("getLong", Object.class, long.class);
+        clazz.getMethod(
+            "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
+        supported = true;
+      } catch (Throwable e) {
+        // Do nothing.
+      }
+    }
+    return supported;
+  }
+
+  private static boolean supportsUnsafeByteBufferOperations() {
+    boolean supported = false;
+    if (UNSAFE != null) {
+      try {
+        Class<?> clazz = UNSAFE.getClass();
+        clazz.getMethod("objectFieldOffset", Field.class);
+        clazz.getMethod("getByte", long.class);
+        clazz.getMethod("getLong", Object.class, long.class);
+        clazz.getMethod("putByte", long.class, byte.class);
+        clazz.getMethod("getLong", long.class);
+        clazz.getMethod("copyMemory", long.class, long.class, long.class);
+        supported = true;
+      } catch (Throwable e) {
+        // Do nothing.
+      }
+    }
+    return supported;
+  }
+
+  /**
+   * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not available.
+   */
+  private static int byteArrayBaseOffset() {
+    return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) : -1;
+  }
+
+  /**
+   * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
+   * available.
+   */
+  private static long fieldOffset(Field field) {
+    return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
+  }
+
+  /**
+   * Gets the field with the given name within the class, or {@code null} if not found. If found,
+   * the field is made accessible.
+   */
+  private static Field field(Class<?> clazz, String fieldName) {
+    Field field;
+    try {
+      field = clazz.getDeclaredField(fieldName);
+      field.setAccessible(true);
+    } catch (Throwable t) {
+      // Failed to access the fields.
+      field = null;
+    }
+    return field;
+  }
+}
diff --git a/java/core/src/main/java/com/google/protobuf/Utf8.java b/java/core/src/main/java/com/google/protobuf/Utf8.java
index 308c69e..5b80d40 100644
--- a/java/core/src/main/java/com/google/protobuf/Utf8.java
+++ b/java/core/src/main/java/com/google/protobuf/Utf8.java
@@ -30,18 +30,16 @@
 
 package com.google.protobuf;
 
+import static com.google.protobuf.UnsafeUtil.addressOffset;
+import static com.google.protobuf.UnsafeUtil.getArrayBaseOffset;
+import static com.google.protobuf.UnsafeUtil.hasUnsafeArrayOperations;
+import static com.google.protobuf.UnsafeUtil.hasUnsafeByteBufferOperations;
 import static java.lang.Character.MAX_SURROGATE;
 import static java.lang.Character.MIN_SURROGATE;
 import static java.lang.Character.isSurrogatePair;
 import static java.lang.Character.toCodePoint;
 
-import java.lang.reflect.Field;
-import java.nio.Buffer;
 import java.nio.ByteBuffer;
-import java.security.AccessController;
-import java.security.PrivilegedExceptionAction;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 
 /**
  * A set of low-level, high-performance static utility methods related
@@ -79,7 +77,6 @@
  */
 // TODO(nathanmittler): Copy changes in this class back to Guava
 final class Utf8 {
-  private static final Logger logger = Logger.getLogger(Utf8.class.getName());
 
   /**
    * UTF-8 is a runtime hot spot so we attempt to provide heavily optimized implementations
@@ -237,7 +234,7 @@
   // fallback to more lenient behavior.
   
   static class UnpairedSurrogateException extends IllegalArgumentException {
-    private UnpairedSurrogateException(int index, int length) {
+    UnpairedSurrogateException(int index, int length) {
       super("Unpaired surrogate at index " + index + " of " + length);
     }
   }
@@ -991,23 +988,11 @@
    * {@link Processor} that uses {@code sun.misc.Unsafe} where possible to improve performance.
    */
   static final class UnsafeProcessor extends Processor {
-    private static final sun.misc.Unsafe UNSAFE = getUnsafe();
-    private static final long BUFFER_ADDRESS_OFFSET =
-        fieldOffset(field(Buffer.class, "address"));
-    private static final int ARRAY_BASE_OFFSET = byteArrayBaseOffset();
-
-    /**
-     * We only use Unsafe operations if we have access to direct {@link ByteBuffer}'s address
-     * and the array base offset is a multiple of 8 (needed by Unsafe.getLong()).
-     */
-    private static final boolean AVAILABLE =
-        BUFFER_ADDRESS_OFFSET != -1 && ARRAY_BASE_OFFSET % 8 == 0;
-
     /**
      * Indicates whether or not all required unsafe operations are supported on this platform.
      */
     static boolean isAvailable() {
-      return AVAILABLE;
+      return hasUnsafeArrayOperations() && hasUnsafeByteBufferOperations();
     }
 
     @Override
@@ -1016,8 +1001,8 @@
         throw new ArrayIndexOutOfBoundsException(
             String.format("Array length=%d, index=%d, limit=%d", bytes.length, index, limit));
       }
-      long offset = ARRAY_BASE_OFFSET + index;
-      final long offsetLimit = ARRAY_BASE_OFFSET + limit;
+      long offset = getArrayBaseOffset() + index;
+      final long offsetLimit = getArrayBaseOffset() + limit;
       if (state != COMPLETE) {
         // The previous decoding operation was incomplete (or malformed).
         // We look for a well-formed sequence consisting of bytes from
@@ -1038,7 +1023,7 @@
           // leading position and overlong 2-byte form.
           if (byte1 < (byte) 0xC2
               // byte2 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else if (byte1 < (byte) 0xF0) {
@@ -1047,7 +1032,7 @@
           // Get byte2 from saved state or array
           int byte2 = (byte) ~(state >> 8);
           if (byte2 == 0) {
-            byte2 = UNSAFE.getByte(bytes, offset++);
+            byte2 = UnsafeUtil.getByte(bytes, offset++);
             if (offset >= offsetLimit) {
               return incompleteStateFor(byte1, byte2);
             }
@@ -1058,7 +1043,7 @@
               // illegal surrogate codepoint?
               || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
               // byte3 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else {
@@ -1068,7 +1053,7 @@
           int byte2 = (byte) ~(state >> 8);
           int byte3 = 0;
           if (byte2 == 0) {
-            byte2 = UNSAFE.getByte(bytes, offset++);
+            byte2 = UnsafeUtil.getByte(bytes, offset++);
             if (offset >= offsetLimit) {
               return incompleteStateFor(byte1, byte2);
             }
@@ -1076,7 +1061,7 @@
             byte3 = (byte) (state >> 16);
           }
           if (byte3 == 0) {
-            byte3 = UNSAFE.getByte(bytes, offset++);
+            byte3 = UnsafeUtil.getByte(bytes, offset++);
             if (offset >= offsetLimit) {
               return incompleteStateFor(byte1, byte2, byte3);
             }
@@ -1095,7 +1080,7 @@
               // byte3 trailing-byte test
               || byte3 > (byte) 0xBF
               // byte4 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         }
@@ -1134,7 +1119,7 @@
           // leading position and overlong 2-byte form.
           if (byte1 < (byte) 0xC2
               // byte2 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else if (byte1 < (byte) 0xF0) {
@@ -1143,7 +1128,7 @@
           // Get byte2 from saved state or array
           int byte2 = (byte) ~(state >> 8);
           if (byte2 == 0) {
-            byte2 = UNSAFE.getByte(address++);
+            byte2 = UnsafeUtil.getByte(address++);
             if (address >= addressLimit) {
               return incompleteStateFor(byte1, byte2);
             }
@@ -1154,7 +1139,7 @@
               // illegal surrogate codepoint?
               || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
               // byte3 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else {
@@ -1164,7 +1149,7 @@
           int byte2 = (byte) ~(state >> 8);
           int byte3 = 0;
           if (byte2 == 0) {
-            byte2 = UNSAFE.getByte(address++);
+            byte2 = UnsafeUtil.getByte(address++);
             if (address >= addressLimit) {
               return incompleteStateFor(byte1, byte2);
             }
@@ -1172,7 +1157,7 @@
             byte3 = (byte) (state >> 16);
           }
           if (byte3 == 0) {
-            byte3 = UNSAFE.getByte(address++);
+            byte3 = UnsafeUtil.getByte(address++);
             if (address >= addressLimit) {
               return incompleteStateFor(byte1, byte2, byte3);
             }
@@ -1191,7 +1176,7 @@
               // byte3 trailing-byte test
               || byte3 > (byte) 0xBF
               // byte4 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         }
@@ -1202,7 +1187,7 @@
 
     @Override
     int encodeUtf8(final CharSequence in, final byte[] out, final int offset, final int length) {
-      long outIx = ARRAY_BASE_OFFSET + offset;
+      long outIx = getArrayBaseOffset() + offset;
       final long outLimit = outIx + length;
       final int inLimit = in.length();
       if (inLimit > length || out.length - length < offset) {
@@ -1215,25 +1200,25 @@
       // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
       int inIx = 0;
       for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
-        UNSAFE.putByte(out, outIx++, (byte) c);
+        UnsafeUtil.putByte(out, outIx++, (byte) c);
       }
       if (inIx == inLimit) {
         // We're done, it was ASCII encoded.
-        return (int) (outIx - ARRAY_BASE_OFFSET);
+        return (int) (outIx - getArrayBaseOffset());
       }
 
       for (char c; inIx < inLimit; ++inIx) {
         c = in.charAt(inIx);
         if (c < 0x80 && outIx < outLimit) {
-          UNSAFE.putByte(out, outIx++, (byte) c);
+          UnsafeUtil.putByte(out, outIx++, (byte) c);
         } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
-          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
         } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
           // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
-          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & c)));
         } else if (outIx <= outLimit - 4L) {
           // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
           // bytes
@@ -1242,10 +1227,10 @@
             throw new UnpairedSurrogateException((inIx - 1), inLimit);
           }
           int codePoint = toCodePoint(c, low);
-          UNSAFE.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
-          UNSAFE.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
+          UnsafeUtil.putByte(out, outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UnsafeUtil.putByte(out, outIx++, (byte) (0x80 | (0x3F & codePoint)));
         } else {
           if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
               && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
@@ -1258,7 +1243,7 @@
       }
 
       // All bytes have been encoded.
-      return (int) (outIx - ARRAY_BASE_OFFSET);
+      return (int) (outIx - getArrayBaseOffset());
     }
 
     @Override
@@ -1277,7 +1262,7 @@
       // https://wikis.oracle.com/display/HotSpotInternals/RangeCheckElimination
       int inIx = 0;
       for (char c; inIx < inLimit && (c = in.charAt(inIx)) < 0x80; ++inIx) {
-        UNSAFE.putByte(outIx++, (byte) c);
+        UnsafeUtil.putByte(outIx++, (byte) c);
       }
       if (inIx == inLimit) {
         // We're done, it was ASCII encoded.
@@ -1288,15 +1273,15 @@
       for (char c; inIx < inLimit; ++inIx) {
         c = in.charAt(inIx);
         if (c < 0x80 && outIx < outLimit) {
-          UNSAFE.putByte(outIx++, (byte) c);
+          UnsafeUtil.putByte(outIx++, (byte) c);
         } else if (c < 0x800 && outIx <= outLimit - 2L) { // 11 bits, two UTF-8 bytes
-          UNSAFE.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 6) | (c >>> 6)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
         } else if ((c < MIN_SURROGATE || MAX_SURROGATE < c) && outIx <= outLimit - 3L) {
           // Maximum single-char code point is 0xFFFF, 16 bits, three UTF-8 bytes
-          UNSAFE.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 5) | (c >>> 12)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (c >>> 6))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & c)));
         } else if (outIx <= outLimit - 4L) {
           // Minimum code point represented by a surrogate pair is 0x10000, 17 bits, four UTF-8
           // bytes
@@ -1305,10 +1290,10 @@
             throw new UnpairedSurrogateException((inIx - 1), inLimit);
           }
           int codePoint = toCodePoint(c, low);
-          UNSAFE.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
-          UNSAFE.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
+          UnsafeUtil.putByte(outIx++, (byte) ((0xF << 4) | (codePoint >>> 18)));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 12))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & (codePoint >>> 6))));
+          UnsafeUtil.putByte(outIx++, (byte) (0x80 | (0x3F & codePoint)));
         } else {
           if ((MIN_SURROGATE <= c && c <= MAX_SURROGATE)
               && (inIx + 1 == inLimit || !isSurrogatePair(c, in.charAt(inIx + 1)))) {
@@ -1349,7 +1334,7 @@
       // we're 8-byte aligned.
       final int unaligned = (int) offset & 7;
       for (int j = unaligned; j > 0; j--) {
-        if (UNSAFE.getByte(bytes, offset++) < 0) {
+        if (UnsafeUtil.getByte(bytes, offset++) < 0) {
           return unaligned - j;
         }
       }
@@ -1358,7 +1343,7 @@
       // To speed things up further, we're reading longs instead of bytes so we use a mask to
       // determine if any byte in the current long is non-ASCII.
       remaining -= unaligned;
-      for (; remaining >= 8 && (UNSAFE.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
+      for (; remaining >= 8 && (UnsafeUtil.getLong(bytes, offset) & ASCII_MASK_LONG) == 0;
           offset += 8, remaining -= 8) {}
       return maxChars - remaining;
     }
@@ -1379,7 +1364,7 @@
       // be read before we're 8-byte aligned.
       final int unaligned = (int) address & 7;
       for (int j = unaligned; j > 0; j--) {
-        if (UNSAFE.getByte(address++) < 0) {
+        if (UnsafeUtil.getByte(address++) < 0) {
           return unaligned - j;
         }
       }
@@ -1388,7 +1373,7 @@
       // To speed things up further, we're reading longs instead of bytes so we use a mask to
       // determine if any byte in the current long is non-ASCII.
       remaining -= unaligned;
-      for (; remaining >= 8 && (UNSAFE.getLong(address) & ASCII_MASK_LONG) == 0;
+      for (; remaining >= 8 && (UnsafeUtil.getLong(address) & ASCII_MASK_LONG) == 0;
           address += 8, remaining -= 8) {}
       return maxChars - remaining;
     }
@@ -1404,7 +1389,7 @@
         // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
         // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
         int byte1 = 0;
-        for (; remaining > 0 && (byte1 = UNSAFE.getByte(bytes, offset++)) >= 0; --remaining) {
+        for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(bytes, offset++)) >= 0; --remaining) {
         }
         if (remaining == 0) {
           return COMPLETE;
@@ -1423,7 +1408,7 @@
           // Simultaneously checks for illegal trailing-byte in
           // leading position and overlong 2-byte form.
           if (byte1 < (byte) 0xC2
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else if (byte1 < (byte) 0xF0) {
@@ -1435,13 +1420,13 @@
           remaining -= 2;
 
           final int byte2;
-          if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+          if ((byte2 = UnsafeUtil.getByte(bytes, offset++)) > (byte) 0xBF
               // overlong? 5 most significant bits must not all be zero
               || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
               // check for illegal surrogate codepoints
               || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
               // byte3 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else {
@@ -1453,16 +1438,16 @@
           remaining -= 3;
 
           final int byte2;
-          if ((byte2 = UNSAFE.getByte(bytes, offset++)) > (byte) 0xBF
+          if ((byte2 = UnsafeUtil.getByte(bytes, offset++)) > (byte) 0xBF
               // Check that 1 <= plane <= 16.  Tricky optimized form of:
               // if (byte1 > (byte) 0xF4 ||
               //     byte1 == (byte) 0xF0 && byte2 < (byte) 0x90 ||
               //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
               || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
               // byte3 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF
               // byte4 trailing-byte test
-              || UNSAFE.getByte(bytes, offset++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(bytes, offset++) > (byte) 0xBF) {
             return MALFORMED;
           }
         }
@@ -1480,7 +1465,7 @@
         // TODO(nathanmittler): Consider checking 8 bytes at a time after some threshold?
         // Maybe after seeing a few in a row that are ASCII, go back to fast mode?
         int byte1 = 0;
-        for (; remaining > 0 && (byte1 = UNSAFE.getByte(address++)) >= 0; --remaining) {
+        for (; remaining > 0 && (byte1 = UnsafeUtil.getByte(address++)) >= 0; --remaining) {
         }
         if (remaining == 0) {
           return COMPLETE;
@@ -1498,7 +1483,7 @@
 
           // Simultaneously checks for illegal trailing-byte in
           // leading position and overlong 2-byte form.
-          if (byte1 < (byte) 0xC2 || UNSAFE.getByte(address++) > (byte) 0xBF) {
+          if (byte1 < (byte) 0xC2 || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else if (byte1 < (byte) 0xF0) {
@@ -1510,14 +1495,14 @@
           }
           remaining -= 2;
 
-          final byte byte2 = UNSAFE.getByte(address++);
+          final byte byte2 = UnsafeUtil.getByte(address++);
           if (byte2 > (byte) 0xBF
               // overlong? 5 most significant bits must not all be zero
               || (byte1 == (byte) 0xE0 && byte2 < (byte) 0xA0)
               // check for illegal surrogate codepoints
               || (byte1 == (byte) 0xED && byte2 >= (byte) 0xA0)
               // byte3 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         } else {
@@ -1529,7 +1514,7 @@
           }
           remaining -= 3;
 
-          final byte byte2 = UNSAFE.getByte(address++);
+          final byte byte2 = UnsafeUtil.getByte(address++);
           if (byte2 > (byte) 0xBF
               // Check that 1 <= plane <= 16.  Tricky optimized form of:
               // if (byte1 > (byte) 0xF4 ||
@@ -1537,9 +1522,9 @@
               //     byte1 == (byte) 0xF4 && byte2 > (byte) 0x8F)
               || (((byte1 << 28) + (byte2 - (byte) 0x90)) >> 30) != 0
               // byte3 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF
               // byte4 trailing-byte test
-              || UNSAFE.getByte(address++) > (byte) 0xBF) {
+              || UnsafeUtil.getByte(address++) > (byte) 0xBF) {
             return MALFORMED;
           }
         }
@@ -1553,11 +1538,11 @@
           return incompleteStateFor(byte1);
         }
         case 1: {
-          return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset));
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset));
         }
         case 2: {
-          return incompleteStateFor(byte1, UNSAFE.getByte(bytes, offset),
-              UNSAFE.getByte(bytes, offset + 1));
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(bytes, offset),
+              UnsafeUtil.getByte(bytes, offset + 1));
         }
         default: {
           throw new AssertionError();
@@ -1571,112 +1556,17 @@
           return incompleteStateFor(byte1);
         }
         case 1: {
-          return incompleteStateFor(byte1, UNSAFE.getByte(address));
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(address));
         }
         case 2: {
-          return incompleteStateFor(byte1, UNSAFE.getByte(address), UNSAFE.getByte(address + 1));
+          return incompleteStateFor(byte1, UnsafeUtil.getByte(address),
+              UnsafeUtil.getByte(address + 1));
         }
         default: {
           throw new AssertionError();
         }
       }
     }
-
-    /**
-     * Gets the field with the given name within the class, or {@code null} if not found. If
-     * found, the field is made accessible.
-     */
-    private static Field field(Class<?> clazz, String fieldName) {
-      Field field;
-      try {
-        field = clazz.getDeclaredField(fieldName);
-        field.setAccessible(true);
-      } catch (Throwable t) {
-        // Failed to access the fields.
-        field = null;
-      }
-      logger.log(Level.FINEST, "{0}.{1}: {2}",
-          new Object[] {clazz.getName(), fieldName, (field != null ? "available" : "unavailable")});
-      return field;
-    }
-
-    /**
-     * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
-     * available.
-     */
-    private static long fieldOffset(Field field) {
-      return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field);
-    }
-
-    /**
-     * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsafe} is not
-     * available.
-     */
-    private static <T> int byteArrayBaseOffset() {
-      return UNSAFE == null ? -1 : UNSAFE.arrayBaseOffset(byte[].class);
-    }
-
-    /**
-     * Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}.
-     */
-    private static long addressOffset(ByteBuffer buffer) {
-      return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET);
-    }
-
-    /**
-     * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this
-     * platform.
-     */
-    private static sun.misc.Unsafe getUnsafe() {
-      sun.misc.Unsafe unsafe = null;
-      try {
-        unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction<sun.misc.Unsafe>() {
-          @Override
-          public sun.misc.Unsafe run() throws Exception {
-            Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
-
-            // Check that this platform supports all of the required unsafe methods.
-            checkRequiredMethods(k);
-
-            for (Field f : k.getDeclaredFields()) {
-              f.setAccessible(true);
-              Object x = f.get(null);
-              if (k.isInstance(x)) {
-                return k.cast(x);
-              }
-            }
-            // The sun.misc.Unsafe field does not exist.
-            return null;
-          }
-        });
-      } catch (Throwable e) {
-        // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
-        // for Unsafe.
-      }
-
-      logger.log(Level.FINEST, "sun.misc.Unsafe: {}",
-          unsafe != null ? "available" : "unavailable");
-      return unsafe;
-    }
-
-    /**
-     * Verifies that all required methods of {@code sun.misc.Unsafe} are available on this platform.
-     */
-    private static void checkRequiredMethods(Class<sun.misc.Unsafe> clazz)
-        throws NoSuchMethodException, SecurityException {
-      // Needed for Unsafe byte[] access
-      clazz.getMethod("arrayBaseOffset", Class.class);
-      clazz.getMethod("getByte", Object.class, long.class);
-      clazz.getMethod("putByte", Object.class, long.class, byte.class);
-      clazz.getMethod("getLong", Object.class, long.class);
-
-      // Needed for Unsafe Direct ByteBuffer access
-      clazz.getMethod("objectFieldOffset", Field.class);
-      clazz.getMethod("getByte", long.class);
-      clazz.getMethod("getLong", Object.class, long.class);
-      clazz.getMethod("putByte", long.class, byte.class);
-      clazz.getMethod("getLong", long.class);
-    }
   }
 
   private Utf8() {}
diff --git a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
index 24b96c6..ec13922 100644
--- a/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/BooleanArrayListTest.java
@@ -40,30 +40,31 @@
 
 /**
  * Tests for {@link BooleanArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class BooleanArrayListTest extends TestCase {
-  
-  private static final BooleanArrayList UNARY_LIST = newImmutableBooleanArrayList(true);
+
+  private static final BooleanArrayList UNARY_LIST =
+      newImmutableBooleanArrayList(true);
   private static final BooleanArrayList TERTIARY_LIST =
-      newImmutableBooleanArrayList(true, true, false);
-  
+      newImmutableBooleanArrayList(true, false, true);
+
   private BooleanArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new BooleanArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(BooleanArrayList.emptyList(), BooleanArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(BooleanArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
     list.addBoolean(true);
     list.addBoolean(false);
@@ -72,16 +73,16 @@
     list.makeImmutable();
     assertImmutable(list);
   }
-  
+
   public void testModificationWithIteration() {
-    list.addAll(asList(true, false, false, true));
+    list.addAll(asList(true, false, true, false));
     Iterator<Boolean> iterator = list.iterator();
     assertEquals(4, list.size());
     assertEquals(true, (boolean) list.get(0));
     assertEquals(true, (boolean) iterator.next());
     list.set(0, true);
     assertEquals(false, (boolean) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -89,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, false);
     try {
@@ -99,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(true, (boolean) TERTIARY_LIST.get(0));
-    assertEquals(true, (boolean) TERTIARY_LIST.get(1));
-    assertEquals(false, (boolean) TERTIARY_LIST.get(2));
-    
+    assertEquals(false, (boolean) TERTIARY_LIST.get(1));
+    assertEquals(true, (boolean) TERTIARY_LIST.get(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -119,19 +120,19 @@
       // expected
     }
   }
-  
-  public void testGetInt() {
+
+  public void testGetBoolean() {
     assertEquals(true, TERTIARY_LIST.getBoolean(0));
-    assertEquals(true, TERTIARY_LIST.getBoolean(1));
-    assertEquals(false, TERTIARY_LIST.getBoolean(2));
-    
+    assertEquals(false, TERTIARY_LIST.getBoolean(1));
+    assertEquals(true, TERTIARY_LIST.getBoolean(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -139,7 +140,7 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, BooleanArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
@@ -150,26 +151,26 @@
     list.addBoolean(false);
     list.addBoolean(false);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
+
     list.add(true);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addBoolean(false);
     list.addBoolean(false);
-    
+
     assertEquals(false, (boolean) list.set(0, true));
     assertEquals(true, list.getBoolean(0));
 
     assertEquals(false, (boolean) list.set(1, false));
     assertEquals(false, list.getBoolean(1));
-    
+
     try {
-      list.set(-1, true);
+      list.set(-1, false);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
@@ -182,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetInt() {
+
+  public void testSetBoolean() {
     list.addBoolean(true);
     list.addBoolean(true);
-    
+
     assertEquals(true, list.setBoolean(0, false));
     assertEquals(false, list.getBoolean(0));
 
     assertEquals(true, list.setBoolean(1, false));
     assertEquals(false, list.getBoolean(1));
-    
+
     try {
       list.setBoolean(-1, false);
       fail();
@@ -201,76 +202,78 @@
     }
 
     try {
-      list.setBoolean(2, true);
+      list.setBoolean(2, false);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
-    assertTrue(list.add(true));
-    assertEquals(asList(true), list);
-
     assertTrue(list.add(false));
+    assertEquals(asList(false), list);
+
+    assertTrue(list.add(true));
     list.add(0, false);
-    assertEquals(asList(false, true, false), list);
-    
-    list.add(0, false);
+    assertEquals(asList(false, false, true), list);
+
     list.add(0, true);
+    list.add(0, false);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
-      list.add(true);
+      list.add(i % 2 == 0);
     }
-    assertEquals(asList(true, false, false, true, false, true, true, true, true, true, true), list);
-    
+    assertEquals(
+        asList(false, true, false, false, true, true, false, true, false, true, false),
+        list);
+
     try {
-      list.add(-1, false);
+      list.add(-1, true);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, true);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
-  public void testAddInt() {
+
+  public void testAddBoolean() {
     assertEquals(0, list.size());
 
-    list.addBoolean(true);
-    assertEquals(asList(true), list);
-
     list.addBoolean(false);
-    assertEquals(asList(true, false), list);
+    assertEquals(asList(false), list);
+
+    list.addBoolean(true);
+    assertEquals(asList(false, true), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
-    assertTrue(list.addAll(Collections.singleton(false)));
+    assertTrue(list.addAll(Collections.singleton(true)));
     assertEquals(1, list.size());
-    assertEquals(false, (boolean) list.get(0));
-    assertEquals(false, list.getBoolean(0));
-    
-    assertTrue(list.addAll(asList(true, false, false, false, true)));
-    assertEquals(asList(false, true, false, false, false, true), list);
-    
+    assertEquals(true, (boolean) list.get(0));
+    assertEquals(true, list.getBoolean(0));
+
+    assertTrue(list.addAll(asList(false, true, false, true, false)));
+    assertEquals(asList(true, false, true, false, true, false), list);
+
     assertTrue(list.addAll(TERTIARY_LIST));
-    assertEquals(asList(false, true, false, false, false, true, true, true, false), list);
+    assertEquals(asList(true, false, true, false, true, false, true, false, true), list);
 
     assertFalse(list.addAll(Collections.<Boolean>emptyList()));
     assertFalse(list.addAll(BooleanArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(true, (boolean) list.remove(0));
-    assertEquals(asList(true, false), list);
+    assertEquals(asList(false, true), list);
 
     assertTrue(list.remove(Boolean.TRUE));
     assertEquals(asList(false), list);
@@ -280,92 +283,93 @@
 
     assertEquals(false, (boolean) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   private void assertImmutable(BooleanArrayList list) {
+
     try {
-      list.add(false);
+      list.add(true);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, true);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.addAll(Collections.singletonList(false));
+      list.addAll(Collections.singletonList(true));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new BooleanArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(true));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.addBoolean(true);
+      list.addBoolean(false);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -379,63 +383,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Boolean>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.retainAll(Collections.singleton(Boolean.TRUE));
+      list.removeAll(Collections.singleton(Boolean.TRUE));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
-      list.set(0, true);
+      list.set(0, false);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setBoolean(0, false);
       fail();
@@ -443,7 +447,7 @@
       // expected
     }
   }
-  
+
   private static BooleanArrayList newImmutableBooleanArrayList(boolean... elements) {
     BooleanArrayList list = new BooleanArrayList();
     for (boolean element : elements) {
diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
index ef89b38..b330244 100644
--- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -382,6 +382,14 @@
     assertEquals(Long.valueOf(8765432109L),
       field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
 
+    OneofDescriptor oneof = descriptor.getOneofs().get(0);
+    assertNotNull(oneof);
+
+    assertTrue(
+      oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
+    assertEquals(Integer.valueOf(-99),
+      oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
+
     EnumDescriptor enumType =
       UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
 
diff --git a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
index 85b418c..8e8e4fe 100644
--- a/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/DoubleArrayListTest.java
@@ -40,39 +40,40 @@
 
 /**
  * Tests for {@link DoubleArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class DoubleArrayListTest extends TestCase {
-  
-  private static final DoubleArrayList UNARY_LIST = newImmutableDoubleArrayList(1);
+
+  private static final DoubleArrayList UNARY_LIST =
+      newImmutableDoubleArrayList(1);
   private static final DoubleArrayList TERTIARY_LIST =
       newImmutableDoubleArrayList(1, 2, 3);
-  
+
   private DoubleArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new DoubleArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(DoubleArrayList.emptyList(), DoubleArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(DoubleArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addDouble(2);
+    list.addDouble(3);
     list.addDouble(4);
-    list.addDouble(6);
-    list.addDouble(8);
+    list.addDouble(5);
+    list.addDouble(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
+
   public void testModificationWithIteration() {
     list.addAll(asList(1D, 2D, 3D, 4D));
     Iterator<Double> iterator = list.iterator();
@@ -81,7 +82,7 @@
     assertEquals(1D, (double) iterator.next());
     list.set(0, 1D);
     assertEquals(2D, (double) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -89,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0D);
     try {
@@ -99,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1D, (double) TERTIARY_LIST.get(0));
     assertEquals(2D, (double) TERTIARY_LIST.get(1));
     assertEquals(3D, (double) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -119,19 +120,19 @@
       // expected
     }
   }
-  
-  public void testGetInt() {
+
+  public void testGetDouble() {
     assertEquals(1D, TERTIARY_LIST.getDouble(0));
     assertEquals(2D, TERTIARY_LIST.getDouble(1));
     assertEquals(3D, TERTIARY_LIST.getDouble(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -139,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, DoubleArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addDouble(2);
+    list.addDouble(3);
     list.addDouble(4);
     list.addDouble(6);
     list.addDouble(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16D);
+
+    list.add(17D);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addDouble(2);
     list.addDouble(4);
-    
-    assertEquals(2D, (double) list.set(0, 0D));
-    assertEquals(0D, list.getDouble(0));
+
+    assertEquals(2D, (double) list.set(0, 3D));
+    assertEquals(3D, list.getDouble(0));
 
     assertEquals(4D, (double) list.set(1, 0D));
     assertEquals(0D, list.getDouble(1));
-    
+
     try {
       list.set(-1, 0D);
       fail();
@@ -182,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetInt() {
-    list.addDouble(2);
-    list.addDouble(4);
-    
-    assertEquals(2D, list.setDouble(0, 0));
+
+  public void testSetDouble() {
+    list.addDouble(1);
+    list.addDouble(3);
+
+    assertEquals(1D, list.setDouble(0, 0));
     assertEquals(0D, list.getDouble(0));
 
-    assertEquals(4D, list.setDouble(1, 0));
+    assertEquals(3D, list.setDouble(1, 0));
     assertEquals(0D, list.getDouble(1));
-    
+
     try {
       list.setDouble(-1, 0);
       fail();
@@ -207,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -217,29 +218,31 @@
     assertTrue(list.add(3D));
     list.add(0, 4D);
     assertEquals(asList(4D, 2D, 3D), list);
-    
+
     list.add(0, 1D);
     list.add(0, 0D);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
       list.add(Double.valueOf(5 + i));
     }
-    assertEquals(asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D), list);
-    
+    assertEquals(
+        asList(0D, 1D, 4D, 2D, 3D, 5D, 6D, 7D, 8D, 9D, 10D),
+        list);
+
     try {
       list.add(-1, 5D);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5D);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
-  public void testAddInt() {
+
+  public void testAddDouble() {
     assertEquals(0, list.size());
 
     list.addDouble(2);
@@ -248,7 +251,7 @@
     list.addDouble(3);
     assertEquals(asList(2D, 3D), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -256,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1D, (double) list.get(0));
     assertEquals(1D, list.getDouble(0));
-    
+
     assertTrue(list.addAll(asList(2D, 3D, 4D, 5D, 6D)));
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1D, 2D, 3D, 4D, 5D, 6D, 1D, 2D, 3D), list);
 
     assertFalse(list.addAll(Collections.<Double>emptyList()));
     assertFalse(list.addAll(DoubleArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1D, (double) list.remove(0));
@@ -280,96 +283,96 @@
 
     assertEquals(2D, (double) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   private void assertImmutable(DoubleArrayList list) {
     if (list.contains(1D)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new DoubleArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addDouble(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -383,28 +386,28 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Double>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
@@ -418,28 +421,28 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1D));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0D);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setDouble(0, 0);
       fail();
@@ -447,7 +450,7 @@
       // expected
     }
   }
-  
+
   private static DoubleArrayList newImmutableDoubleArrayList(double... elements) {
     DoubleArrayList list = new DoubleArrayList();
     for (double element : elements) {
diff --git a/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
new file mode 100644
index 0000000..c124678
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/ExtensionRegistryFactoryTest.java
@@ -0,0 +1,245 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.NonNestedExtension;
+import protobuf_unittest.NonNestedExtensionLite;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.lang.reflect.Method;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Tests for {@link ExtensionRegistryFactory} and the {@link ExtensionRegistry} instances it
+ * creates.
+ * 
+ * <p>This test simulates the runtime behaviour of the ExtensionRegistryFactory by delegating test
+ * definitions to two inner classes {@link InnerTest} and {@link InnerLiteTest}, the latter of
+ * which is executed using a custom ClassLoader, simulating the ProtoLite environment.
+ * 
+ * <p>The test mechanism employed here is based on the pattern in
+ * {@code com.google.common.util.concurrent.AbstractFutureFallbackAtomicHelperTest}
+ */
+public class ExtensionRegistryFactoryTest extends TestCase {
+
+  // A classloader which blacklists some non-Lite classes.
+  private static final ClassLoader LITE_CLASS_LOADER = getLiteOnlyClassLoader();
+
+  /**
+   * Defines the set of test methods which will be run.
+   */
+  static interface RegistryTests {
+    void testCreate();
+    void testEmpty();
+    void testIsFullRegistry();
+    void testAdd();
+  }
+
+  /**
+   * Test implementations for the non-Lite usage of ExtensionRegistryFactory.
+   */
+  public static class InnerTest implements RegistryTests {
+
+    @Override
+    public void testCreate() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+
+      assertEquals(registry.getClass(), ExtensionRegistry.class);
+    }
+
+    @Override
+    public void testEmpty() {
+      ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
+
+      assertEquals(emptyRegistry.getClass(), ExtensionRegistry.class);
+      assertEquals(emptyRegistry, ExtensionRegistry.EMPTY_REGISTRY);
+    }
+
+    @Override
+    public void testIsFullRegistry() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+      assertTrue(ExtensionRegistryFactory.isFullRegistry(registry));
+    }
+
+    @Override
+    public void testAdd() {
+      ExtensionRegistryLite registry1 = ExtensionRegistryLite.newInstance();
+      NonNestedExtensionLite.registerAllExtensions(registry1);
+      registry1.add(NonNestedExtensionLite.nonNestedExtensionLite);
+
+      ExtensionRegistryLite registry2 = ExtensionRegistryLite.newInstance();
+      NonNestedExtension.registerAllExtensions((ExtensionRegistry) registry2);
+      registry2.add(NonNestedExtension.nonNestedExtension);
+
+      ExtensionRegistry fullRegistry1 = (ExtensionRegistry) registry1;
+      ExtensionRegistry fullRegistry2 = (ExtensionRegistry) registry2;
+
+      assertTrue("Test is using a non-lite extension",
+          GeneratedMessageLite.GeneratedExtension.class.isAssignableFrom(
+              NonNestedExtensionLite.nonNestedExtensionLite.getClass()));
+      assertNull("Extension is not registered in masqueraded full registry",
+          fullRegistry1.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
+      GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
+      extension = registry1.findLiteExtensionByNumber(
+          NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
+      assertNotNull("Extension registered in lite registry", extension);
+
+      assertTrue("Test is using a non-lite extension",
+          GeneratedMessage.GeneratedExtension.class.isAssignableFrom(
+          NonNestedExtension.nonNestedExtension.getClass()));
+      assertNotNull("Extension is registered in masqueraded full registry",
+          fullRegistry2.findImmutableExtensionByName("protobuf_unittest.nonNestedExtension"));
+    }
+  }
+
+  /**
+   * Test implementations for the Lite usage of ExtensionRegistryFactory.
+   */
+  public static final class InnerLiteTest implements RegistryTests {
+
+    @Override
+    public void testCreate() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+
+      assertEquals(registry.getClass(), ExtensionRegistryLite.class);
+    }
+
+    @Override
+    public void testEmpty() {
+      ExtensionRegistryLite emptyRegistry = ExtensionRegistryFactory.createEmpty();
+
+      assertEquals(emptyRegistry.getClass(), ExtensionRegistryLite.class);
+      assertEquals(emptyRegistry, ExtensionRegistryLite.EMPTY_REGISTRY_LITE);
+    }
+
+    @Override
+    public void testIsFullRegistry() {
+      ExtensionRegistryLite registry = ExtensionRegistryFactory.create();
+      assertFalse(ExtensionRegistryFactory.isFullRegistry(registry));
+    }
+
+    @Override
+    public void testAdd() {
+      ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+      NonNestedExtensionLite.registerAllExtensions(registry);
+      GeneratedMessageLite.GeneratedExtension<NonNestedExtensionLite.MessageLiteToBeExtended, ?>
+          extension = registry.findLiteExtensionByNumber(
+              NonNestedExtensionLite.MessageLiteToBeExtended.getDefaultInstance(), 1);
+      assertNotNull("Extension is registered in Lite registry", extension);
+    }
+  }
+
+  /**
+   * Defines a suite of tests which the JUnit3 runner retrieves by reflection.
+   */
+  public static Test suite() { 
+    TestSuite suite = new TestSuite();
+    for (Method method : RegistryTests.class.getMethods()) {
+      suite.addTest(TestSuite.createTest(ExtensionRegistryFactoryTest.class, method.getName()));
+    }
+    return suite;
+  }
+
+  /**
+   * Sequentially runs first the Lite and then the non-Lite test variant via classloader
+   * manipulation.
+   */
+  @Override
+  public void runTest() throws Exception {
+    ClassLoader storedClassLoader = Thread.currentThread().getContextClassLoader();
+    Thread.currentThread().setContextClassLoader(LITE_CLASS_LOADER);
+    try {
+      runTestMethod(LITE_CLASS_LOADER, InnerLiteTest.class);
+    } finally {
+      Thread.currentThread().setContextClassLoader(storedClassLoader);
+    }
+    try {
+      runTestMethod(storedClassLoader, InnerTest.class);
+    } finally {
+      Thread.currentThread().setContextClassLoader(storedClassLoader);
+    }
+  }
+
+  private void runTestMethod(ClassLoader classLoader, Class<? extends RegistryTests> testClass)
+      throws Exception {
+    classLoader.loadClass(ExtensionRegistryFactory.class.getName());
+    Class<?> test = classLoader.loadClass(testClass.getName());
+    String testName = getName();
+    test.getMethod(testName).invoke(test.newInstance());
+  }
+
+  /**
+   * Constructs a custom ClassLoader blacklisting the classes which are inspected in the SUT
+   * to determine the Lite/non-Lite runtime.
+   */
+  private static ClassLoader getLiteOnlyClassLoader() {
+    ClassLoader testClassLoader = ExtensionRegistryFactoryTest.class.getClassLoader();
+    final Set<String> classNamesNotInLite =
+        Collections.unmodifiableSet(
+            new HashSet<String>(
+                Arrays.asList(
+                    ExtensionRegistryFactory.FULL_REGISTRY_CLASS_NAME,
+                    ExtensionRegistry.EXTENSION_CLASS_NAME)));
+
+    // Construct a URLClassLoader delegating to the system ClassLoader, and looking up classes
+    // in jar files based on the URLs already configured for this test's UrlClassLoader.
+    // Certain classes throw a ClassNotFoundException by design.
+    return new URLClassLoader(((URLClassLoader) testClassLoader).getURLs(),
+        ClassLoader.getSystemClassLoader()) {
+      @Override
+      public Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
+        if (classNamesNotInLite.contains(name)) {
+          throw new ClassNotFoundException("Class deliberately blacklisted by test.");
+        }
+        Class<?> loadedClass = null;
+        try {
+          loadedClass = findLoadedClass(name);
+          if (loadedClass == null) {
+            loadedClass = findClass(name);
+            if (resolve) {
+              resolveClass(loadedClass);
+            }
+          }
+        } catch (ClassNotFoundException e) {
+          loadedClass = super.loadClass(name, resolve);
+        }
+        return loadedClass;
+      }
+    };
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
index 304cec4..82f4216 100644
--- a/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FieldPresenceTest.java
@@ -152,6 +152,26 @@
     assertFalse(message1.equals(message2));
   }
 
+  public void testLazyField() throws Exception {
+    // Test default constructed message.
+    TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+    TestAllTypes message = builder.build();
+    assertFalse(message.hasOptionalLazyMessage());
+    assertEquals(0, message.getSerializedSize());
+    assertEquals(ByteString.EMPTY, message.toByteString());
+
+    // Set default instance to the field.
+    builder.setOptionalLazyMessage(TestAllTypes.NestedMessage.getDefaultInstance());
+    message = builder.build();
+    assertTrue(message.hasOptionalLazyMessage());
+    assertEquals(2, message.getSerializedSize());
+
+    // Test parse zero-length from wire sets the presence.
+    TestAllTypes parsed = TestAllTypes.parseFrom(message.toByteString());
+    assertTrue(parsed.hasOptionalLazyMessage());
+    assertEquals(message.getOptionalLazyMessage(), parsed.getOptionalLazyMessage());
+  }
+
   public void testFieldPresence() {
     // Optional non-message fields set to their default value are treated the
     // same way as not set.
diff --git a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
index 88a7574..0e13a59 100644
--- a/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/FloatArrayListTest.java
@@ -40,39 +40,40 @@
 
 /**
  * Tests for {@link FloatArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class FloatArrayListTest extends TestCase {
-  
-  private static final FloatArrayList UNARY_LIST = newImmutableFloatArrayList(1);
+
+  private static final FloatArrayList UNARY_LIST =
+      newImmutableFloatArrayList(1);
   private static final FloatArrayList TERTIARY_LIST =
       newImmutableFloatArrayList(1, 2, 3);
-  
+
   private FloatArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new FloatArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(FloatArrayList.emptyList(), FloatArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(FloatArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addFloat(2);
+    list.addFloat(3);
     list.addFloat(4);
-    list.addFloat(6);
-    list.addFloat(8);
+    list.addFloat(5);
+    list.addFloat(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
+
   public void testModificationWithIteration() {
     list.addAll(asList(1F, 2F, 3F, 4F));
     Iterator<Float> iterator = list.iterator();
@@ -81,7 +82,7 @@
     assertEquals(1F, (float) iterator.next());
     list.set(0, 1F);
     assertEquals(2F, (float) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -89,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0F);
     try {
@@ -99,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1F, (float) TERTIARY_LIST.get(0));
     assertEquals(2F, (float) TERTIARY_LIST.get(1));
     assertEquals(3F, (float) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -119,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetFloat() {
     assertEquals(1F, TERTIARY_LIST.getFloat(0));
     assertEquals(2F, TERTIARY_LIST.getFloat(1));
     assertEquals(3F, TERTIARY_LIST.getFloat(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -139,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, FloatArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addFloat(2);
+    list.addFloat(3);
     list.addFloat(4);
     list.addFloat(6);
     list.addFloat(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16F);
+
+    list.add(17F);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addFloat(2);
     list.addFloat(4);
-    
-    assertEquals(2F, (float) list.set(0, 0F));
-    assertEquals(0F, list.getFloat(0));
+
+    assertEquals(2F, (float) list.set(0, 3F));
+    assertEquals(3F, list.getFloat(0));
 
     assertEquals(4F, (float) list.set(1, 0F));
     assertEquals(0F, list.getFloat(1));
-    
+
     try {
       list.set(-1, 0F);
       fail();
@@ -182,17 +183,17 @@
       // expected
     }
   }
-  
+
   public void testSetFloat() {
-    list.addFloat(2);
-    list.addFloat(4);
-    
-    assertEquals(2F, list.setFloat(0, 0));
+    list.addFloat(1);
+    list.addFloat(3);
+
+    assertEquals(1F, list.setFloat(0, 0));
     assertEquals(0F, list.getFloat(0));
 
-    assertEquals(4F, list.setFloat(1, 0));
+    assertEquals(3F, list.setFloat(1, 0));
     assertEquals(0F, list.getFloat(1));
-    
+
     try {
       list.setFloat(-1, 0);
       fail();
@@ -207,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -217,28 +218,30 @@
     assertTrue(list.add(3F));
     list.add(0, 4F);
     assertEquals(asList(4F, 2F, 3F), list);
-    
+
     list.add(0, 1F);
     list.add(0, 0F);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
       list.add(Float.valueOf(5 + i));
     }
-    assertEquals(asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F), list);
-    
+    assertEquals(
+        asList(0F, 1F, 4F, 2F, 3F, 5F, 6F, 7F, 8F, 9F, 10F),
+        list);
+
     try {
       list.add(-1, 5F);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5F);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddFloat() {
     assertEquals(0, list.size());
 
@@ -248,7 +251,7 @@
     list.addFloat(3);
     assertEquals(asList(2F, 3F), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -256,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1F, (float) list.get(0));
     assertEquals(1F, list.getFloat(0));
-    
+
     assertTrue(list.addAll(asList(2F, 3F, 4F, 5F, 6F)));
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1F, 2F, 3F, 4F, 5F, 6F, 1F, 2F, 3F), list);
 
     assertFalse(list.addAll(Collections.<Float>emptyList()));
     assertFalse(list.addAll(FloatArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1F, (float) list.remove(0));
@@ -280,96 +283,96 @@
 
     assertEquals(2F, (float) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   private void assertImmutable(FloatArrayList list) {
     if (list.contains(1F)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new FloatArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addFloat(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -383,63 +386,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Float>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1F));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0F);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setFloat(0, 0);
       fail();
@@ -447,10 +450,10 @@
       // expected
     }
   }
-  
-  private static FloatArrayList newImmutableFloatArrayList(int... elements) {
+
+  private static FloatArrayList newImmutableFloatArrayList(float... elements) {
     FloatArrayList list = new FloatArrayList();
-    for (int element : elements) {
+    for (float element : elements) {
       list.addFloat(element);
     }
     list.makeImmutable();
diff --git a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
index efb8f3e..e59e3c6 100644
--- a/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/IntArrayListTest.java
@@ -40,35 +40,36 @@
 
 /**
  * Tests for {@link IntArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class IntArrayListTest extends TestCase {
-  
-  private static final IntArrayList UNARY_LIST = newImmutableIntArrayList(1);
+
+  private static final IntArrayList UNARY_LIST =
+      newImmutableIntArrayList(1);
   private static final IntArrayList TERTIARY_LIST =
       newImmutableIntArrayList(1, 2, 3);
-  
+
   private IntArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new IntArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(IntArrayList.emptyList(), IntArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(IntArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addInt(2);
+    list.addInt(3);
     list.addInt(4);
-    list.addInt(6);
-    list.addInt(8);
+    list.addInt(5);
+    list.addInt(7);
     list.makeImmutable();
     assertImmutable(list);
   }
@@ -81,7 +82,7 @@
     assertEquals(1, (int) iterator.next());
     list.set(0, 1);
     assertEquals(2, (int) iterator.next());
-    
+
     list.remove(0);
     try {
       iterator.next();
@@ -99,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
     assertEquals(1, (int) TERTIARY_LIST.get(0));
     assertEquals(2, (int) TERTIARY_LIST.get(1));
     assertEquals(3, (int) TERTIARY_LIST.get(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -119,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetInt() {
     assertEquals(1, TERTIARY_LIST.getInt(0));
     assertEquals(2, TERTIARY_LIST.getInt(1));
     assertEquals(3, TERTIARY_LIST.getInt(2));
-    
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -139,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, IntArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addInt(2);
+    list.addInt(3);
     list.addInt(4);
     list.addInt(6);
     list.addInt(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16);
+
+    list.add(17);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addInt(2);
     list.addInt(4);
-    
-    assertEquals(2, (int) list.set(0, 0));
-    assertEquals(0, list.getInt(0));
+
+    assertEquals(2, (int) list.set(0, 3));
+    assertEquals(3, list.getInt(0));
 
     assertEquals(4, (int) list.set(1, 0));
     assertEquals(0, list.getInt(1));
-    
+
     try {
       list.set(-1, 0);
       fail();
@@ -182,17 +183,17 @@
       // expected
     }
   }
-  
+
   public void testSetInt() {
-    list.addInt(2);
-    list.addInt(4);
-    
-    assertEquals(2, list.setInt(0, 0));
+    list.addInt(1);
+    list.addInt(3);
+
+    assertEquals(1, list.setInt(0, 0));
     assertEquals(0, list.getInt(0));
 
-    assertEquals(4, list.setInt(1, 0));
+    assertEquals(3, list.setInt(1, 0));
     assertEquals(0, list.getInt(1));
-    
+
     try {
       list.setInt(-1, 0);
       fail();
@@ -207,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -217,28 +218,30 @@
     assertTrue(list.add(3));
     list.add(0, 4);
     assertEquals(asList(4, 2, 3), list);
-    
+
     list.add(0, 1);
     list.add(0, 0);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
-      list.add(5 + i);
+      list.add(Integer.valueOf(5 + i));
     }
-    assertEquals(asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10), list);
-    
+    assertEquals(
+        asList(0, 1, 4, 2, 3, 5, 6, 7, 8, 9, 10),
+        list);
+
     try {
       list.add(-1, 5);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddInt() {
     assertEquals(0, list.size());
 
@@ -248,7 +251,7 @@
     list.addInt(3);
     assertEquals(asList(2, 3), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
@@ -256,17 +259,17 @@
     assertEquals(1, list.size());
     assertEquals(1, (int) list.get(0));
     assertEquals(1, list.getInt(0));
-    
+
     assertTrue(list.addAll(asList(2, 3, 4, 5, 6)));
     assertEquals(asList(1, 2, 3, 4, 5, 6), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1, 2, 3, 4, 5, 6, 1, 2, 3), list);
 
     assertFalse(list.addAll(Collections.<Integer>emptyList()));
     assertFalse(list.addAll(IntArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
     assertEquals(1, (int) list.remove(0));
@@ -280,96 +283,96 @@
 
     assertEquals(2, (int) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   private void assertImmutable(IntArrayList list) {
     if (list.contains(1)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new IntArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addInt(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -383,63 +386,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Integer>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setInt(0, 0);
       fail();
@@ -447,7 +450,7 @@
       // expected
     }
   }
-  
+
   private static IntArrayList newImmutableIntArrayList(int... elements) {
     IntArrayList list = new IntArrayList();
     for (int element : elements) {
diff --git a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
index afe0fff..e5b11cf 100644
--- a/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LazyMessageLiteTest.java
@@ -251,6 +251,23 @@
     assertEquals(42, merged.getOneofInner().getNumWithDefault());
   }
 
+  // Regression test for b/28198805.
+  public void testMergeOneofMessages() throws Exception {
+    LazyInnerMessageLite inner = LazyInnerMessageLite.newBuilder().build();
+    LazyMessageLite outer = LazyMessageLite.newBuilder().setOneofInner(inner).build();
+    ByteString data1 = outer.toByteString();
+
+    // The following should not alter the content of the 'outer' message.
+    LazyMessageLite.Builder merged = LazyMessageLite.newBuilder().mergeFrom(outer);
+    LazyInnerMessageLite anotherInner = LazyInnerMessageLite.newBuilder().setNum(12345).build();
+    merged.setOneofInner(anotherInner);
+
+    // Check that the 'outer' stays the same.
+    ByteString data2 = outer.toByteString();
+    assertEquals(data1, data2);
+    assertEquals(0, outer.getOneofInner().getNum());
+  }
+
   public void testSerialize() throws InvalidProtocolBufferException {
     LazyNestedInnerMessageLite nested = LazyNestedInnerMessageLite.newBuilder()
         .setNum(3)
diff --git a/java/core/src/test/java/com/google/protobuf/LiteTest.java b/java/core/src/test/java/com/google/protobuf/LiteTest.java
index 88c3e0b..b3a246d 100644
--- a/java/core/src/test/java/com/google/protobuf/LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LiteTest.java
@@ -1630,7 +1630,7 @@
       fail();
     } catch (InvalidProtocolBufferException expected) {}
   }
-  
+
   public void testMergeFrom_sanity() throws Exception {
     TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
     byte[] bytes = one.toByteArray();
@@ -1642,7 +1642,19 @@
     assertEquals(two, one);
     assertEquals(one.hashCode(), two.hashCode());
   }
-  
+
+  public void testMergeFromNoLazyFieldSharing() throws Exception {
+    TestAllTypesLite.Builder sourceBuilder = TestAllTypesLite.newBuilder().setOptionalLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(1));
+    TestAllTypesLite.Builder targetBuilder =
+        TestAllTypesLite.newBuilder().mergeFrom(sourceBuilder.build());
+    assertEquals(1, sourceBuilder.getOptionalLazyMessage().getBb());
+    // now change the sourceBuilder, and target value shouldn't be affected.
+    sourceBuilder.setOptionalLazyMessage(
+        TestAllTypesLite.NestedMessage.newBuilder().setBb(2));
+    assertEquals(1, targetBuilder.getOptionalLazyMessage().getBb());
+  }
+
   public void testEquals_notEqual() throws Exception {
     TestAllTypesLite one = TestUtilLite.getAllLiteSetBuilder().build();
     byte[] bytes = one.toByteArray();
@@ -2202,6 +2214,21 @@
     assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndUnknownFields);
     assertEqualsAndHashCodeAreFalse(fooWithValueAndExtension, fooWithValueAndUnknownFields);
   }
+
+  public void testEqualsAndHashCodeWithExtensions() throws InvalidProtocolBufferException {
+    Foo fooWithOnlyValue = Foo.newBuilder()
+        .setValue(1)
+        .build();
+
+    Foo fooWithValueAndExtension = fooWithOnlyValue.toBuilder()
+        .setValue(1)
+        .setExtension(Bar.fooExt, Bar.newBuilder()
+            .setName("name")
+            .build())
+        .build();
+
+    assertEqualsAndHashCodeAreFalse(fooWithOnlyValue, fooWithValueAndExtension);
+  }
   
   // Test to ensure we avoid a class cast exception with oneofs.
   public void testEquals_oneOfMessages() {
diff --git a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
index 0a8f9ed..6aaf85d 100644
--- a/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
+++ b/java/core/src/test/java/com/google/protobuf/LongArrayListTest.java
@@ -40,48 +40,49 @@
 
 /**
  * Tests for {@link LongArrayList}.
- * 
+ *
  * @author dweis@google.com (Daniel Weis)
  */
 public class LongArrayListTest extends TestCase {
-  
-  private static final LongArrayList UNARY_LIST = newImmutableLongArrayList(1);
+
+  private static final LongArrayList UNARY_LIST =
+      newImmutableLongArrayList(1);
   private static final LongArrayList TERTIARY_LIST =
       newImmutableLongArrayList(1, 2, 3);
-  
+
   private LongArrayList list;
-  
+
   @Override
   protected void setUp() throws Exception {
     list = new LongArrayList();
   }
-  
+
   public void testEmptyListReturnsSameInstance() {
     assertSame(LongArrayList.emptyList(), LongArrayList.emptyList());
   }
-  
+
   public void testEmptyListIsImmutable() {
     assertImmutable(LongArrayList.emptyList());
   }
-  
+
   public void testMakeImmutable() {
-    list.addLong(2);
+    list.addLong(3);
     list.addLong(4);
-    list.addLong(6);
-    list.addLong(8);
+    list.addLong(5);
+    list.addLong(7);
     list.makeImmutable();
     assertImmutable(list);
   }
-  
+
   public void testModificationWithIteration() {
     list.addAll(asList(1L, 2L, 3L, 4L));
     Iterator<Long> iterator = list.iterator();
     assertEquals(4, list.size());
-    assertEquals(1, (long) list.get(0));
-    assertEquals(1, (long) iterator.next());
+    assertEquals(1L, (long) list.get(0));
+    assertEquals(1L, (long) iterator.next());
     list.set(0, 1L);
-    assertEquals(2, (long) iterator.next());
-    
+    assertEquals(2L, (long) iterator.next());
+
     list.remove(0);
     try {
       iterator.next();
@@ -89,7 +90,7 @@
     } catch (ConcurrentModificationException e) {
       // expected
     }
-    
+
     iterator = list.iterator();
     list.add(0, 0L);
     try {
@@ -99,19 +100,19 @@
       // expected
     }
   }
-  
+
   public void testGet() {
-    assertEquals(1, (long) TERTIARY_LIST.get(0));
-    assertEquals(2, (long) TERTIARY_LIST.get(1));
-    assertEquals(3, (long) TERTIARY_LIST.get(2));
-    
+    assertEquals(1L, (long) TERTIARY_LIST.get(0));
+    assertEquals(2L, (long) TERTIARY_LIST.get(1));
+    assertEquals(3L, (long) TERTIARY_LIST.get(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -119,19 +120,19 @@
       // expected
     }
   }
-  
+
   public void testGetLong() {
-    assertEquals(1, TERTIARY_LIST.getLong(0));
-    assertEquals(2, TERTIARY_LIST.getLong(1));
-    assertEquals(3, TERTIARY_LIST.getLong(2));
-    
+    assertEquals(1L, TERTIARY_LIST.getLong(0));
+    assertEquals(2L, TERTIARY_LIST.getLong(1));
+    assertEquals(3L, TERTIARY_LIST.getLong(2));
+
     try {
       TERTIARY_LIST.get(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       TERTIARY_LIST.get(3);
       fail();
@@ -139,35 +140,35 @@
       // expected
     }
   }
-  
+
   public void testSize() {
     assertEquals(0, LongArrayList.emptyList().size());
     assertEquals(1, UNARY_LIST.size());
     assertEquals(3, TERTIARY_LIST.size());
 
-    list.addLong(2);
+    list.addLong(3);
     list.addLong(4);
     list.addLong(6);
     list.addLong(8);
     assertEquals(4, list.size());
-    
+
     list.remove(0);
     assertEquals(3, list.size());
-    
-    list.add(16L);
+
+    list.add(17L);
     assertEquals(4, list.size());
   }
-  
+
   public void testSet() {
     list.addLong(2);
     list.addLong(4);
-    
-    assertEquals(2, (long) list.set(0, 0L));
-    assertEquals(0, list.getLong(0));
 
-    assertEquals(4, (long) list.set(1, 0L));
-    assertEquals(0, list.getLong(1));
-    
+    assertEquals(2L, (long) list.set(0, 3L));
+    assertEquals(3L, list.getLong(0));
+
+    assertEquals(4L, (long) list.set(1, 0L));
+    assertEquals(0L, list.getLong(1));
+
     try {
       list.set(-1, 0L);
       fail();
@@ -182,17 +183,17 @@
       // expected
     }
   }
-  
-  public void testSetLong() {
-    list.addLong(2);
-    list.addLong(4);
-    
-    assertEquals(2, list.setLong(0, 0));
-    assertEquals(0, list.getLong(0));
 
-    assertEquals(4, list.setLong(1, 0));
-    assertEquals(0, list.getLong(1));
-    
+  public void testSetLong() {
+    list.addLong(1);
+    list.addLong(3);
+
+    assertEquals(1L, list.setLong(0, 0));
+    assertEquals(0L, list.getLong(0));
+
+    assertEquals(3L, list.setLong(1, 0));
+    assertEquals(0L, list.getLong(1));
+
     try {
       list.setLong(-1, 0);
       fail();
@@ -207,7 +208,7 @@
       // expected
     }
   }
-  
+
   public void testAdd() {
     assertEquals(0, list.size());
 
@@ -217,28 +218,30 @@
     assertTrue(list.add(3L));
     list.add(0, 4L);
     assertEquals(asList(4L, 2L, 3L), list);
-    
+
     list.add(0, 1L);
     list.add(0, 0L);
     // Force a resize by getting up to 11 elements.
     for (int i = 0; i < 6; i++) {
       list.add(Long.valueOf(5 + i));
     }
-    assertEquals(asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L), list);
-    
+    assertEquals(
+        asList(0L, 1L, 4L, 2L, 3L, 5L, 6L, 7L, 8L, 9L, 10L),
+        list);
+
     try {
       list.add(-1, 5L);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.add(4, 5L);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   public void testAddLong() {
     assertEquals(0, list.size());
 
@@ -248,128 +251,128 @@
     list.addLong(3);
     assertEquals(asList(2L, 3L), list);
   }
-  
+
   public void testAddAll() {
     assertEquals(0, list.size());
 
     assertTrue(list.addAll(Collections.singleton(1L)));
     assertEquals(1, list.size());
-    assertEquals(1, (long) list.get(0));
-    assertEquals(1, list.getLong(0));
-    
+    assertEquals(1L, (long) list.get(0));
+    assertEquals(1L, list.getLong(0));
+
     assertTrue(list.addAll(asList(2L, 3L, 4L, 5L, 6L)));
     assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L), list);
-    
+
     assertTrue(list.addAll(TERTIARY_LIST));
     assertEquals(asList(1L, 2L, 3L, 4L, 5L, 6L, 1L, 2L, 3L), list);
 
     assertFalse(list.addAll(Collections.<Long>emptyList()));
     assertFalse(list.addAll(LongArrayList.emptyList()));
   }
-  
+
   public void testRemove() {
     list.addAll(TERTIARY_LIST);
-    assertEquals(1, (long) list.remove(0));
+    assertEquals(1L, (long) list.remove(0));
     assertEquals(asList(2L, 3L), list);
 
-    assertTrue(list.remove(3L));
+    assertTrue(list.remove(Long.valueOf(3)));
     assertEquals(asList(2L), list);
 
-    assertFalse(list.remove(3L));
+    assertFalse(list.remove(Long.valueOf(3)));
     assertEquals(asList(2L), list);
 
-    assertEquals(2, (long) list.remove(0));
+    assertEquals(2L, (long) list.remove(0));
     assertEquals(asList(), list);
-    
+
     try {
       list.remove(-1);
       fail();
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
-    
+
     try {
       list.remove(0);
     } catch (IndexOutOfBoundsException e) {
       // expected
     }
   }
-  
+
   private void assertImmutable(LongArrayList list) {
     if (list.contains(1L)) {
       throw new RuntimeException("Cannot test the immutability of lists that contain 1.");
     }
-    
+
     try {
       list.add(1L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.add(0, 1L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(Collections.singletonList(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(new LongArrayList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addAll(0, Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.addLong(0);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.clear();
       fail();
@@ -383,63 +386,63 @@
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.remove(new Object());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.removeAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.<Long>emptyList());
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(Collections.singleton(1L));
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.retainAll(UNARY_LIST);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.set(0, 0L);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
-    
+
     try {
       list.setLong(0, 0);
       fail();
@@ -447,7 +450,7 @@
       // expected
     }
   }
-  
+
   private static LongArrayList newImmutableLongArrayList(long... elements) {
     LongArrayList list = new LongArrayList();
     for (long element : elements) {
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
index d79d002..04d5800 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2LiteTest.java
@@ -30,12 +30,16 @@
 
 package com.google.protobuf;
 
+import map_lite_test.MapForProto2TestProto.BizarroTestMap;
 import map_lite_test.MapForProto2TestProto.TestMap;
 import map_lite_test.MapForProto2TestProto.TestMap.MessageValue;
+import map_lite_test.MapForProto2TestProto.TestMapOrBuilder;
 import map_lite_test.MapForProto2TestProto.TestUnknownEnumValue;
 
 import junit.framework.TestCase;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -44,34 +48,40 @@
 /**
  * Unit tests for map fields.
  */
-public class MapForProto2LiteTest extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
-    builder.getMutableInt32ToInt32Field().put(1, 11);
-    builder.getMutableInt32ToInt32Field().put(2, 22);
-    builder.getMutableInt32ToInt32Field().put(3, 33);
+public final class MapForProto2LiteTest extends TestCase {
 
-    builder.getMutableInt32ToStringField().put(1, "11");
-    builder.getMutableInt32ToStringField().put(2, "22");
-    builder.getMutableInt32ToStringField().put(3, "33");
-    
-    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
-    builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
-    builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-    
-    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
-    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
-    builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-    
-    builder.getMutableInt32ToMessageField().put(
-        1, MessageValue.newBuilder().setValue(11).build());
-    builder.getMutableInt32ToMessageField().put(
-        2, MessageValue.newBuilder().setValue(22).build());
-    builder.getMutableInt32ToMessageField().put(
-        3, MessageValue.newBuilder().setValue(33).build());
-    
-    builder.getMutableStringToInt32Field().put("1", 11);
-    builder.getMutableStringToInt32Field().put("2", 22);
-    builder.getMutableStringToInt32Field().put("3", 33);
+  private void setMapValues(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    setMapValues(mapBuilder);
+    TestMap map = mapBuilder.build();
+    assertMapValuesSet(map);
   }
 
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
@@ -94,22 +104,22 @@
     assertEquals("11", message.getInt32ToStringField().get(1));
     assertEquals("22", message.getInt32ToStringField().get(2));
     assertEquals("33", message.getInt32ToStringField().get(3));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(11, message.getStringToInt32Field().get("1").intValue());
     assertEquals(22, message.getStringToInt32Field().get("2").intValue());
@@ -117,31 +127,42 @@
   }
 
   private void updateMapValues(TestMap.Builder builder) {
-    builder.getMutableInt32ToInt32Field().put(1, 111);
-    builder.getMutableInt32ToInt32Field().remove(2);
-    builder.getMutableInt32ToInt32Field().put(4, 44);
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
 
-    builder.getMutableInt32ToStringField().put(1, "111");
-    builder.getMutableInt32ToStringField().remove(2);
-    builder.getMutableInt32ToStringField().put(4, "44");
-    
-    builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
-    builder.getMutableInt32ToBytesField().remove(2);
-    builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-    
-    builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
-    builder.getMutableInt32ToEnumField().remove(2);
-    builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-    
-    builder.getMutableInt32ToMessageField().put(
-        1, MessageValue.newBuilder().setValue(111).build());
-    builder.getMutableInt32ToMessageField().remove(2);
-    builder.getMutableInt32ToMessageField().put(
-        4, MessageValue.newBuilder().setValue(44).build());
-    
-    builder.getMutableStringToInt32Field().put("1", 111);
-    builder.getMutableStringToInt32Field().remove("2");
-    builder.getMutableStringToInt32Field().put("4", 44);
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder mapBuilder = TestMap.newBuilder();
+    setMapValues(mapBuilder);
+    TestMap map = mapBuilder.build();
+    assertMapValuesSet(map);
+
+    mapBuilder = map.toBuilder();
+    updateMapValues(mapBuilder);
+    map = mapBuilder.build();
+    assertMapValuesUpdated(map);
   }
 
   private void assertMapValuesUpdated(TestMap message) {
@@ -154,188 +175,149 @@
     assertEquals("111", message.getInt32ToStringField().get(1));
     assertEquals("33", message.getInt32ToStringField().get(3));
     assertEquals("44", message.getInt32ToStringField().get(4));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
     assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
     assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
     assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(111, message.getStringToInt32Field().get("1").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
 
   public void testSanityCopyOnWrite() throws InvalidProtocolBufferException {
     // Since builders are implemented as a thin wrapper around a message
     // instance, we attempt to verify that we can't cause the builder to modify
     // a produced message.
-    
+
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
-    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
-    intMap.put(1, 2);
+    builder.putInt32ToInt32Field(1, 2);
     assertTrue(message.getInt32ToInt32Field().isEmpty());
     message = builder.build();
-    try {
-      intMap.put(2, 3);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    builder.getMutableInt32ToInt32Field().put(2, 3);
+    builder.putInt32ToInt32Field(2, 3);
     assertEquals(newMap(1, 2), message.getInt32ToInt32Field());
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
   }
-  
-  public void testMutableMapLifecycle() {
+
+  public void testGetMapIsImmutable() {
     TestMap.Builder builder = TestMap.newBuilder();
-    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
-    intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValues(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
     try {
-      intMap.put(2, 3);
+      map.put(key, value);
       fail();
     } catch (UnsupportedOperationException e) {
       // expected
     }
+    if (!map.isEmpty()) {
+      try {
+        map.entrySet().remove(map.entrySet().iterator().next());
+        fail();
+      } catch (UnsupportedOperationException e) {
+        // expected
+      }
+    }
+  }
+
+  public void testMutableMapLifecycle() {
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2);
+    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    builder.getMutableInt32ToInt32Field().put(2, 3);
+    builder.putInt32ToInt32Field(2, 3);
     assertEquals(newMap(1, 2, 2, 3), builder.getInt32ToInt32Field());
 
-    Map<Integer, TestMap.EnumValue> enumMap = builder.getMutableInt32ToEnumField();
-    enumMap.put(1, TestMap.EnumValue.BAR);
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.BAR);
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.build().getInt32ToEnumField());
-    try {
-      enumMap.put(2, TestMap.EnumValue.FOO);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, TestMap.EnumValue.BAR), builder.getInt32ToEnumField());
-    builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.FOO);
+    builder.putInt32ToEnumField(2, TestMap.EnumValue.FOO);
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
-    Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
-    stringMap.put(1, "1");
+
+    builder.putInt32ToStringField(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
-    try {
-      stringMap.put(2, "2");
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, "1"), builder.getInt32ToStringField());
-    builder.getMutableInt32ToStringField().put(2, "2");
-    assertEquals(
-        newMap(1, "1", 2, "2"),
-        builder.getInt32ToStringField());
-    
-    Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
-    messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToStringField(2, "2");
+    assertEquals(newMap(1, "1", 2, "2"), builder.getInt32ToStringField());
+
+    builder.putInt32ToMessageField(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.build().getInt32ToMessageField());
-    try {
-      messageMap.put(2, TestMap.MessageValue.getDefaultInstance());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
-    builder.getMutableInt32ToMessageField().put(2, TestMap.MessageValue.getDefaultInstance());
+    builder.putInt32ToMessageField(2, TestMap.MessageValue.getDefaultInstance());
     assertEquals(
         newMap(1, TestMap.MessageValue.getDefaultInstance(),
             2, TestMap.MessageValue.getDefaultInstance()),
         builder.getInt32ToMessageField());
   }
 
-  public void testMutableMapLifecycle_collections() {
-    TestMap.Builder builder = TestMap.newBuilder();
-    Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
-    intMap.put(1, 2);
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
-    try {
-      intMap.remove(2);
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.entrySet().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.entrySet().iterator().remove();
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.keySet().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.values().remove(new Object());
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    try {
-      intMap.values().iterator().remove();
-      fail();
-    } catch (UnsupportedOperationException e) {
-      // expected
-    }
-    assertEquals(newMap(1, 2), intMap);
-    assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
-    assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
-  }
-
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
-    
+
     builder = message.toBuilder();
     setMapValues(builder);
     message = builder.build();
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
@@ -344,12 +326,52 @@
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
     setMapValues(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
     assertMapValuesSet(destination.build());
   }
 
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+  }
+
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
@@ -357,14 +379,14 @@
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
     updateMapValues(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
@@ -372,12 +394,61 @@
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
-  
+
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  public void testParseError() throws Exception {
+    ByteString bytes = TestUtil.toBytes("SOME BYTES");
+    String stringKey = "a string key";
+
+    TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToInt32Field(5, bytes)
+        .build());
+    assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     setMapValues(builder);
     TestMap message = builder.build();
-    
+
     TestMap.Builder other = TestMap.newBuilder();
     other.mergeFrom(message);
     assertMapValuesSet(other.build());
@@ -386,26 +457,26 @@
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
-    
+
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
-    TestMap.Builder b1 = TestMap.newBuilder();
-    b1.getMutableInt32ToInt32Field().put(1, 2);
-    b1.getMutableInt32ToInt32Field().put(3, 4);
-    b1.getMutableInt32ToInt32Field().put(5, 6);
+    TestMap.Builder b1 = TestMap.newBuilder()
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4)
+        .putInt32ToInt32Field(5, 6);
     TestMap m1 = b1.build();
-    
-    TestMap.Builder b2 = TestMap.newBuilder();
-    b2.getMutableInt32ToInt32Field().put(5, 6);
-    b2.getMutableInt32ToInt32Field().put(1, 2);
-    b2.getMutableInt32ToInt32Field().put(3, 4);
+
+    TestMap.Builder b2 = TestMap.newBuilder()
+        .putInt32ToInt32Field(5, 6)
+        .putInt32ToInt32Field(1, 2)
+        .putInt32ToInt32Field(3, 4);
     TestMap m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
-    b2.getMutableInt32ToInt32Field().put(1, 0);
+    b2.putInt32ToInt32Field(1, 0);
     m2 = b2.build();
     assertFalse(m1.equals(m2));
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
@@ -413,10 +484,9 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestUnknownEnumValue.Builder builder =
-        TestUnknownEnumValue.newBuilder();
-    builder.getMutableInt32ToInt32Field().put(1, 1);
-    builder.getMutableInt32ToInt32Field().put(2, 54321);
+    TestUnknownEnumValue.Builder builder = TestUnknownEnumValue.newBuilder()
+        .putInt32ToInt32Field(1, 1)
+        .putInt32ToInt32Field(2, 54321);
     ByteString data = builder.build().toByteString();
 
     TestMap message = TestMap.parseFrom(data);
@@ -442,17 +512,288 @@
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
+
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValues(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValues(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValues(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValues(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
 }
diff --git a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
index 73154c0..e8246bf 100644
--- a/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
+++ b/java/core/src/test/java/com/google/protobuf/MapForProto2Test.java
@@ -31,13 +31,17 @@
 package com.google.protobuf;
 
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapForProto2TestProto.BizarroTestMap;
 import map_test.MapForProto2TestProto.TestMap;
 import map_test.MapForProto2TestProto.TestMap.MessageValue;
 import map_test.MapForProto2TestProto.TestMap.MessageWithRequiredFields;
+import map_test.MapForProto2TestProto.TestMapOrBuilder;
 import map_test.MapForProto2TestProto.TestRecursiveMap;
 import map_test.MapForProto2TestProto.TestUnknownEnumValue;
 import junit.framework.TestCase;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -48,7 +52,8 @@
  * Unit tests for map fields in proto2 protos.
  */
 public class MapForProto2Test extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
+
+  private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
@@ -56,27 +61,67 @@
     builder.getMutableInt32ToStringField().put(1, "11");
     builder.getMutableInt32ToStringField().put(2, "22");
     builder.getMutableInt32ToStringField().put(3, "33");
-    
+
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("11"));
     builder.getMutableInt32ToBytesField().put(2, TestUtil.toBytes("22"));
     builder.getMutableInt32ToBytesField().put(3, TestUtil.toBytes("33"));
-    
+
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.FOO);
     builder.getMutableInt32ToEnumField().put(2, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().put(3, TestMap.EnumValue.BAZ);
-    
+
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(11).build());
     builder.getMutableInt32ToMessageField().put(
         2, MessageValue.newBuilder().setValue(22).build());
     builder.getMutableInt32ToMessageField().put(
         3, MessageValue.newBuilder().setValue(33).build());
-    
+
     builder.getMutableStringToInt32Field().put("1", 11);
     builder.getMutableStringToInt32Field().put("2", 22);
     builder.getMutableStringToInt32Field().put("3", 33);
   }
 
+  private void setMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
         .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
@@ -87,7 +132,7 @@
         .putAllStringToInt32Field(source.getStringToInt32Field());
   }
 
-  private void assertMapValuesSet(TestMap message) {
+  private void assertMapValuesSet(TestMapOrBuilder message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(11, message.getInt32ToInt32Field().get(1).intValue());
     assertEquals(22, message.getInt32ToInt32Field().get(2).intValue());
@@ -97,29 +142,29 @@
     assertEquals("11", message.getInt32ToStringField().get(1));
     assertEquals("22", message.getInt32ToStringField().get(2));
     assertEquals("33", message.getInt32ToStringField().get(3));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("11"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("22"), message.getInt32ToBytesField().get(2));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.FOO, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(2));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(11, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(22, message.getInt32ToMessageField().get(2).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(11, message.getStringToInt32Field().get("1").intValue());
     assertEquals(22, message.getStringToInt32Field().get("2").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
   }
 
-  private void updateMapValues(TestMap.Builder builder) {
+  private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
@@ -127,26 +172,78 @@
     builder.getMutableInt32ToStringField().put(1, "111");
     builder.getMutableInt32ToStringField().remove(2);
     builder.getMutableInt32ToStringField().put(4, "44");
-    
+
     builder.getMutableInt32ToBytesField().put(1, TestUtil.toBytes("111"));
     builder.getMutableInt32ToBytesField().remove(2);
     builder.getMutableInt32ToBytesField().put(4, TestUtil.toBytes("44"));
-    
+
     builder.getMutableInt32ToEnumField().put(1, TestMap.EnumValue.BAR);
     builder.getMutableInt32ToEnumField().remove(2);
     builder.getMutableInt32ToEnumField().put(4, TestMap.EnumValue.QUX);
-    
+
     builder.getMutableInt32ToMessageField().put(
         1, MessageValue.newBuilder().setValue(111).build());
     builder.getMutableInt32ToMessageField().remove(2);
     builder.getMutableInt32ToMessageField().put(
         4, MessageValue.newBuilder().setValue(44).build());
-    
+
     builder.getMutableStringToInt32Field().put("1", 111);
     builder.getMutableStringToInt32Field().remove("2");
     builder.getMutableStringToInt32Field().put("4", 44);
   }
 
+  private void updateMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
+
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+    assertEquals(usingAccessors, usingMutableMap);
+
+    usingMutableMapBuilder = usingMutableMap.toBuilder();
+    updateMapValuesUsingMutableMap(usingMutableMapBuilder);
+    usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesUpdated(usingMutableMap);
+
+    usingAccessorsBuilder = usingAccessors.toBuilder();
+    updateMapValuesUsingAccessors(usingAccessorsBuilder);
+    usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesUpdated(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void assertMapValuesUpdated(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
@@ -157,37 +254,72 @@
     assertEquals("111", message.getInt32ToStringField().get(1));
     assertEquals("33", message.getInt32ToStringField().get(3));
     assertEquals("44", message.getInt32ToStringField().get(4));
-    
+
     assertEquals(3, message.getInt32ToBytesField().size());
     assertEquals(TestUtil.toBytes("111"), message.getInt32ToBytesField().get(1));
     assertEquals(TestUtil.toBytes("33"), message.getInt32ToBytesField().get(3));
     assertEquals(TestUtil.toBytes("44"), message.getInt32ToBytesField().get(4));
-    
+
     assertEquals(3, message.getInt32ToEnumField().size());
     assertEquals(TestMap.EnumValue.BAR, message.getInt32ToEnumField().get(1));
     assertEquals(TestMap.EnumValue.BAZ, message.getInt32ToEnumField().get(3));
     assertEquals(TestMap.EnumValue.QUX, message.getInt32ToEnumField().get(4));
-    
+
     assertEquals(3, message.getInt32ToMessageField().size());
     assertEquals(111, message.getInt32ToMessageField().get(1).getValue());
     assertEquals(33, message.getInt32ToMessageField().get(3).getValue());
     assertEquals(44, message.getInt32ToMessageField().get(4).getValue());
-    
+
     assertEquals(3, message.getStringToInt32Field().size());
     assertEquals(111, message.getStringToInt32Field().get("1").intValue());
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
-  
+
+  public void testGetMapIsImmutable() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValuesUsingAccessors(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
+    try {
+      map.put(key, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -217,7 +349,7 @@
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
+
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -232,7 +364,7 @@
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-    
+
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -302,48 +434,91 @@
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
-    
+
     builder = message.toBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValues(sourceBuilder);
+    setMapValuesUsingMutableMap(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
     assertMapValuesSet(destination.build());
+
+    assertEquals(3, destination.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
   }
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
-    
+
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesUpdated(message);
-    
+
     builder = message.toBuilder();
     builder.clear();
     message = builder.build();
@@ -351,12 +526,61 @@
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesCleared(message);
   }
-  
+
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  public void testParseError() throws Exception {
+    ByteString bytes = TestUtil.toBytes("SOME BYTES");
+    String stringKey = "a string key";
+
+    TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToInt32Field(5, bytes)
+        .build());
+    assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
-    
+
     TestMap.Builder other = TestMap.newBuilder();
     other.mergeFrom(message);
     assertMapValuesSet(other.build());
@@ -365,7 +589,7 @@
   public void testEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
-    
+
     // We can't control the order of elements in a HashMap. The best we can do
     // here is to add elements in different order.
     TestMap.Builder b1 = TestMap.newBuilder();
@@ -373,16 +597,16 @@
     b1.getMutableInt32ToInt32Field().put(3, 4);
     b1.getMutableInt32ToInt32Field().put(5, 6);
     TestMap m1 = b1.build();
-    
+
     TestMap.Builder b2 = TestMap.newBuilder();
     b2.getMutableInt32ToInt32Field().put(5, 6);
     b2.getMutableInt32ToInt32Field().put(1, 2);
     b2.getMutableInt32ToInt32Field().put(3, 4);
     TestMap m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
     b2.getMutableInt32ToInt32Field().put(1, 0);
     m2 = b2.build();
@@ -390,26 +614,26 @@
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
-  
-  
+
+
   // The following methods are used to test reflection API.
-  
+
   private static FieldDescriptor f(String name) {
     return TestMap.getDescriptor().findFieldByName(name);
   }
-  
+
   private static Object getFieldValue(Message mapEntry, String name) {
     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
     return mapEntry.getField(field);
   }
-  
+
   private static Message.Builder setFieldValue(
       Message.Builder mapEntry, String name, Object value) {
     FieldDescriptor field = mapEntry.getDescriptorForType().findFieldByName(name);
     mapEntry.setField(field, value);
     return mapEntry;
   }
-  
+
   private static void assertHasMapValues(Message message, String name, Map<?, ?> values) {
     FieldDescriptor field = f(name);
     for (Object entry : (List<?>) message.getField(field)) {
@@ -428,7 +652,7 @@
       assertEquals(value, values.get(key));
     }
   }
-  
+
   private static <KeyType, ValueType>
   Message newMapEntry(Message.Builder builder, String name, KeyType key, ValueType value) {
     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
@@ -439,7 +663,7 @@
     entryBuilder.setField(valueField, value);
     return entryBuilder.build();
   }
-  
+
   private static void setMapValues(Message.Builder builder, String name, Map<?, ?> values) {
     List<Message> entryList = new ArrayList<Message>();
     for (Map.Entry<?, ?> entry : values.entrySet()) {
@@ -448,9 +672,8 @@
     FieldDescriptor field = builder.getDescriptorForType().findFieldByName(name);
     builder.setField(field, entryList);
   }
-  
-  private static <KeyType, ValueType>
-  Map<KeyType, ValueType> mapForValues(
+
+  private static <KeyType, ValueType> Map<KeyType, ValueType> mapForValues(
       KeyType key1, ValueType value1, KeyType key2, ValueType value2) {
     Map<KeyType, ValueType> map = new HashMap<KeyType, ValueType>();
     map.put(key1, value1);
@@ -476,14 +699,14 @@
         mapForValues(
             11, MessageValue.newBuilder().setValue(22).build(),
             33, MessageValue.newBuilder().setValue(44).build()));
-    
+
     // Test clearField()
     builder.clearField(f("int32_to_int32_field"));
     builder.clearField(f("int32_to_message_field"));
     message = builder.build();
     assertEquals(0, message.getInt32ToInt32Field().size());
     assertEquals(0, message.getInt32ToMessageField().size());
-    
+
     // Test setField()
     setMapValues(builder, "int32_to_int32_field",
         mapForValues(11, 22, 33, 44));
@@ -496,7 +719,7 @@
     assertEquals(44, message.getInt32ToInt32Field().get(33).intValue());
     assertEquals(222, message.getInt32ToMessageField().get(111).getValue());
     assertEquals(444, message.getInt32ToMessageField().get(333).getValue());
-    
+
     // Test addRepeatedField
     builder.addRepeatedField(f("int32_to_int32_field"),
         newMapEntry(builder, "int32_to_int32_field", 55, 66));
@@ -516,7 +739,7 @@
     message = builder.build();
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
     assertEquals(555, message.getInt32ToMessageField().get(555).getValue());
-    
+
     // Test setRepeatedField
     for (int i = 0; i < builder.getRepeatedFieldCount(f("int32_to_int32_field")); i++) {
       Message mapEntry = (Message) builder.getRepeatedField(f("int32_to_int32_field"), i);
@@ -533,35 +756,35 @@
     assertEquals(33, message.getInt32ToInt32Field().get(44).intValue());
     assertEquals(55, message.getInt32ToInt32Field().get(55).intValue());
   }
-  
+
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
-    
+
     String textData = TextFormat.printToString(message);
-    
+
     builder = TestMap.newBuilder();
     TextFormat.merge(textData, builder);
     message = builder.build();
-    
+
     assertMapValuesSet(message);
   }
-  
+
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
-    
+
     Message dynamicDefaultInstance =
         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     Message dynamicMessage = dynamicDefaultInstance
         .newBuilderForType().mergeFrom(message.toByteString()).build();
-    
+
     assertEquals(message, dynamicMessage);
     assertEquals(message.hashCode(), dynamicMessage.hashCode());
   }
-  
+
   public void testReflectionEqualsAndHashCode() throws Exception {
     // Test that generated equals() and hashCode() will disregard the order
     // of map entries when comparing/hashing map fields.
@@ -570,22 +793,22 @@
     Message dynamicDefaultInstance =
         DynamicMessage.getDefaultInstance(TestMap.getDescriptor());
     FieldDescriptor field = f("int32_to_int32_field");
-    
+
     Message.Builder b1 = dynamicDefaultInstance.newBuilderForType();
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 1, 2));
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 3, 4));
     b1.addRepeatedField(field, newMapEntry(b1, "int32_to_int32_field", 5, 6));
     Message m1 = b1.build();
-    
+
     Message.Builder b2 = dynamicDefaultInstance.newBuilderForType();
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 5, 6));
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 1, 2));
     b2.addRepeatedField(field, newMapEntry(b2, "int32_to_int32_field", 3, 4));
     Message m2 = b2.build();
-    
+
     assertEquals(m1, m2);
     assertEquals(m1.hashCode(), m2.hashCode());
-    
+
     // Make sure we did compare map fields.
     b2.setRepeatedField(field, 0, newMapEntry(b1, "int32_to_int32_field", 0, 0));
     m2 = b2.build();
@@ -593,7 +816,7 @@
     // Don't check m1.hashCode() != m2.hashCode() because it's not guaranteed
     // to be different.
   }
-  
+
   public void testUnknownEnumValues() throws Exception {
     TestUnknownEnumValue.Builder builder =
         TestUnknownEnumValue.newBuilder();
@@ -646,13 +869,266 @@
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
 
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValuesUsingMutableMap(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
   // Regression test for b/20494788
   public void testMapInitializationOrder() throws Exception {
     assertEquals("RedactAllTypes", map_test.RedactAllTypes
@@ -666,18 +1142,36 @@
         message.getDescriptorForType().findFieldByName("map_field"), 0);
     assertEquals(2, mapEntry.getAllFields().size());
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     map.put(key2, value2);
     return map;
   }
-}
 
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(builder);
+    assertMapValuesSet(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/MapTest.java b/java/core/src/test/java/com/google/protobuf/MapTest.java
index 1dc5787..caef246 100644
--- a/java/core/src/test/java/com/google/protobuf/MapTest.java
+++ b/java/core/src/test/java/com/google/protobuf/MapTest.java
@@ -30,15 +30,20 @@
 
 package com.google.protobuf;
 
+
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.EnumDescriptor;
 import com.google.protobuf.Descriptors.EnumValueDescriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
+import map_test.MapTestProto.BizarroTestMap;
 import map_test.MapTestProto.TestMap;
 import map_test.MapTestProto.TestMap.MessageValue;
+import map_test.MapTestProto.TestMapOrBuilder;
 import map_test.MapTestProto.TestOnChangeEventPropagation;
 import junit.framework.TestCase;
 
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -49,7 +54,8 @@
  * Unit tests for map fields.
  */
 public class MapTest extends TestCase {
-  private void setMapValues(TestMap.Builder builder) {
+
+  private void setMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 11);
     builder.getMutableInt32ToInt32Field().put(2, 22);
     builder.getMutableInt32ToInt32Field().put(3, 33);
@@ -78,6 +84,46 @@
     builder.getMutableStringToInt32Field().put("3", 33);
   }
 
+  private void setMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 11)
+        .putInt32ToInt32Field(2, 22)
+        .putInt32ToInt32Field(3, 33)
+
+        .putInt32ToStringField(1, "11")
+        .putInt32ToStringField(2, "22")
+        .putInt32ToStringField(3, "33")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("11"))
+        .putInt32ToBytesField(2, TestUtil.toBytes("22"))
+        .putInt32ToBytesField(3, TestUtil.toBytes("33"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.FOO)
+        .putInt32ToEnumField(2, TestMap.EnumValue.BAR)
+        .putInt32ToEnumField(3, TestMap.EnumValue.BAZ)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(11).build())
+        .putInt32ToMessageField(2, MessageValue.newBuilder().setValue(22).build())
+        .putInt32ToMessageField(3, MessageValue.newBuilder().setValue(33).build())
+
+        .putStringToInt32Field("1", 11)
+        .putStringToInt32Field("2", 22)
+        .putStringToInt32Field("3", 33);
+  }
+
+  public void testSetMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void copyMapValues(TestMap source, TestMap.Builder destination) {
     destination
         .putAllInt32ToInt32Field(source.getInt32ToInt32Field())
@@ -120,7 +166,7 @@
     assertEquals(33, message.getStringToInt32Field().get("3").intValue());
   }
 
-  private void updateMapValues(TestMap.Builder builder) {
+  private void updateMapValuesUsingMutableMap(TestMap.Builder builder) {
     builder.getMutableInt32ToInt32Field().put(1, 111);
     builder.getMutableInt32ToInt32Field().remove(2);
     builder.getMutableInt32ToInt32Field().put(4, 44);
@@ -148,6 +194,58 @@
     builder.getMutableStringToInt32Field().put("4", 44);
   }
 
+  private void updateMapValuesUsingAccessors(TestMap.Builder builder) {
+    builder
+        .putInt32ToInt32Field(1, 111)
+        .removeInt32ToInt32Field(2)
+        .putInt32ToInt32Field(4, 44)
+
+        .putInt32ToStringField(1, "111")
+        .removeInt32ToStringField(2)
+        .putInt32ToStringField(4, "44")
+
+        .putInt32ToBytesField(1, TestUtil.toBytes("111"))
+        .removeInt32ToBytesField(2)
+        .putInt32ToBytesField(4, TestUtil.toBytes("44"))
+
+        .putInt32ToEnumField(1, TestMap.EnumValue.BAR)
+        .removeInt32ToEnumField(2)
+        .putInt32ToEnumField(4, TestMap.EnumValue.QUX)
+
+        .putInt32ToMessageField(1, MessageValue.newBuilder().setValue(111).build())
+        .removeInt32ToMessageField(2)
+        .putInt32ToMessageField(4, MessageValue.newBuilder().setValue(44).build())
+
+        .putStringToInt32Field("1", 111)
+        .removeStringToInt32Field("2")
+        .putStringToInt32Field("4", 44);
+  }
+
+  public void testUpdateMapValues() {
+    TestMap.Builder usingMutableMapBuilder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(usingMutableMapBuilder);
+    TestMap usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesSet(usingMutableMap);
+
+    TestMap.Builder usingAccessorsBuilder = TestMap.newBuilder();
+    setMapValuesUsingAccessors(usingAccessorsBuilder);
+    TestMap usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesSet(usingAccessors);
+    assertEquals(usingAccessors, usingMutableMap);
+
+    usingMutableMapBuilder = usingMutableMap.toBuilder();
+    updateMapValuesUsingMutableMap(usingMutableMapBuilder);
+    usingMutableMap = usingMutableMapBuilder.build();
+    assertMapValuesUpdated(usingMutableMap);
+
+    usingAccessorsBuilder = usingAccessors.toBuilder();
+    updateMapValuesUsingAccessors(usingAccessorsBuilder);
+    usingAccessors = usingAccessorsBuilder.build();
+    assertMapValuesUpdated(usingAccessors);
+
+    assertEquals(usingAccessors, usingMutableMap);
+  }
+
   private void assertMapValuesUpdated(TestMap message) {
     assertEquals(3, message.getInt32ToInt32Field().size());
     assertEquals(111, message.getInt32ToInt32Field().get(1).intValue());
@@ -180,15 +278,50 @@
     assertEquals(44, message.getStringToInt32Field().get("4").intValue());
   }
 
-  private void assertMapValuesCleared(TestMap message) {
-    assertEquals(0, message.getInt32ToInt32Field().size());
-    assertEquals(0, message.getInt32ToStringField().size());
-    assertEquals(0, message.getInt32ToBytesField().size());
-    assertEquals(0, message.getInt32ToEnumField().size());
-    assertEquals(0, message.getInt32ToMessageField().size());
-    assertEquals(0, message.getStringToInt32Field().size());
+  private void assertMapValuesCleared(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageField().size());
+    assertEquals(0, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(0, testMapOrBuilder.getStringToInt32Field().size());
+    assertEquals(0, testMapOrBuilder.getStringToInt32FieldCount());
   }
-  
+
+  public void testGetMapIsImmutable() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+
+    setMapValuesUsingAccessors(builder);
+    assertMapsAreImmutable(builder);
+    assertMapsAreImmutable(builder.build());
+  }
+
+  private void assertMapsAreImmutable(TestMapOrBuilder testMapOrBuilder) {
+    assertImmutable(testMapOrBuilder.getInt32ToInt32Field(), 1, 2);
+    assertImmutable(testMapOrBuilder.getInt32ToStringField(), 1, "2");
+    assertImmutable(testMapOrBuilder.getInt32ToBytesField(), 1, TestUtil.toBytes("2"));
+    assertImmutable(testMapOrBuilder.getInt32ToEnumField(), 1, TestMap.EnumValue.FOO);
+    assertImmutable(
+        testMapOrBuilder.getInt32ToMessageField(), 1, MessageValue.getDefaultInstance());
+    assertImmutable(testMapOrBuilder.getStringToInt32Field(), "1", 2);
+  }
+
+  private <K, V> void assertImmutable(Map<K, V> map, K key, V value) {
+    try {
+      map.put(key, value);
+      fail();
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
   public void testMutableMapLifecycle() {
     TestMap.Builder builder = TestMap.newBuilder();
     Map<Integer, Integer> intMap = builder.getMutableInt32ToInt32Field();
@@ -218,7 +351,7 @@
     assertEquals(
         newMap(1, TestMap.EnumValue.BAR, 2, TestMap.EnumValue.FOO),
         builder.getInt32ToEnumField());
-    
+
     Map<Integer, String> stringMap = builder.getMutableInt32ToStringField();
     stringMap.put(1, "1");
     assertEquals(newMap(1, "1"), builder.build().getInt32ToStringField());
@@ -233,7 +366,7 @@
     assertEquals(
         newMap(1, "1", 2, "2"),
         builder.getInt32ToStringField());
-    
+
     Map<Integer, TestMap.MessageValue> messageMap = builder.getMutableInt32ToMessageField();
     messageMap.put(1, TestMap.MessageValue.getDefaultInstance());
     assertEquals(newMap(1, TestMap.MessageValue.getDefaultInstance()),
@@ -298,32 +431,34 @@
     assertEquals(newMap(1, 2), builder.getInt32ToInt32Field());
     assertEquals(newMap(1, 2), builder.build().getInt32ToInt32Field());
   }
-  
+
   public void testGettersAndSetters() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     TestMap message = builder.build();
     assertMapValuesCleared(message);
 
     builder = message.toBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertMapValuesUpdated(message);
 
     builder = message.toBuilder();
     builder.clear();
+    assertMapValuesCleared(builder);
     message = builder.build();
     assertMapValuesCleared(message);
   }
 
   public void testPutAll() throws Exception {
     TestMap.Builder sourceBuilder = TestMap.newBuilder();
-    setMapValues(sourceBuilder);
+    setMapValuesUsingMutableMap(sourceBuilder);
     TestMap source = sourceBuilder.build();
+    assertMapValuesSet(source);
 
     TestMap.Builder destination = TestMap.newBuilder();
     copyMapValues(source, destination);
@@ -344,18 +479,76 @@
     assertEquals(0, destination.getInt32ToEnumFieldValue().get(0).intValue());
     assertEquals(1, destination.getInt32ToEnumFieldValue().get(1).intValue());
     assertEquals(1000, destination.getInt32ToEnumFieldValue().get(2).intValue());
+    assertEquals(3, destination.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutForUnknownEnumValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder()
+        .putInt32ToEnumFieldValue(0, 0)
+        .putInt32ToEnumFieldValue(1, 1);
+
+    try {
+      builder.putInt32ToEnumFieldValue(2, 1000);  // unknown value.
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    TestMap message = builder.build();
+    assertEquals(0, message.getInt32ToEnumFieldValueOrThrow(0));
+    assertEquals(1, message.getInt32ToEnumFieldValueOrThrow(1));
+    assertEquals(2, message.getInt32ToEnumFieldCount());
+  }
+
+  public void testPutChecksNullKeysAndValues() throws Exception {
+    TestMap.Builder builder = TestMap.newBuilder();
+
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putInt32ToMessageField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
+
+    try {
+      builder.putStringToInt32Field(null, 1);
+      fail();
+    } catch (NullPointerException e) {
+      // expected.
+    }
   }
 
   public void testSerializeAndParse() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
     assertMapValuesSet(message);
 
     builder = message.toBuilder();
-    updateMapValues(builder);
+    updateMapValuesUsingMutableMap(builder);
     message = builder.build();
     assertEquals(message.getSerializedSize(), message.toByteString().size());
     message = TestMap.parser().parseFrom(message.toByteString());
@@ -369,9 +562,58 @@
     assertMapValuesCleared(message);
   }
 
+  private TestMap tryParseTestMap(BizarroTestMap bizarroMap) throws IOException {
+    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+    CodedOutputStream output = CodedOutputStream.newInstance(byteArrayOutputStream);
+    bizarroMap.writeTo(output);
+    output.flush();
+    return TestMap.parser().parseFrom(ByteString.copyFrom(byteArrayOutputStream.toByteArray()));
+  }
+
+  public void testParseError() throws Exception {
+    ByteString bytes = TestUtil.toBytes("SOME BYTES");
+    String stringKey = "a string key";
+
+    TestMap map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToInt32Field(5, bytes)
+        .build());
+    assertEquals(map.getInt32ToInt32FieldOrDefault(5, -1), 0);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToStringField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToStringFieldOrDefault(0, null), "");
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToBytesField(stringKey, 5)
+        .build());
+    assertEquals(map.getInt32ToBytesFieldOrDefault(0, null), ByteString.EMPTY);
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putInt32ToEnumField(stringKey, bytes)
+        .build());
+    assertEquals(map.getInt32ToEnumFieldOrDefault(0, null), TestMap.EnumValue.FOO);
+
+    try {
+      tryParseTestMap(BizarroTestMap.newBuilder()
+          .putInt32ToMessageField(stringKey, bytes)
+          .build());
+      fail();
+    } catch (InvalidProtocolBufferException expected) {
+      assertTrue(expected.getUnfinishedMessage() instanceof TestMap);
+      map = (TestMap) expected.getUnfinishedMessage();
+      assertTrue(map.getInt32ToMessageField().isEmpty());
+    }
+
+    map = tryParseTestMap(BizarroTestMap.newBuilder()
+        .putStringToInt32Field(stringKey, bytes)
+        .build());
+    assertEquals(map.getStringToInt32FieldOrDefault(stringKey, -1), 0);
+  }
+
   public void testMergeFrom() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
 
     TestMap.Builder other = TestMap.newBuilder();
@@ -629,7 +871,7 @@
 
   public void testTextFormat() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
 
     String textData = TextFormat.printToString(message);
@@ -643,7 +885,7 @@
 
   public void testDynamicMessage() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
 
     Message dynamicDefaultInstance =
@@ -760,19 +1002,317 @@
 
   public void testIterationOrder() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    setMapValues(builder);
+    setMapValuesUsingMutableMap(builder);
     TestMap message = builder.build();
 
     assertEquals(Arrays.asList("1", "2", "3"),
         new ArrayList<String>(message.getStringToInt32Field().keySet()));
   }
-  
+
+  public void testGetMap() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(builder);
+    TestMap message = builder.build();
+    assertEquals(
+        message.getStringToInt32Field(),
+        message.getStringToInt32FieldMap());
+    assertEquals(
+        message.getInt32ToBytesField(),
+        message.getInt32ToBytesFieldMap());
+    assertEquals(
+        message.getInt32ToEnumField(),
+        message.getInt32ToEnumFieldMap());
+    assertEquals(
+        message.getInt32ToEnumFieldValue(),
+        message.getInt32ToEnumFieldValueMap());
+    assertEquals(
+        message.getInt32ToMessageField(),
+        message.getInt32ToMessageFieldMap());
+  }
+
+  public void testContains() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(builder);
+    assertMapContainsSetValues(builder);
+    assertMapContainsSetValues(builder.build());
+  }
+
+  private void assertMapContainsSetValues(TestMapOrBuilder testMapOrBuilder) {
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(1));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(2));
+    assertTrue(testMapOrBuilder.containsInt32ToInt32Field(3));
+    assertFalse(testMapOrBuilder.containsInt32ToInt32Field(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToStringField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToStringField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToBytesField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToBytesField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToEnumField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToEnumField(-1));
+
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(1));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(2));
+    assertTrue(testMapOrBuilder.containsInt32ToMessageField(3));
+    assertFalse(testMapOrBuilder.containsInt32ToMessageField(-1));
+
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("1"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("2"));
+    assertTrue(testMapOrBuilder.containsStringToInt32Field("3"));
+    assertFalse(testMapOrBuilder.containsStringToInt32Field("-1"));
+  }
+
+  public void testCount() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+
+    setMapValuesUsingMutableMap(builder);
+    assertMapCounts(3, builder);
+
+    TestMap message = builder.build();
+    assertMapCounts(3, message);
+
+    builder = message.toBuilder().putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+    assertEquals(4, builder.build().getInt32ToInt32FieldCount());
+
+    // already present - should be unchanged
+    builder.putInt32ToInt32Field(4, 44);
+    assertEquals(4, builder.getInt32ToInt32FieldCount());
+  }
+
+  private void assertMapCounts(int expectedCount, TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToInt32FieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToStringFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToBytesFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToEnumFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getInt32ToMessageFieldCount());
+    assertEquals(expectedCount, testMapOrBuilder.getStringToInt32FieldCount());
+  }
+
+  public void testGetOrDefault() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrDefault(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(1, -11));
+    assertEquals(-11, testMapOrBuilder.getInt32ToInt32FieldOrDefault(-1, -11));
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrDefault(1, "-11"));
+    assertNull("-11", testMapOrBuilder.getInt32ToStringFieldOrDefault(-1, null));
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToBytesFieldOrDefault(-1, null));
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToEnumFieldOrDefault(-1, null));
+
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(),
+        (int) testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(2, -1));
+    assertEquals(-1, testMapOrBuilder.getInt32ToEnumFieldValueOrDefault(-1000, -1));
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrDefault(1, null));
+    assertNull(testMapOrBuilder.getInt32ToMessageFieldOrDefault(-1, null));
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrDefault("1", -11));
+    assertEquals(-11, testMapOrBuilder.getStringToInt32FieldOrDefault("-1", -11));
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrDefault(null, -11);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testGetOrThrow() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    assertMapCounts(0, builder);
+    setMapValuesUsingAccessors(builder);
+    doTestGetOrDefault(builder);
+    doTestGetOrDefault(builder.build());
+  }
+
+  public void doTestGetOrThrow(TestMapOrBuilder testMapOrBuilder) {
+    assertEquals(11, testMapOrBuilder.getInt32ToInt32FieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToInt32FieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals("11", testMapOrBuilder.getInt32ToStringFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToStringFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestUtil.toBytes("11"), testMapOrBuilder.getInt32ToBytesFieldOrThrow(1));
+
+    try {
+      testMapOrBuilder.getInt32ToBytesFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, testMapOrBuilder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(), testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(2));
+    try {
+      testMapOrBuilder.getInt32ToEnumFieldValueOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(MessageValue.newBuilder().setValue(11).build(),
+        testMapOrBuilder.getInt32ToMessageFieldOrThrow(1));
+    try {
+      testMapOrBuilder.getInt32ToMessageFieldOrThrow(-1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    assertEquals(11, testMapOrBuilder.getStringToInt32FieldOrThrow("1"));
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow("-1");
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    try {
+      testMapOrBuilder.getStringToInt32FieldOrThrow(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testPut() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    builder.putInt32ToInt32Field(1, 11);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+
+    builder.putInt32ToStringField(1, "a");
+    assertEquals("a", builder.getInt32ToStringFieldOrThrow(1));
+    try {
+      builder.putInt32ToStringField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToBytesField(1, TestUtil.toBytes("11"));
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    try {
+      builder.putInt32ToBytesField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumField(1, TestMap.EnumValue.FOO);
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    try {
+      builder.putInt32ToEnumField(1, null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+
+    builder.putInt32ToEnumFieldValue(1, TestMap.EnumValue.BAR.getNumber());
+    assertEquals(
+        TestMap.EnumValue.BAR.getNumber(), builder.getInt32ToEnumFieldValueOrThrow(1));
+    try {
+      builder.putInt32ToEnumFieldValue(1, -1);
+      fail();
+    } catch (IllegalArgumentException e) {
+      // expected
+    }
+
+    builder.putStringToInt32Field("a", 1);
+    assertEquals(1, builder.getStringToInt32FieldOrThrow("a"));
+    try {
+      builder.putStringToInt32Field(null, -1);
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
+  public void testRemove() {
+    TestMap.Builder builder = TestMap.newBuilder();
+    setMapValuesUsingMutableMap(builder);
+    assertEquals(11, builder.getInt32ToInt32FieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToInt32Field(1);
+      assertEquals(-1, builder.getInt32ToInt32FieldOrDefault(1, -1));
+    }
+
+    assertEquals("11", builder.getInt32ToStringFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToStringField(1);
+      assertNull(builder.getInt32ToStringFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestUtil.toBytes("11"), builder.getInt32ToBytesFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToBytesField(1);
+      assertNull(builder.getInt32ToBytesFieldOrDefault(1, null));
+    }
+
+    assertEquals(TestMap.EnumValue.FOO, builder.getInt32ToEnumFieldOrThrow(1));
+    for (int times = 0; times < 2; times++) {
+      builder.removeInt32ToEnumField(1);
+      assertNull(builder.getInt32ToEnumFieldOrDefault(1, null));
+    }
+
+    assertEquals(11, builder.getStringToInt32FieldOrThrow("1"));
+    for (int times = 0; times < 2; times++) {
+      builder.removeStringToInt32Field("1");
+      assertEquals(-1, builder.getStringToInt32FieldOrDefault("1", -1));
+    }
+
+    try {
+      builder.removeStringToInt32Field(null);
+      fail();
+    } catch (NullPointerException e) {
+      // expected
+    }
+  }
+
   private static <K, V> Map<K, V> newMap(K key1, V value1) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
     return map;
   }
-  
+
   private static <K, V> Map<K, V> newMap(K key1, V value1, K key2, V value2) {
     Map<K, V> map = new HashMap<K, V>();
     map.put(key1, value1);
diff --git a/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
new file mode 100644
index 0000000..241a435
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/RepeatedFieldBuilderV3Test.java
@@ -0,0 +1,190 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+
+import junit.framework.TestCase;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests for {@link RepeatedFieldBuilderV3}. This tests basic functionality.
+ * More extensive testing is provided via other tests that exercise the
+ * builder.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class RepeatedFieldBuilderV3Test extends TestCase {
+
+  public void testBasicUse() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+    assertEquals(0, builder.getMessage(0).getOptionalInt32());
+    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+    List<TestAllTypes> list = builder.build();
+    assertEquals(2, list.size());
+    assertEquals(0, list.get(0).getOptionalInt32());
+    assertEquals(1, list.get(1).getOptionalInt32());
+    assertIsUnmodifiable(list);
+
+    // Make sure it doesn't change.
+    List<TestAllTypes> list2 = builder.build();
+    assertSame(list, list2);
+    assertEquals(0, mockParent.getInvalidationCount());
+  }
+
+  public void testGoingBackAndForth() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+    assertEquals(0, builder.getMessage(0).getOptionalInt32());
+    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+    // Convert to list
+    List<TestAllTypes> list = builder.build();
+    assertEquals(2, list.size());
+    assertEquals(0, list.get(0).getOptionalInt32());
+    assertEquals(1, list.get(1).getOptionalInt32());
+    assertIsUnmodifiable(list);
+
+    // Update 0th item
+    assertEquals(0, mockParent.getInvalidationCount());
+    builder.getBuilder(0).setOptionalString("foo");
+    assertEquals(1, mockParent.getInvalidationCount());
+    list = builder.build();
+    assertEquals(2, list.size());
+    assertEquals(0, list.get(0).getOptionalInt32());
+      assertEquals("foo", list.get(0).getOptionalString());
+    assertEquals(1, list.get(1).getOptionalInt32());
+    assertIsUnmodifiable(list);
+    assertEquals(1, mockParent.getInvalidationCount());
+  }
+
+  public void testVariousMethods() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(2).build());
+    builder.addBuilder(0, TestAllTypes.getDefaultInstance())
+        .setOptionalInt32(0);
+    builder.addBuilder(TestAllTypes.getDefaultInstance()).setOptionalInt32(3);
+
+    assertEquals(0, builder.getMessage(0).getOptionalInt32());
+    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+    assertEquals(2, builder.getMessage(2).getOptionalInt32());
+    assertEquals(3, builder.getMessage(3).getOptionalInt32());
+
+    assertEquals(0, mockParent.getInvalidationCount());
+    List<TestAllTypes> messages = builder.build();
+    assertEquals(4, messages.size());
+    assertSame(messages, builder.build()); // expect same list
+
+    // Remove a message.
+    builder.remove(2);
+    assertEquals(1, mockParent.getInvalidationCount());
+    assertEquals(3, builder.getCount());
+    assertEquals(0, builder.getMessage(0).getOptionalInt32());
+    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+    assertEquals(3, builder.getMessage(2).getOptionalInt32());
+
+    // Remove a builder.
+    builder.remove(0);
+    assertEquals(1, mockParent.getInvalidationCount());
+    assertEquals(2, builder.getCount());
+    assertEquals(1, builder.getMessage(0).getOptionalInt32());
+    assertEquals(3, builder.getMessage(1).getOptionalInt32());
+
+    // Test clear.
+    builder.clear();
+    assertEquals(1, mockParent.getInvalidationCount());
+    assertEquals(0, builder.getCount());
+    assertTrue(builder.isEmpty());
+  }
+
+  public void testLists() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder = newRepeatedFieldBuilderV3(mockParent);
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(1).build());
+    builder.addMessage(0,
+        TestAllTypes.newBuilder().setOptionalInt32(0).build());
+    assertEquals(0, builder.getMessage(0).getOptionalInt32());
+    assertEquals(1, builder.getMessage(1).getOptionalInt32());
+
+    // Use list of builders.
+    List<TestAllTypes.Builder> builders = builder.getBuilderList();
+    assertEquals(0, builders.get(0).getOptionalInt32());
+    assertEquals(1, builders.get(1).getOptionalInt32());
+    builders.get(0).setOptionalInt32(10);
+    builders.get(1).setOptionalInt32(11);
+
+    // Use list of protos
+    List<TestAllTypes> protos = builder.getMessageList();
+    assertEquals(10, protos.get(0).getOptionalInt32());
+    assertEquals(11, protos.get(1).getOptionalInt32());
+
+    // Add an item to the builders and verify it's updated in both
+    builder.addMessage(TestAllTypes.newBuilder().setOptionalInt32(12).build());
+    assertEquals(3, builders.size());
+    assertEquals(3, protos.size());
+  }
+
+  private void assertIsUnmodifiable(List<?> list) {
+    if (list == Collections.emptyList()) {
+      // OKAY -- Need to check this b/c EmptyList allows you to call clear.
+    } else {
+      try {
+        list.clear();
+        fail("List wasn't immutable");
+      } catch (UnsupportedOperationException e) {
+        // good
+      }
+    }
+  }
+
+  private RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+      TestAllTypesOrBuilder>
+      newRepeatedFieldBuilderV3(GeneratedMessage.BuilderParent parent) {
+    return new RepeatedFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder>(Collections.<TestAllTypes>emptyList(), false,
+        parent, false);
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
new file mode 100644
index 0000000..e3a8d4f
--- /dev/null
+++ b/java/core/src/test/java/com/google/protobuf/SingleFieldBuilderV3Test.java
@@ -0,0 +1,155 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllTypesOrBuilder;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link SingleFieldBuilderV3}. This tests basic functionality.
+ * More extensive testing is provided via other tests that exercise the
+ * builder.
+ *
+ * @author jonp@google.com (Jon Perlow)
+ */
+public class SingleFieldBuilderV3Test extends TestCase {
+
+  public void testBasicUseAndInvalidations() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder =
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+            TestAllTypesOrBuilder>(
+            TestAllTypes.getDefaultInstance(),
+            mockParent,
+            false);
+    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    assertEquals(TestAllTypes.getDefaultInstance(),
+        builder.getBuilder().buildPartial());
+    assertEquals(0, mockParent.getInvalidationCount());
+
+    builder.getBuilder().setOptionalInt32(10);
+    assertEquals(0, mockParent.getInvalidationCount());
+    TestAllTypes message = builder.build();
+    assertEquals(10, message.getOptionalInt32());
+
+    // Test that we receive invalidations now that build has been called.
+    assertEquals(0, mockParent.getInvalidationCount());
+    builder.getBuilder().setOptionalInt32(20);
+    assertEquals(1, mockParent.getInvalidationCount());
+
+    // Test that we don't keep getting invalidations on every change
+    builder.getBuilder().setOptionalInt32(30);
+    assertEquals(1, mockParent.getInvalidationCount());
+
+  }
+
+  public void testSetMessage() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder =
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+            TestAllTypesOrBuilder>(
+            TestAllTypes.getDefaultInstance(),
+            mockParent,
+            false);
+    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+    assertEquals(0, builder.getMessage().getOptionalInt32());
+
+    // Update message using the builder
+    builder.getBuilder().setOptionalInt32(1);
+    assertEquals(0, mockParent.getInvalidationCount());
+    assertEquals(1, builder.getBuilder().getOptionalInt32());
+    assertEquals(1, builder.getMessage().getOptionalInt32());
+    builder.build();
+    builder.getBuilder().setOptionalInt32(2);
+    assertEquals(2, builder.getBuilder().getOptionalInt32());
+    assertEquals(2, builder.getMessage().getOptionalInt32());
+
+    // Make sure message stays cached
+    assertSame(builder.getMessage(), builder.getMessage());
+  }
+
+  public void testClear() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder =
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+            TestAllTypesOrBuilder>(
+            TestAllTypes.getDefaultInstance(),
+            mockParent,
+            false);
+    builder.setMessage(TestAllTypes.newBuilder().setOptionalInt32(0).build());
+    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    builder.clear();
+    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+
+    builder.getBuilder().setOptionalInt32(1);
+    assertNotSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+    builder.clear();
+    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+  }
+
+  public void testMerge() {
+    TestUtil.MockBuilderParent mockParent = new TestUtil.MockBuilderParent();
+    SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+        TestAllTypesOrBuilder> builder =
+        new SingleFieldBuilderV3<TestAllTypes, TestAllTypes.Builder,
+            TestAllTypesOrBuilder>(
+            TestAllTypes.getDefaultInstance(),
+            mockParent,
+            false);
+
+    // Merge into default field.
+    builder.mergeFrom(TestAllTypes.getDefaultInstance());
+    assertSame(TestAllTypes.getDefaultInstance(), builder.getMessage());
+
+    // Merge into non-default field on existing builder.
+    builder.getBuilder().setOptionalInt32(2);
+    builder.mergeFrom(TestAllTypes.newBuilder()
+        .setOptionalDouble(4.0)
+        .buildPartial());
+    assertEquals(2, builder.getMessage().getOptionalInt32());
+    assertEquals(4.0, builder.getMessage().getOptionalDouble());
+
+    // Merge into non-default field on existing message
+    builder.setMessage(TestAllTypes.newBuilder()
+        .setOptionalInt32(10)
+        .buildPartial());
+    builder.mergeFrom(TestAllTypes.newBuilder()
+        .setOptionalDouble(5.0)
+        .buildPartial());
+    assertEquals(10, builder.getMessage().getOptionalInt32());
+    assertEquals(5.0, builder.getMessage().getOptionalDouble());
+  }
+}
diff --git a/java/core/src/test/java/com/google/protobuf/TestUtil.java b/java/core/src/test/java/com/google/protobuf/TestUtil.java
index 08b2a76..d94f99e 100644
--- a/java/core/src/test/java/com/google/protobuf/TestUtil.java
+++ b/java/core/src/test/java/com/google/protobuf/TestUtil.java
@@ -3764,7 +3764,8 @@
 
   private static File getTestDataDir() {
     // Search each parent directory looking for "src/google/protobuf".
-    File ancestor = new File(".");
+    File ancestor = new File(System.getProperty("protobuf.dir", "."));
+    String initialPath = ancestor.getAbsolutePath();
     try {
       ancestor = ancestor.getCanonicalFile();
     } catch (IOException e) {
@@ -3781,7 +3782,7 @@
     throw new RuntimeException(
       "Could not find golden files.  This test must be run from within the " +
       "protobuf source package so that it can read test data files from the " +
-      "C++ source tree.");
+      "C++ source tree: " + initialPath);
   }
 
   /**
diff --git a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
index 63c17cd..14783b0 100644
--- a/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
+++ b/java/core/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -522,15 +522,16 @@
       "optional_string: \"ueoauaoe\n" +
       "optional_int32: 123");
     assertParseError(
-      "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
+      "1:2: Input contains unknown fields and/or extensions:\n" +
+      "1:2:\tprotobuf_unittest.TestAllTypes.[nosuchext]",
       "[nosuchext]: 123");
     assertParseError(
       "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
         "not extend message type \"protobuf_unittest.TestAllTypes\".",
       "[protobuf_unittest.optional_int32_extension]: 123");
     assertParseError(
-      "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
-        "named \"nosuchfield\".",
+      "1:1: Input contains unknown fields and/or extensions:\n" +
+      "1:1:\tprotobuf_unittest.TestAllTypes.nosuchfield",
       "nosuchfield: 123");
     assertParseError(
       "1:21: Expected \">\".",
diff --git a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
index 8f3ca8c..86cdd28 100644
--- a/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/field_presence_test.proto
@@ -54,6 +54,7 @@
   NestedEnum optional_nested_enum = 4;
   NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
+  NestedMessage optional_lazy_message = 7 [lazy=true];
 
   oneof oneof_field {
     int32 oneof_int32 = 11;
@@ -81,6 +82,7 @@
   TestAllTypes.NestedEnum optional_nested_enum = 4;
   TestAllTypes.NestedMessage optional_nested_message = 5;
   protobuf_unittest.TestRequired optional_proto2_message = 6;
+  TestAllTypes.NestedMessage optional_lazy_message = 7 [lazy=true];
 }
 
 message TestRepeatedFieldsOnly {
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
index d5418f2..de3336a 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_lite_test.proto
@@ -70,6 +70,17 @@
   optional int32 value = 1;
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
+
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
 package map_for_proto2_lite_test;
 option java_package = "map_lite_test";
 option optimize_for = LITE_RUNTIME;
diff --git a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
index a9be516..0c92b0a 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_for_proto2_test.proto
@@ -72,3 +72,14 @@
   optional int32 value = 1;
   map<int32, TestRecursiveMap> recursive_map_field = 2;
 }
+
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
diff --git a/java/core/src/test/proto/com/google/protobuf/map_test.proto b/java/core/src/test/proto/com/google/protobuf/map_test.proto
index 2280ac0..9eb63fc 100644
--- a/java/core/src/test/proto/com/google/protobuf/map_test.proto
+++ b/java/core/src/test/proto/com/google/protobuf/map_test.proto
@@ -55,9 +55,19 @@
   map<string, int32>       string_to_int32_field = 6;
 }
 
-// Used to test that a nested bulider containing map fields will properly
+// Used to test that a nested builder containing map fields will properly
 // propagate the onChange event and mark its parent dirty when a change
 // is made to a map field.
 message TestOnChangeEventPropagation {
   TestMap optional_message = 1;
 }
+
+// a decoy of TestMap for testing parsing errors
+message BizarroTestMap {
+  map<int32, bytes> int32_to_int32_field = 1; // same key type, different value
+  map<string, int32> int32_to_string_field = 2; // different key and value types
+  map<string, int32> int32_to_bytes_field = 3; // different key types, same value
+  map<string, bytes> int32_to_enum_field = 4; // different key and value types
+  map<string, bytes> int32_to_message_field = 5; // different key and value types
+  map<string, bytes> string_to_int32_field = 6;  // same key type, different value
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/Durations.java b/java/util/src/main/java/com/google/protobuf/util/Durations.java
new file mode 100644
index 0000000..5fe6ebc
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Durations.java
@@ -0,0 +1,256 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.util;
+
+import static com.google.protobuf.util.Timestamps.MICROS_PER_SECOND;
+import static com.google.protobuf.util.Timestamps.MILLIS_PER_SECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_MICROSECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_MILLISECOND;
+import static com.google.protobuf.util.Timestamps.NANOS_PER_SECOND;
+
+import com.google.protobuf.Duration;
+
+import java.text.ParseException;
+
+/**
+ * Utilities to help create/manipulate {@code protobuf/duration.proto}.
+ */
+public final class Durations {
+  static final long DURATION_SECONDS_MIN = -315576000000L;
+  static final long DURATION_SECONDS_MAX = 315576000000L;
+
+  // TODO(kak): Do we want to expose Duration constants for MAX/MIN?
+
+  private Durations() {}
+
+  /**
+   * Returns true if the given {@link Duration} is valid. The {@code seconds} value must be in the
+   * range [-315,576,000,000, +315,576,000,000]. The {@code nanos} value must be in the range
+   * [-999,999,999, +999,999,999].
+   *
+   * <p>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
+   * positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
+   * for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+   */
+  public static boolean isValid(Duration duration) {
+    return isValid(duration.getSeconds(), duration.getNanos());
+  }
+
+  /**
+   * Returns true if the given number of seconds and nanos is a valid {@link Duration}. The
+   * {@code seconds} value must be in the range [-315,576,000,000, +315,576,000,000]. The
+   * {@code nanos} value must be in the range [-999,999,999, +999,999,999].
+   *
+   * <p>Note: Durations less than one second are represented with a 0 {@code seconds} field and a
+   * positive or negative {@code nanos} field. For durations of one second or more, a non-zero value
+   * for the {@code nanos} field must be of the same sign as the {@code seconds} field.
+   */
+  public static boolean isValid(long seconds, long nanos) {
+    if (seconds < DURATION_SECONDS_MIN || seconds > DURATION_SECONDS_MAX) {
+      return false;
+    }
+    if (nanos < -999999999L || nanos >= NANOS_PER_SECOND) {
+      return false;
+    }
+    if (seconds < 0 || nanos < 0) {
+      if (seconds > 0 || nanos > 0) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Throws an {@link IllegalArgumentException} if the given seconds/nanos are not
+   * a valid {@link Duration}.
+   */
+  private static void checkValid(long seconds, int nanos) {
+    if (!isValid(seconds, nanos)) {
+      throw new IllegalArgumentException(String.format(
+          "Duration is not valid. See proto definition for valid values. "
+          + "Seconds (%s) must be in range [-315,576,000,000, +315,576,000,000]."
+          + "Nanos (%s) must be in range [-999,999,999, +999,999,999]. "
+          + "Nanos must have the same sign as seconds", seconds, nanos));
+    }
+  }
+
+  /**
+   * Convert Duration to string format. The string format will contains 3, 6,
+   * or 9 fractional digits depending on the precision required to represent
+   * the exact Duration value. For example: "1s", "1.010s", "1.000000100s",
+   * "-3.100s" The range that can be represented by Duration is from
+   * -315,576,000,000 to +315,576,000,000 inclusive (in seconds).
+   *
+   * @return The string representation of the given duration.
+   * @throws IllegalArgumentException if the given duration is not in the valid
+   *         range.
+   */
+  public static String toString(Duration duration) {
+    long seconds = duration.getSeconds();
+    int nanos = duration.getNanos();
+    checkValid(seconds, nanos);
+
+    StringBuilder result = new StringBuilder();
+    if (seconds < 0 || nanos < 0) {
+      result.append("-");
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    result.append(seconds);
+    if (nanos != 0) {
+      result.append(".");
+      result.append(Timestamps.formatNanos(nanos));
+    }
+    result.append("s");
+    return result.toString();
+  }
+
+  /**
+   * Parse from a string to produce a duration.
+   *
+   * @return A Duration parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+  public static Duration parse(String value) throws ParseException {
+    // Must ended with "s".
+    if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    boolean negative = false;
+    if (value.charAt(0) == '-') {
+      negative = true;
+      value = value.substring(1);
+    }
+    String secondValue = value.substring(0, value.length() - 1);
+    String nanoValue = "";
+    int pointPosition = secondValue.indexOf('.');
+    if (pointPosition != -1) {
+      nanoValue = secondValue.substring(pointPosition + 1);
+      secondValue = secondValue.substring(0, pointPosition);
+    }
+    long seconds = Long.parseLong(secondValue);
+    int nanos = nanoValue.isEmpty() ? 0 : Timestamps.parseNanos(nanoValue);
+    if (seconds < 0) {
+      throw new ParseException("Invalid duration string: " + value, 0);
+    }
+    if (negative) {
+      seconds = -seconds;
+      nanos = -nanos;
+    }
+    try {
+      return normalizedDuration(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException("Duration value is out of range.", 0);
+    }
+  }
+
+  /**
+   * Create a Duration from the number of milliseconds.
+   */
+  public static Duration fromMillis(long milliseconds) {
+    return normalizedDuration(
+        milliseconds / MILLIS_PER_SECOND,
+        (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Convert a Duration to the number of milliseconds.The result will be
+   * rounded towards 0 to the nearest millisecond. E.g., if the duration
+   * represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMillis(Duration duration) {
+    return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos() / NANOS_PER_MILLISECOND;
+  }
+
+  /**
+   * Create a Duration from the number of microseconds.
+   */
+  public static Duration fromMicros(long microseconds) {
+    return normalizedDuration(
+        microseconds / MICROS_PER_SECOND,
+        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Convert a Duration to the number of microseconds.The result will be
+   * rounded towards 0 to the nearest microseconds. E.g., if the duration
+   * represents -1 nanosecond, it will be rounded to 0.
+   */
+  public static long toMicros(Duration duration) {
+    return duration.getSeconds() * MICROS_PER_SECOND + duration.getNanos() / NANOS_PER_MICROSECOND;
+  }
+
+  /**
+   * Create a Duration from the number of nanoseconds.
+   */
+  public static Duration fromNanos(long nanoseconds) {
+    return normalizedDuration(
+        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /**
+   * Convert a Duration to the number of nanoseconds.
+   */
+  public static long toNanos(Duration duration) {
+    return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
+  }
+
+  /**
+   * Add two durations.
+   */
+  public static Duration add(Duration d1, Duration d2) {
+    return normalizedDuration(d1.getSeconds() + d2.getSeconds(), d1.getNanos() + d2.getNanos());
+  }
+
+  /**
+   * Subtract a duration from another.
+   */
+  public static Duration subtract(Duration d1, Duration d2) {
+    return normalizedDuration(d1.getSeconds() - d2.getSeconds(), d1.getNanos() - d2.getNanos());
+  }
+
+  static Duration normalizedDuration(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds += nanos / NANOS_PER_SECOND;
+      nanos %= NANOS_PER_SECOND;
+    }
+    if (seconds > 0 && nanos < 0) {
+      nanos += NANOS_PER_SECOND;
+      seconds -= 1;
+    }
+    if (seconds < 0 && nanos > 0) {
+      nanos -= NANOS_PER_SECOND;
+      seconds += 1;
+    }
+    checkValid(seconds, nanos);
+    return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+  }
+}
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
index 668d65a..b577495 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java
@@ -38,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.SortedMap;
 import java.util.TreeMap;
 import java.util.logging.Logger;
 
@@ -59,22 +60,26 @@
  * intersection to two FieldMasks and traverse all fields specified by the
  * FieldMask in a message tree.
  */
-class FieldMaskTree {
+final class FieldMaskTree {
   private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getName());
 
   private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
 
-  private static class Node {
-    public TreeMap<String, Node> children = new TreeMap<String, Node>();
+  private static final class Node {
+    final SortedMap<String, Node> children = new TreeMap<String, Node>();
   }
 
   private final Node root = new Node();
 
-  /** Creates an empty FieldMaskTree. */
-  public FieldMaskTree() {}
+  /**
+   * Creates an empty FieldMaskTree.
+   */
+  FieldMaskTree() {}
 
-  /** Creates a FieldMaskTree for a given FieldMask. */
-  public FieldMaskTree(FieldMask mask) {
+  /**
+   * Creates a FieldMaskTree for a given FieldMask.
+   */
+  FieldMaskTree(FieldMask mask) {
     mergeFromFieldMask(mask);
   }
 
@@ -93,7 +98,7 @@
    * Likewise, if the field path to add is a sub-path of an existing leaf node,
    * nothing will be changed in the tree.
    */
-  public FieldMaskTree addFieldPath(String path) {
+  FieldMaskTree addFieldPath(String path) {
     String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
     if (parts.length == 0) {
       return this;
@@ -124,15 +129,17 @@
   /**
    * Merges all field paths in a FieldMask into this tree.
    */
-  public FieldMaskTree mergeFromFieldMask(FieldMask mask) {
+  FieldMaskTree mergeFromFieldMask(FieldMask mask) {
     for (String path : mask.getPathsList()) {
       addFieldPath(path);
     }
     return this;
   }
 
-  /** Converts this tree to a FieldMask. */
-  public FieldMask toFieldMask() {
+  /**
+   * Converts this tree to a FieldMask.
+   */
+  FieldMask toFieldMask() {
     if (root.children.isEmpty()) {
       return FieldMask.getDefaultInstance();
     }
@@ -141,7 +148,9 @@
     return FieldMask.newBuilder().addAllPaths(paths).build();
   }
 
-  /** Gathers all field paths in a sub-tree. */
+  /**
+   * Gathers all field paths in a sub-tree.
+   */
   private void getFieldPaths(Node node, String path, List<String> paths) {
     if (node.children.isEmpty()) {
       paths.add(path);
@@ -154,10 +163,9 @@
   }
 
   /**
-   * Adds the intersection of this tree with the given {@code path} to
-   * {@code output}.
+   * Adds the intersection of this tree with the given {@code path} to {@code output}.
    */
-  public void intersectFieldPath(String path, FieldMaskTree output) {
+  void intersectFieldPath(String path, FieldMaskTree output) {
     if (root.children.isEmpty()) {
       return;
     }
@@ -188,11 +196,9 @@
   }
 
   /**
-   * Merges all fields specified by this FieldMaskTree from {@code source} to
-   * {@code destination}.
+   * Merges all fields specified by this FieldMaskTree from {@code source} to {@code destination}.
    */
-  public void merge(
-      Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
+  void merge(Message source, Message.Builder destination, FieldMaskUtil.MergeOptions options) {
     if (source.getDescriptorForType() != destination.getDescriptorForType()) {
       throw new IllegalArgumentException("Cannot merge messages of different types.");
     }
@@ -202,8 +208,8 @@
     merge(root, "", source, destination, options);
   }
 
-  /** Merges all fields specified by a sub-tree from {@code source} to
-   * {@code destination}.
+  /**
+   * Merges all fields specified by a sub-tree from {@code source} to {@code destination}.
    */
   private void merge(
       Node node,
diff --git a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
index 9696152..21d11b2 100644
--- a/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/FieldMaskUtil.java
@@ -32,6 +32,9 @@
 
 import static com.google.common.base.Preconditions.checkArgument;
 
+import com.google.common.base.CaseFormat;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
 import com.google.common.primitives.Ints;
 import com.google.protobuf.Descriptors.Descriptor;
 import com.google.protobuf.Descriptors.FieldDescriptor;
@@ -39,7 +42,9 @@
 import com.google.protobuf.Internal;
 import com.google.protobuf.Message;
 
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Utility helper functions to work with {@link com.google.protobuf.FieldMask}.
@@ -48,7 +53,7 @@
   private static final String FIELD_PATH_SEPARATOR = ",";
   private static final String FIELD_PATH_SEPARATOR_REGEX = ",";
   private static final String FIELD_SEPARATOR_REGEX = "\\.";
-  
+
   private FieldMaskUtil() {}
 
   /**
@@ -78,19 +83,17 @@
    */
   public static FieldMask fromString(String value) {
     // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
-    return fromStringList(
-        null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+    return fromStringList(null, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
 
   /**
    * Parses from a string to a FieldMask and validates all field paths.
-   * 
+   *
    * @throws IllegalArgumentException if any of the field path is invalid.
    */
   public static FieldMask fromString(Class<? extends Message> type, String value) {
     // TODO(xiaofeng): Consider using com.google.common.base.Splitter here instead.
-    return fromStringList(
-        type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
+    return fromStringList(type, Arrays.asList(value.split(FIELD_PATH_SEPARATOR_REGEX)));
   }
 
   /**
@@ -99,8 +102,7 @@
    * @throws IllegalArgumentException if any of the field path is not valid.
    */
   // TODO(xiaofeng): Consider renaming fromStrings()
-  public static FieldMask fromStringList(
-      Class<? extends Message> type, Iterable<String> paths) {
+  public static FieldMask fromStringList(Class<? extends Message> type, Iterable<String> paths) {
     FieldMask.Builder builder = FieldMask.newBuilder();
     for (String path : paths) {
       if (path.isEmpty()) {
@@ -108,8 +110,7 @@
         continue;
       }
       if (type != null && !isValid(type, path)) {
-        throw new IllegalArgumentException(
-            path + " is not a valid path for " + type);
+        throw new IllegalArgumentException(path + " is not a valid path for " + type);
       }
       builder.addPaths(path);
     }
@@ -146,15 +147,45 @@
   }
 
   /**
+   * Converts a field mask to a Proto3 JSON string, that is converting from snake case to camel
+   * case and joining all paths into one string with commas.
+   */
+  public static String toJsonString(FieldMask fieldMask) {
+    List<String> paths = new ArrayList<String>(fieldMask.getPathsCount());
+    for (String path : fieldMask.getPathsList()) {
+      if (path.isEmpty()) {
+        continue;
+      }
+      paths.add(CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, path));
+    }
+    return Joiner.on(FIELD_PATH_SEPARATOR).join(paths);
+  }
+
+  /**
+   * Converts a field mask from a Proto3 JSON string, that is splitting the paths along commas and
+   * converting from camel case to snake case.
+   */
+  public static FieldMask fromJsonString(String value) {
+    Iterable<String> paths = Splitter.on(FIELD_PATH_SEPARATOR).split(value);
+    FieldMask.Builder builder = FieldMask.newBuilder();
+    for (String path : paths) {
+      if (path.isEmpty()) {
+        continue;
+      }
+      builder.addPaths(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, path));
+    }
+    return builder.build();
+  }
+
+  /**
    * Checks whether paths in a given fields mask are valid.
    */
   public static boolean isValid(Class<? extends Message> type, FieldMask fieldMask) {
-    Descriptor descriptor =
-        Internal.getDefaultInstance(type).getDescriptorForType();
-    
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
     return isValid(descriptor, fieldMask);
   }
-  
+
   /**
    * Checks whether paths in a given fields mask are valid.
    */
@@ -171,9 +202,8 @@
    * Checks whether a given field path is valid.
    */
   public static boolean isValid(Class<? extends Message> type, String path) {
-    Descriptor descriptor =
-        Internal.getDefaultInstance(type).getDescriptorForType();
-    
+    Descriptor descriptor = Internal.getDefaultInstance(type).getDescriptorForType();
+
     return isValid(descriptor, path);
   }
 
@@ -193,8 +223,7 @@
       if (field == null) {
         return false;
       }
-      if (!field.isRepeated()
-          && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+      if (!field.isRepeated() && field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
         descriptor = field.getMessageType();
       } else {
         descriptor = null;
@@ -202,7 +231,7 @@
     }
     return true;
   }
-  
+
   /**
    * Converts a FieldMask to its canonical form. In the canonical form of a
    * FieldMask, all field paths are sorted alphabetically and redundant field
@@ -251,7 +280,7 @@
      * destination message fields) when merging.
      * Default behavior is to merge the source message field into the
      * destination message field.
-     */ 
+     */
     public boolean replaceMessageFields() {
       return replaceMessageFields;
     }
@@ -299,16 +328,15 @@
    * Merges fields specified by a FieldMask from one message to another with the
    * specified merge options.
    */
-  public static void merge(FieldMask mask, Message source,
-      Message.Builder destination, MergeOptions options) {
+  public static void merge(
+      FieldMask mask, Message source, Message.Builder destination, MergeOptions options) {
     new FieldMaskTree(mask).merge(source, destination, options);
   }
 
   /**
    * Merges fields specified by a FieldMask from one message to another.
    */
-  public static void merge(FieldMask mask, Message source,
-      Message.Builder destination) {
+  public static void merge(FieldMask mask, Message source, Message.Builder destination) {
     merge(mask, source, destination, new MergeOptions());
   }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
index 76f3437..bf70834 100644
--- a/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
+++ b/java/util/src/main/java/com/google/protobuf/util/JsonFormat.java
@@ -60,6 +60,7 @@
 import com.google.protobuf.ListValue;
 import com.google.protobuf.Message;
 import com.google.protobuf.MessageOrBuilder;
+import com.google.protobuf.NullValue;
 import com.google.protobuf.StringValue;
 import com.google.protobuf.Struct;
 import com.google.protobuf.Timestamp;
@@ -92,18 +93,17 @@
  * as well.
  */
 public class JsonFormat {
-  private static final Logger logger =
-      Logger.getLogger(JsonFormat.class.getName());
+  private static final Logger logger = Logger.getLogger(JsonFormat.class.getName());
 
   private JsonFormat() {}
-  
+
   /**
    * Creates a {@link Printer} with default configurations.
    */
   public static Printer printer() {
     return new Printer(TypeRegistry.getEmptyTypeRegistry(), false, false);
   }
-  
+
   /**
    * A Printer converts protobuf message to JSON format.
    */
@@ -120,11 +120,11 @@
       this.includingDefaultValueFields = includingDefaultValueFields;
       this.preservingProtoFieldNames = preservingProtoFieldNames;
     }
-    
+
     /**
      * Creates a new {@link Printer} using the given registry. The new Printer
      * clones all other configurations from the current {@link Printer}.
-     * 
+     *
      * @throws IllegalArgumentException if a registry is already set.
      */
     public Printer usingTypeRegistry(TypeRegistry registry) {
@@ -153,16 +153,15 @@
     public Printer preservingProtoFieldNames() {
       return new Printer(registry, includingDefaultValueFields, true);
     }
-    
+
     /**
      * Converts a protobuf message to JSON format.
-     * 
+     *
      * @throws InvalidProtocolBufferException if the message contains Any types
      *         that can't be resolved.
      * @throws IOException if writing to the output fails.
      */
-    public void appendTo(MessageOrBuilder message, Appendable output)
-        throws IOException {
+    public void appendTo(MessageOrBuilder message, Appendable output) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
       new PrinterImpl(registry, includingDefaultValueFields, preservingProtoFieldNames, output)
@@ -171,10 +170,9 @@
 
     /**
      * Converts a protobuf message to JSON format. Throws exceptions if there
-     * are unknown Any types in the message. 
+     * are unknown Any types in the message.
      */
-    public String print(MessageOrBuilder message)
-        throws InvalidProtocolBufferException {
+    public String print(MessageOrBuilder message) throws InvalidProtocolBufferException {
       try {
         StringBuilder builder = new StringBuilder();
         appendTo(message, builder);
@@ -194,21 +192,21 @@
   public static Parser parser() {
     return new Parser(TypeRegistry.getEmptyTypeRegistry());
   }
-  
+
   /**
    * A Parser parses JSON to protobuf message.
    */
   public static class Parser {
     private final TypeRegistry registry;
-    
+
     private Parser(TypeRegistry registry) {
-      this.registry = registry; 
+      this.registry = registry;
     }
-    
+
     /**
      * Creates a new {@link Parser} using the given registry. The new Parser
      * clones all other configurations from this Parser.
-     * 
+     *
      * @throws IllegalArgumentException if a registry is already set.
      */
     public Parser usingTypeRegistry(TypeRegistry registry) {
@@ -217,29 +215,27 @@
       }
       return new Parser(registry);
     }
-    
+
     /**
      * Parses from JSON into a protobuf message.
-     * 
+     *
      * @throws InvalidProtocolBufferException if the input is not valid JSON
      *         format or there are unknown fields in the input.
      */
-    public void merge(String json, Message.Builder builder)
-        throws InvalidProtocolBufferException {
+    public void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
       new ParserImpl(registry).merge(json, builder);
     }
-    
+
     /**
      * Parses from JSON into a protobuf message.
-     * 
+     *
      * @throws InvalidProtocolBufferException if the input is not valid JSON
      *         format or there are unknown fields in the input.
      * @throws IOException if reading from the input throws.
      */
-    public void merge(Reader json, Message.Builder builder)
-        throws IOException {
+    public void merge(Reader json, Message.Builder builder) throws IOException {
       // TODO(xiaofeng): Investigate the allocation overhead and optimize for
       // mobile.
       new ParserImpl(registry).merge(json, builder);
@@ -255,8 +251,8 @@
    */
   public static class TypeRegistry {
     private static class EmptyTypeRegistryHolder {
-      private static final TypeRegistry EMPTY = new TypeRegistry(
-          Collections.<String, Descriptor>emptyMap());
+      private static final TypeRegistry EMPTY =
+          new TypeRegistry(Collections.<String, Descriptor>emptyMap());
     }
 
     public static TypeRegistry getEmptyTypeRegistry() {
@@ -293,8 +289,7 @@
        */
       public Builder add(Descriptor messageType) {
         if (types == null) {
-          throw new IllegalStateException(
-              "A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
         }
         addFile(messageType.getFile());
         return this;
@@ -306,8 +301,7 @@
        */
       public Builder add(Iterable<Descriptor> messageTypes) {
         if (types == null) {
-          throw new IllegalStateException(
-              "A TypeRegistry.Builer can only be used once.");
+          throw new IllegalStateException("A TypeRegistry.Builer can only be used once.");
         }
         for (Descriptor type : messageTypes) {
           addFile(type.getFile());
@@ -345,8 +339,7 @@
         }
 
         if (types.containsKey(message.getFullName())) {
-          logger.warning("Type " + message.getFullName()
-              + " is added multiple times.");
+          logger.warning("Type " + message.getFullName() + " is added multiple times.");
           return;
         }
 
@@ -354,8 +347,7 @@
       }
 
       private final Set<String> files = new HashSet<String>();
-      private Map<String, Descriptor> types =
-          new HashMap<String, Descriptor>();
+      private Map<String, Descriptor> types = new HashMap<String, Descriptor>();
     }
   }
 
@@ -387,8 +379,7 @@
     public void outdent() {
       final int length = indent.length();
       if (length < 2) {
-        throw new IllegalArgumentException(
-            " Outdent() without matching Indent().");
+        throw new IllegalArgumentException(" Outdent() without matching Indent().");
       }
       indent.delete(length - 2, length);
     }
@@ -450,45 +441,41 @@
     }
 
     void print(MessageOrBuilder message) throws IOException {
-      WellKnownTypePrinter specialPrinter = wellKnownTypePrinters.get(
-          message.getDescriptorForType().getFullName());
+      WellKnownTypePrinter specialPrinter =
+          wellKnownTypePrinters.get(message.getDescriptorForType().getFullName());
       if (specialPrinter != null) {
         specialPrinter.print(this, message);
         return;
       }
       print(message, null);
     }
-    
+
     private interface WellKnownTypePrinter {
-      void print(PrinterImpl printer, MessageOrBuilder message)
-          throws IOException;
+      void print(PrinterImpl printer, MessageOrBuilder message) throws IOException;
     }
-    
-    private static final Map<String, WellKnownTypePrinter>
-    wellKnownTypePrinters = buildWellKnownTypePrinters();
-    
-    private static Map<String, WellKnownTypePrinter>
-    buildWellKnownTypePrinters() {
-      Map<String, WellKnownTypePrinter> printers =
-          new HashMap<String, WellKnownTypePrinter>();
+
+    private static final Map<String, WellKnownTypePrinter> wellKnownTypePrinters =
+        buildWellKnownTypePrinters();
+
+    private static Map<String, WellKnownTypePrinter> buildWellKnownTypePrinters() {
+      Map<String, WellKnownTypePrinter> printers = new HashMap<String, WellKnownTypePrinter>();
       // Special-case Any.
-      printers.put(Any.getDescriptor().getFullName(),
+      printers.put(
+          Any.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printAny(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printAny(message);
+            }
+          });
       // Special-case wrapper types.
-      WellKnownTypePrinter wrappersPrinter = new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printWrapper(message);
-          
-        }
-      };
+      WellKnownTypePrinter wrappersPrinter =
+          new WellKnownTypePrinter() {
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printWrapper(message);
+            }
+          };
       printers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -499,70 +486,71 @@
       printers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
       printers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
       // Special-case Timestamp.
-      printers.put(Timestamp.getDescriptor().getFullName(),
+      printers.put(
+          Timestamp.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printTimestamp(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printTimestamp(message);
+            }
+          });
       // Special-case Duration.
-      printers.put(Duration.getDescriptor().getFullName(),
+      printers.put(
+          Duration.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printDuration(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printDuration(message);
+            }
+          });
       // Special-case FieldMask.
-      printers.put(FieldMask.getDescriptor().getFullName(),
+      printers.put(
+          FieldMask.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printFieldMask(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printFieldMask(message);
+            }
+          });
       // Special-case Struct.
-      printers.put(Struct.getDescriptor().getFullName(),
+      printers.put(
+          Struct.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printStruct(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printStruct(message);
+            }
+          });
       // Special-case Value.
-      printers.put(Value.getDescriptor().getFullName(),
+      printers.put(
+          Value.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printValue(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printValue(message);
+            }
+          });
       // Special-case ListValue.
-      printers.put(ListValue.getDescriptor().getFullName(),
+      printers.put(
+          ListValue.getDescriptor().getFullName(),
           new WellKnownTypePrinter() {
-        @Override
-        public void print(PrinterImpl printer, MessageOrBuilder message)
-            throws IOException {
-          printer.printListValue(message);
-        }
-      });
+            @Override
+            public void print(PrinterImpl printer, MessageOrBuilder message) throws IOException {
+              printer.printListValue(message);
+            }
+          });
       return printers;
     }
-    
+
     /** Prints google.protobuf.Any */
     private void printAny(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
       FieldDescriptor valueField = descriptor.findFieldByName("value");
       // Validates type of the message. Note that we can't just cast the message
-      // to com.google.protobuf.Any because it might be a DynamicMessage. 
-      if (typeUrlField == null || valueField == null
+      // to com.google.protobuf.Any because it might be a DynamicMessage.
+      if (typeUrlField == null
+          || valueField == null
           || typeUrlField.getType() != FieldDescriptor.Type.STRING
           || valueField.getType() != FieldDescriptor.Type.BYTES) {
         throw new InvalidProtocolBufferException("Invalid Any type.");
@@ -571,12 +559,11 @@
       String typeName = getTypeName(typeUrl);
       Descriptor type = registry.find(typeName);
       if (type == null) {
-        throw new InvalidProtocolBufferException(
-            "Cannot find type for url: " + typeUrl);
+        throw new InvalidProtocolBufferException("Cannot find type for url: " + typeUrl);
       }
       ByteString content = (ByteString) message.getField(valueField);
-      Message contentMessage = DynamicMessage.getDefaultInstance(type)
-          .getParserForType().parseFrom(content);
+      Message contentMessage =
+          DynamicMessage.getDefaultInstance(type).getParserForType().parseFrom(content);
       WellKnownTypePrinter printer = wellKnownTypePrinters.get(typeName);
       if (printer != null) {
         // If the type is one of the well-known types, we use a special
@@ -594,7 +581,7 @@
         print(contentMessage, typeUrl);
       }
     }
-    
+
     /** Prints wrapper types (e.g., google.protobuf.Int32Value) */
     private void printWrapper(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -606,7 +593,7 @@
       // the whole message.
       printSingleFieldValue(valueField, message.getField(valueField));
     }
-    
+
     private ByteString toByteString(MessageOrBuilder message) {
       if (message instanceof Message) {
         return ((Message) message).toByteString();
@@ -614,26 +601,25 @@
         return ((Message.Builder) message).build().toByteString();
       }
     }
-    
+
     /** Prints google.protobuf.Timestamp */
     private void printTimestamp(MessageOrBuilder message) throws IOException {
       Timestamp value = Timestamp.parseFrom(toByteString(message));
-      generator.print("\"" + TimeUtil.toString(value) + "\"");
+      generator.print("\"" + Timestamps.toString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.Duration */
     private void printDuration(MessageOrBuilder message) throws IOException {
       Duration value = Duration.parseFrom(toByteString(message));
-      generator.print("\"" + TimeUtil.toString(value) + "\"");
-      
+      generator.print("\"" + Durations.toString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.FieldMask */
     private void printFieldMask(MessageOrBuilder message) throws IOException {
       FieldMask value = FieldMask.parseFrom(toByteString(message));
-      generator.print("\"" + FieldMaskUtil.toString(value) + "\"");
+      generator.print("\"" + FieldMaskUtil.toJsonString(value) + "\"");
     }
-    
+
     /** Prints google.protobuf.Struct */
     private void printStruct(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -644,7 +630,7 @@
       // Struct is formatted as a map object.
       printMapFieldValue(field, message.getField(field));
     }
-    
+
     /** Prints google.protobuf.Value */
     private void printValue(MessageOrBuilder message) throws IOException {
       // For a Value message, only the value of the field is formatted.
@@ -663,7 +649,7 @@
         printSingleFieldValue(entry.getKey(), entry.getValue());
       }
     }
-    
+
     /** Prints google.protobuf.ListValue */
     private void printListValue(MessageOrBuilder message) throws IOException {
       Descriptor descriptor = message.getDescriptorForType();
@@ -675,8 +661,7 @@
     }
 
     /** Prints a regular message with an optional type URL. */
-    private void print(MessageOrBuilder message, String typeUrl)
-        throws IOException {
+    private void print(MessageOrBuilder message, String typeUrl) throws IOException {
       generator.print("{\n");
       generator.indent();
 
@@ -710,7 +695,7 @@
         }
         printField(field.getKey(), field.getValue());
       }
-      
+
       // Add line-endings for the last field.
       if (printedField) {
         generator.print("\n");
@@ -719,8 +704,7 @@
       generator.print("}");
     }
 
-    private void printField(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printField(FieldDescriptor field, Object value) throws IOException {
       if (preservingProtoFieldNames) {
         generator.print("\"" + field.getName() + "\": ");
       } else {
@@ -734,10 +718,9 @@
         printSingleFieldValue(field, value);
       }
     }
-    
+
     @SuppressWarnings("rawtypes")
-    private void printRepeatedFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printRepeatedFieldValue(FieldDescriptor field, Object value) throws IOException {
       generator.print("[");
       boolean printedElement = false;
       for (Object element : (List) value) {
@@ -750,10 +733,9 @@
       }
       generator.print("]");
     }
-    
+
     @SuppressWarnings("rawtypes")
-    private void printMapFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+    private void printMapFieldValue(FieldDescriptor field, Object value) throws IOException {
       Descriptor type = field.getMessageType();
       FieldDescriptor keyField = type.findFieldByName("key");
       FieldDescriptor valueField = type.findFieldByName("value");
@@ -783,21 +765,20 @@
       generator.outdent();
       generator.print("}");
     }
-    
-    private void printSingleFieldValue(FieldDescriptor field, Object value)
-        throws IOException {
+
+    private void printSingleFieldValue(FieldDescriptor field, Object value) throws IOException {
       printSingleFieldValue(field, value, false);
     }
 
     /**
      * Prints a field's value in JSON format.
-     * 
+     *
      * @param alwaysWithQuotes whether to always add double-quotes to primitive
      *        types.
      */
     private void printSingleFieldValue(
-        final FieldDescriptor field, final Object value,
-        boolean alwaysWithQuotes) throws IOException {
+        final FieldDescriptor field, final Object value, boolean alwaysWithQuotes)
+        throws IOException {
       switch (field.getType()) {
         case INT32:
         case SINT32:
@@ -851,7 +832,7 @@
             }
           }
           break;
-          
+
         case DOUBLE:
           Double doubleValue = (Double) value;
           if (doubleValue.isNaN()) {
@@ -895,15 +876,13 @@
 
         case BYTES:
           generator.print("\"");
-          generator.print(
-              BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
+          generator.print(BaseEncoding.base64().encode(((ByteString) value).toByteArray()));
           generator.print("\"");
           break;
 
         case ENUM:
           // Special-case google.protobuf.NullValue (it's an Enum).
-          if (field.getEnumType().getFullName().equals(
-                  "google.protobuf.NullValue")) {
+          if (field.getEnumType().getFullName().equals("google.protobuf.NullValue")) {
             // No matter what value it contains, we always print it as "null".
             if (alwaysWithQuotes) {
               generator.print("\"");
@@ -914,11 +893,9 @@
             }
           } else {
             if (((EnumValueDescriptor) value).getIndex() == -1) {
-              generator.print(
-                  String.valueOf(((EnumValueDescriptor) value).getNumber()));
+              generator.print(String.valueOf(((EnumValueDescriptor) value).getNumber()));
             } else {
-              generator.print(
-                  "\"" + ((EnumValueDescriptor) value).getName() + "\"");
+              generator.print("\"" + ((EnumValueDescriptor) value).getName() + "\"");
             }
           }
           break;
@@ -947,40 +924,34 @@
     } else {
       // Pull off the most-significant bit so that BigInteger doesn't think
       // the number is negative, then set it again using setBit().
-      return BigInteger.valueOf(value & Long.MAX_VALUE)
-                       .setBit(Long.SIZE - 1).toString();
+      return BigInteger.valueOf(value & Long.MAX_VALUE).setBit(Long.SIZE - 1).toString();
     }
   }
-  
 
-  private static String getTypeName(String typeUrl)
-      throws InvalidProtocolBufferException {
+  private static String getTypeName(String typeUrl) throws InvalidProtocolBufferException {
     String[] parts = typeUrl.split("/");
     if (parts.length == 1) {
-      throw new InvalidProtocolBufferException(
-          "Invalid type url found: " + typeUrl);
+      throw new InvalidProtocolBufferException("Invalid type url found: " + typeUrl);
     }
     return parts[parts.length - 1];
   }
-  
+
   private static class ParserImpl {
     private final TypeRegistry registry;
     private final JsonParser jsonParser;
-    
+
     ParserImpl(TypeRegistry registry) {
       this.registry = registry;
       this.jsonParser = new JsonParser();
     }
-    
-    void merge(Reader json, Message.Builder builder)
-        throws IOException {
+
+    void merge(Reader json, Message.Builder builder) throws IOException {
       JsonReader reader = new JsonReader(json);
       reader.setLenient(false);
       merge(jsonParser.parse(reader), builder);
     }
-    
-    void merge(String json, Message.Builder builder)
-        throws InvalidProtocolBufferException {
+
+    void merge(String json, Message.Builder builder) throws InvalidProtocolBufferException {
       try {
         JsonReader reader = new JsonReader(new StringReader(json));
         reader.setLenient(false);
@@ -992,35 +963,36 @@
         throw new InvalidProtocolBufferException(e.getMessage());
       }
     }
-    
+
     private interface WellKnownTypeParser {
       void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
           throws InvalidProtocolBufferException;
     }
-    
+
     private static final Map<String, WellKnownTypeParser> wellKnownTypeParsers =
         buildWellKnownTypeParsers();
-    
-    private static Map<String, WellKnownTypeParser>
-    buildWellKnownTypeParsers() {
-      Map<String, WellKnownTypeParser> parsers =
-          new HashMap<String, WellKnownTypeParser>();
+
+    private static Map<String, WellKnownTypeParser> buildWellKnownTypeParsers() {
+      Map<String, WellKnownTypeParser> parsers = new HashMap<String, WellKnownTypeParser>();
       // Special-case Any.
-      parsers.put(Any.getDescriptor().getFullName(), new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeAny(json, builder);
-        }
-      });
+      parsers.put(
+          Any.getDescriptor().getFullName(),
+          new WellKnownTypeParser() {
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeAny(json, builder);
+            }
+          });
       // Special-case wrapper types.
-      WellKnownTypeParser wrappersPrinter = new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeWrapper(json, builder);
-        }
-      };
+      WellKnownTypeParser wrappersPrinter =
+          new WellKnownTypeParser() {
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeWrapper(json, builder);
+            }
+          };
       parsers.put(BoolValue.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(Int32Value.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(UInt32Value.getDescriptor().getFullName(), wrappersPrinter);
@@ -1031,82 +1003,86 @@
       parsers.put(FloatValue.getDescriptor().getFullName(), wrappersPrinter);
       parsers.put(DoubleValue.getDescriptor().getFullName(), wrappersPrinter);
       // Special-case Timestamp.
-      parsers.put(Timestamp.getDescriptor().getFullName(),
+      parsers.put(
+          Timestamp.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeTimestamp(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeTimestamp(json, builder);
+            }
+          });
       // Special-case Duration.
-      parsers.put(Duration.getDescriptor().getFullName(),
+      parsers.put(
+          Duration.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeDuration(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeDuration(json, builder);
+            }
+          });
       // Special-case FieldMask.
-      parsers.put(FieldMask.getDescriptor().getFullName(),
+      parsers.put(
+          FieldMask.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeFieldMask(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeFieldMask(json, builder);
+            }
+          });
       // Special-case Struct.
-      parsers.put(Struct.getDescriptor().getFullName(),
+      parsers.put(
+          Struct.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeStruct(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeStruct(json, builder);
+            }
+          });
       // Special-case ListValue.
-      parsers.put(ListValue.getDescriptor().getFullName(),
+      parsers.put(
+          ListValue.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeListValue(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeListValue(json, builder);
+            }
+          });
       // Special-case Value.
-      parsers.put(Value.getDescriptor().getFullName(),
+      parsers.put(
+          Value.getDescriptor().getFullName(),
           new WellKnownTypeParser() {
-        @Override
-        public void merge(ParserImpl parser, JsonElement json,
-            Message.Builder builder) throws InvalidProtocolBufferException {
-          parser.mergeValue(json, builder);
-        }
-      });
+            @Override
+            public void merge(ParserImpl parser, JsonElement json, Message.Builder builder)
+                throws InvalidProtocolBufferException {
+              parser.mergeValue(json, builder);
+            }
+          });
       return parsers;
     }
-    
+
     private void merge(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
-      WellKnownTypeParser specialParser = wellKnownTypeParsers.get(
-          builder.getDescriptorForType().getFullName());
+      WellKnownTypeParser specialParser =
+          wellKnownTypeParsers.get(builder.getDescriptorForType().getFullName());
       if (specialParser != null) {
         specialParser.merge(this, json, builder);
         return;
       }
       mergeMessage(json, builder, false);
     }
-    
+
     // Maps from camel-case field names to FieldDescriptor.
     private final Map<Descriptor, Map<String, FieldDescriptor>> fieldNameMaps =
         new HashMap<Descriptor, Map<String, FieldDescriptor>>();
-    
-    private Map<String, FieldDescriptor> getFieldNameMap(
-        Descriptor descriptor) {
+
+    private Map<String, FieldDescriptor> getFieldNameMap(Descriptor descriptor) {
       if (!fieldNameMaps.containsKey(descriptor)) {
-        Map<String, FieldDescriptor> fieldNameMap =
-            new HashMap<String, FieldDescriptor>();
+        Map<String, FieldDescriptor> fieldNameMap = new HashMap<String, FieldDescriptor>();
         for (FieldDescriptor field : descriptor.getFields()) {
           fieldNameMap.put(field.getName(), field);
           fieldNameMap.put(field.getJsonName(), field);
@@ -1116,16 +1092,14 @@
       }
       return fieldNameMaps.get(descriptor);
     }
-    
-    private void mergeMessage(JsonElement json, Message.Builder builder,
-        boolean skipTypeUrl) throws InvalidProtocolBufferException {
+
+    private void mergeMessage(JsonElement json, Message.Builder builder, boolean skipTypeUrl)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect message object but got: " + json);
+        throw new InvalidProtocolBufferException("Expect message object but got: " + json);
       }
       JsonObject object = (JsonObject) json;
-      Map<String, FieldDescriptor> fieldNameMap =
-          getFieldNameMap(builder.getDescriptorForType());
+      Map<String, FieldDescriptor> fieldNameMap = getFieldNameMap(builder.getDescriptorForType());
       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
         if (skipTypeUrl && entry.getKey().equals("@type")) {
           continue;
@@ -1133,47 +1107,46 @@
         FieldDescriptor field = fieldNameMap.get(entry.getKey());
         if (field == null) {
           throw new InvalidProtocolBufferException(
-              "Cannot find field: " + entry.getKey() + " in message "
-              + builder.getDescriptorForType().getFullName());
+              "Cannot find field: "
+                  + entry.getKey()
+                  + " in message "
+                  + builder.getDescriptorForType().getFullName());
         }
         mergeField(field, entry.getValue(), builder);
       }
     }
-    
+
     private void mergeAny(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor descriptor = builder.getDescriptorForType();
       FieldDescriptor typeUrlField = descriptor.findFieldByName("type_url");
       FieldDescriptor valueField = descriptor.findFieldByName("value");
       // Validates type of the message. Note that we can't just cast the message
-      // to com.google.protobuf.Any because it might be a DynamicMessage. 
-      if (typeUrlField == null || valueField == null
+      // to com.google.protobuf.Any because it might be a DynamicMessage.
+      if (typeUrlField == null
+          || valueField == null
           || typeUrlField.getType() != FieldDescriptor.Type.STRING
           || valueField.getType() != FieldDescriptor.Type.BYTES) {
         throw new InvalidProtocolBufferException("Invalid Any type.");
       }
-      
+
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect message object but got: " + json);
+        throw new InvalidProtocolBufferException("Expect message object but got: " + json);
       }
       JsonObject object = (JsonObject) json;
       JsonElement typeUrlElement = object.get("@type");
       if (typeUrlElement == null) {
-        throw new InvalidProtocolBufferException(
-            "Missing type url when parsing: " + json);
+        throw new InvalidProtocolBufferException("Missing type url when parsing: " + json);
       }
       String typeUrl = typeUrlElement.getAsString();
       Descriptor contentType = registry.find(getTypeName(typeUrl));
       if (contentType == null) {
-        throw new InvalidProtocolBufferException(
-            "Cannot resolve type: " + typeUrl);
+        throw new InvalidProtocolBufferException("Cannot resolve type: " + typeUrl);
       }
       builder.setField(typeUrlField, typeUrl);
       Message.Builder contentBuilder =
           DynamicMessage.getDefaultInstance(contentType).newBuilderForType();
-      WellKnownTypeParser specialParser =
-          wellKnownTypeParsers.get(contentType.getFullName());
+      WellKnownTypeParser specialParser = wellKnownTypeParsers.get(contentType.getFullName());
       if (specialParser != null) {
         JsonElement value = object.get("value");
         if (value != null) {
@@ -1184,35 +1157,33 @@
       }
       builder.setField(valueField, contentBuilder.build().toByteString());
     }
-    
+
     private void mergeFieldMask(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
-      FieldMask value = FieldMaskUtil.fromString(json.getAsString());
+      FieldMask value = FieldMaskUtil.fromJsonString(json.getAsString());
       builder.mergeFrom(value.toByteString());
     }
-    
+
     private void mergeTimestamp(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       try {
-        Timestamp value = TimeUtil.parseTimestamp(json.getAsString());
+        Timestamp value = Timestamps.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException e) {
-        throw new InvalidProtocolBufferException(
-            "Failed to parse timestamp: " + json);
+        throw new InvalidProtocolBufferException("Failed to parse timestamp: " + json);
       }
     }
-    
+
     private void mergeDuration(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       try {
-        Duration value = TimeUtil.parseDuration(json.getAsString());
+        Duration value = Durations.parse(json.getAsString());
         builder.mergeFrom(value.toByteString());
       } catch (ParseException e) {
-        throw new InvalidProtocolBufferException(
-            "Failed to parse duration: " + json);
+        throw new InvalidProtocolBufferException("Failed to parse duration: " + json);
       }
     }
-    
+
     private void mergeStruct(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor descriptor = builder.getDescriptorForType();
@@ -1232,21 +1203,18 @@
       }
       mergeRepeatedField(field, json, builder);
     }
-    
+
     private void mergeValue(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor type = builder.getDescriptorForType();
       if (json instanceof JsonPrimitive) {
         JsonPrimitive primitive = (JsonPrimitive) json;
         if (primitive.isBoolean()) {
-          builder.setField(type.findFieldByName("bool_value"),
-              primitive.getAsBoolean());
+          builder.setField(type.findFieldByName("bool_value"), primitive.getAsBoolean());
         } else if (primitive.isNumber()) {
-          builder.setField(type.findFieldByName("number_value"),
-              primitive.getAsDouble());
+          builder.setField(type.findFieldByName("number_value"), primitive.getAsDouble());
         } else {
-          builder.setField(type.findFieldByName("string_value"),
-              primitive.getAsString());
+          builder.setField(type.findFieldByName("string_value"), primitive.getAsString());
         }
       } else if (json instanceof JsonObject) {
         FieldDescriptor field = type.findFieldByName("struct_value");
@@ -1262,20 +1230,19 @@
         throw new IllegalStateException("Unexpected json data: " + json);
       }
     }
-    
+
     private void mergeWrapper(JsonElement json, Message.Builder builder)
         throws InvalidProtocolBufferException {
       Descriptor type = builder.getDescriptorForType();
       FieldDescriptor field = type.findFieldByName("value");
       if (field == null) {
-        throw new InvalidProtocolBufferException(
-            "Invalid wrapper type: " + type.getFullName());
+        throw new InvalidProtocolBufferException("Invalid wrapper type: " + type.getFullName());
       }
       builder.setField(field, parseFieldValue(field, json, builder));
     }
-    
-    private void mergeField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (field.isRepeated()) {
         if (builder.getRepeatedFieldCount(field) > 0) {
           throw new InvalidProtocolBufferException(
@@ -1290,8 +1257,11 @@
             && builder.getOneofFieldDescriptor(field.getContainingOneof()) != null) {
           FieldDescriptor other = builder.getOneofFieldDescriptor(field.getContainingOneof());
           throw new InvalidProtocolBufferException(
-              "Cannot set field " + field.getFullName() + " because another field "
-              + other.getFullName() + " belonging to the same oneof has already been set ");
+              "Cannot set field "
+                  + field.getFullName()
+                  + " because another field "
+                  + other.getFullName()
+                  + " belonging to the same oneof has already been set ");
         }
       }
       if (field.isRepeated() && json instanceof JsonNull) {
@@ -1310,44 +1280,38 @@
         }
       }
     }
-    
-    private void mergeMapField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeMapField(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonObject)) {
-        throw new InvalidProtocolBufferException(
-            "Expect a map object but found: " + json);
+        throw new InvalidProtocolBufferException("Expect a map object but found: " + json);
       }
       Descriptor type = field.getMessageType();
       FieldDescriptor keyField = type.findFieldByName("key");
       FieldDescriptor valueField = type.findFieldByName("value");
       if (keyField == null || valueField == null) {
-        throw new InvalidProtocolBufferException(
-            "Invalid map field: " + field.getFullName());
+        throw new InvalidProtocolBufferException("Invalid map field: " + field.getFullName());
       }
       JsonObject object = (JsonObject) json;
       for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
         Message.Builder entryBuilder = builder.newBuilderForField(field);
-        Object key = parseFieldValue(
-            keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
-        Object value = parseFieldValue(
-            valueField, entry.getValue(), entryBuilder);
+        Object key = parseFieldValue(keyField, new JsonPrimitive(entry.getKey()), entryBuilder);
+        Object value = parseFieldValue(valueField, entry.getValue(), entryBuilder);
         if (value == null) {
-          throw new InvalidProtocolBufferException(
-              "Map value cannot be null.");
+          throw new InvalidProtocolBufferException("Map value cannot be null.");
         }
         entryBuilder.setField(keyField, key);
         entryBuilder.setField(valueField, value);
         builder.addRepeatedField(field, entryBuilder.build());
       }
     }
-    
+
     /**
      * Gets the default value for a field type. Note that we use proto3
      * language defaults and ignore any default values set through the
-     * proto "default" option. 
+     * proto "default" option.
      */
-    private Object getDefaultValue(FieldDescriptor field,
-        Message.Builder builder) {
+    private Object getDefaultValue(FieldDescriptor field, Message.Builder builder) {
       switch (field.getType()) {
         case INT32:
         case SINT32:
@@ -1377,30 +1341,27 @@
         case GROUP:
           return builder.newBuilderForField(field).getDefaultInstanceForType();
         default:
-          throw new IllegalStateException(
-              "Invalid field type: " + field.getType());
+          throw new IllegalStateException("Invalid field type: " + field.getType());
       }
     }
-    
-    private void mergeRepeatedField(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private void mergeRepeatedField(
+        FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (!(json instanceof JsonArray)) {
-        throw new InvalidProtocolBufferException(
-            "Expect an array but found: " + json);
+        throw new InvalidProtocolBufferException("Expect an array but found: " + json);
       }
       JsonArray array = (JsonArray) json;
       for (int i = 0; i < array.size(); ++i) {
         Object value = parseFieldValue(field, array.get(i), builder);
         if (value == null) {
-          throw new InvalidProtocolBufferException(
-              "Repeated field elements cannot be null");
+          throw new InvalidProtocolBufferException("Repeated field elements cannot be null");
         }
         builder.addRepeatedField(field, value);
       }
     }
-    
-    private int parseInt32(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private int parseInt32(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Integer.parseInt(json.getAsString());
       } catch (Exception e) {
@@ -1416,9 +1377,8 @@
         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
       }
     }
-    
-    private long parseInt64(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private long parseInt64(JsonElement json) throws InvalidProtocolBufferException {
       try {
         return Long.parseLong(json.getAsString());
       } catch (Exception e) {
@@ -1434,14 +1394,12 @@
         throw new InvalidProtocolBufferException("Not an int32 value: " + json);
       }
     }
-    
-    private int parseUint32(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private int parseUint32(JsonElement json) throws InvalidProtocolBufferException {
       try {
         long result = Long.parseLong(json.getAsString());
         if (result < 0 || result > 0xFFFFFFFFL) {
-          throw new InvalidProtocolBufferException(
-              "Out of range uint32 value: " + json);
+          throw new InvalidProtocolBufferException("Out of range uint32 value: " + json);
         }
         return (int) result;
       } catch (InvalidProtocolBufferException e) {
@@ -1462,35 +1420,28 @@
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an uint32 value: " + json);
+        throw new InvalidProtocolBufferException("Not an uint32 value: " + json);
       }
     }
-    
-    private static final BigInteger MAX_UINT64 =
-        new BigInteger("FFFFFFFFFFFFFFFF", 16);
-    
-    private long parseUint64(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private static final BigInteger MAX_UINT64 = new BigInteger("FFFFFFFFFFFFFFFF", 16);
+
+    private long parseUint64(JsonElement json) throws InvalidProtocolBufferException {
       try {
         BigDecimal decimalValue = new BigDecimal(json.getAsString());
         BigInteger value = decimalValue.toBigIntegerExact();
-        if (value.compareTo(BigInteger.ZERO) < 0
-            || value.compareTo(MAX_UINT64) > 0) {
-          throw new InvalidProtocolBufferException(
-              "Out of range uint64 value: " + json);
+        if (value.compareTo(BigInteger.ZERO) < 0 || value.compareTo(MAX_UINT64) > 0) {
+          throw new InvalidProtocolBufferException("Out of range uint64 value: " + json);
         }
         return value.longValue();
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an uint64 value: " + json);
+        throw new InvalidProtocolBufferException("Not an uint64 value: " + json);
       }
     }
-    
-    private boolean parseBool(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private boolean parseBool(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("true")) {
         return true;
       }
@@ -1499,11 +1450,10 @@
       }
       throw new InvalidProtocolBufferException("Invalid bool value: " + json);
     }
-    
+
     private static final double EPSILON = 1e-6;
-    
-    private float parseFloat(JsonElement json)
-        throws InvalidProtocolBufferException {
+
+    private float parseFloat(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("NaN")) {
         return Float.NaN;
       } else if (json.getAsString().equals("Infinity")) {
@@ -1521,8 +1471,7 @@
         // of tolerance when checking whether the float value is in range.
         if (value > Float.MAX_VALUE * (1.0 + EPSILON)
             || value < -Float.MAX_VALUE * (1.0 + EPSILON)) {
-          throw new InvalidProtocolBufferException(
-              "Out of range float value: " + json);
+          throw new InvalidProtocolBufferException("Out of range float value: " + json);
         }
         return (float) value;
       } catch (InvalidProtocolBufferException e) {
@@ -1531,19 +1480,17 @@
         throw new InvalidProtocolBufferException("Not a float value: " + json);
       }
     }
-    
-    private static final BigDecimal MORE_THAN_ONE = new BigDecimal(
-        String.valueOf(1.0 + EPSILON));
+
+    private static final BigDecimal MORE_THAN_ONE = new BigDecimal(String.valueOf(1.0 + EPSILON));
     // When a float value is printed, the printed value might be a little
     // larger or smaller due to precision loss. Here we need to add a bit
     // of tolerance when checking whether the float value is in range.
-    private static final BigDecimal MAX_DOUBLE = new BigDecimal(
-        String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
-    private static final BigDecimal MIN_DOUBLE = new BigDecimal(
-        String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
-    
-    private double parseDouble(JsonElement json)
-        throws InvalidProtocolBufferException {
+    private static final BigDecimal MAX_DOUBLE =
+        new BigDecimal(String.valueOf(Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+    private static final BigDecimal MIN_DOUBLE =
+        new BigDecimal(String.valueOf(-Double.MAX_VALUE)).multiply(MORE_THAN_ONE);
+
+    private double parseDouble(JsonElement json) throws InvalidProtocolBufferException {
       if (json.getAsString().equals("NaN")) {
         return Double.NaN;
       } else if (json.getAsString().equals("Infinity")) {
@@ -1556,36 +1503,32 @@
         // accepts all values. Here we parse the value into a BigDecimal and do
         // explicit range check on it.
         BigDecimal value = new BigDecimal(json.getAsString());
-        if (value.compareTo(MAX_DOUBLE) > 0
-            || value.compareTo(MIN_DOUBLE) < 0) {
-          throw new InvalidProtocolBufferException(
-              "Out of range double value: " + json);
+        if (value.compareTo(MAX_DOUBLE) > 0 || value.compareTo(MIN_DOUBLE) < 0) {
+          throw new InvalidProtocolBufferException("Out of range double value: " + json);
         }
         return value.doubleValue();
       } catch (InvalidProtocolBufferException e) {
         throw e;
       } catch (Exception e) {
-        throw new InvalidProtocolBufferException(
-            "Not an double value: " + json);
+        throw new InvalidProtocolBufferException("Not an double value: " + json);
       }
     }
-    
+
     private String parseString(JsonElement json) {
       return json.getAsString();
     }
-    
+
     private ByteString parseBytes(JsonElement json) throws InvalidProtocolBufferException {
       String encoded = json.getAsString();
       if (encoded.length() % 4 != 0) {
         throw new InvalidProtocolBufferException(
             "Bytes field is not encoded in standard BASE64 with paddings: " + encoded);
       }
-      return ByteString.copyFrom(
-          BaseEncoding.base64().decode(json.getAsString()));
+      return ByteString.copyFrom(BaseEncoding.base64().decode(json.getAsString()));
     }
-    
-    private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor,
-        JsonElement json) throws InvalidProtocolBufferException {
+
+    private EnumValueDescriptor parseEnum(EnumDescriptor enumDescriptor, JsonElement json)
+        throws InvalidProtocolBufferException {
       String value = json.getAsString();
       EnumValueDescriptor result = enumDescriptor.findValueByName(value);
       if (result == null) {
@@ -1602,27 +1545,28 @@
           // that's not the exception we want the user to see. Since result == null, we will throw
           // an exception later.
         }
-        
+
         if (result == null) {
           throw new InvalidProtocolBufferException(
-              "Invalid enum value: " + value + " for enum type: "
-              + enumDescriptor.getFullName());
+              "Invalid enum value: " + value + " for enum type: " + enumDescriptor.getFullName());
         }
       }
       return result;
     }
-    
-    private Object parseFieldValue(FieldDescriptor field, JsonElement json,
-        Message.Builder builder) throws InvalidProtocolBufferException {
+
+    private Object parseFieldValue(FieldDescriptor field, JsonElement json, Message.Builder builder)
+        throws InvalidProtocolBufferException {
       if (json instanceof JsonNull) {
         if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE
-            && field.getMessageType().getFullName().equals(
-                   Value.getDescriptor().getFullName())) {
+            && field.getMessageType().getFullName().equals(Value.getDescriptor().getFullName())) {
           // For every other type, "null" means absence, but for the special
           // Value message, it means the "null_value" field has been set.
           Value value = Value.newBuilder().setNullValueValue(0).build();
-          return builder.newBuilderForField(field).mergeFrom(
-              value.toByteString()).build();
+          return builder.newBuilderForField(field).mergeFrom(value.toByteString()).build();
+        } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM
+            && field.getEnumType().getFullName().equals(NullValue.getDescriptor().getFullName())) {
+          // If the type of the field is a NullValue, then the value should be explicitly set.
+          return field.getEnumType().findValueByNumber(0);
         }
         return null;
       }
@@ -1642,7 +1586,7 @@
 
         case FLOAT:
           return parseFloat(json);
-          
+
         case DOUBLE:
           return parseDouble(json);
 
@@ -1668,11 +1612,10 @@
           Message.Builder subBuilder = builder.newBuilderForField(field);
           merge(json, subBuilder);
           return subBuilder.build();
-          
+
         default:
-          throw new InvalidProtocolBufferException(
-              "Invalid field type: " + field.getType());
-      } 
+          throw new InvalidProtocolBufferException("Invalid field type: " + field.getType());
+      }
     }
   }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
index 3033182..0475847 100644
--- a/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
+++ b/java/util/src/main/java/com/google/protobuf/util/TimeUtil.java
@@ -35,15 +35,14 @@
 
 import java.math.BigInteger;
 import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.GregorianCalendar;
-import java.util.TimeZone;
 
 /**
  * Utilities to help create/manipulate Timestamp/Duration
+ *
+ * @deprecated Use {@link Durations} and {@link Timestamps} instead.
  */
-public class TimeUtil {
+@Deprecated
+public final class TimeUtil {
   // Timestamp for "0001-01-01T00:00:00Z"
   public static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
 
@@ -53,28 +52,6 @@
   public static final long DURATION_SECONDS_MAX = 315576000000L;
 
   private static final long NANOS_PER_SECOND = 1000000000;
-  private static final long NANOS_PER_MILLISECOND = 1000000;
-  private static final long NANOS_PER_MICROSECOND = 1000;
-  private static final long MILLIS_PER_SECOND = 1000;
-  private static final long MICROS_PER_SECOND = 1000000;
-
-  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
-      new ThreadLocal<SimpleDateFormat>() {
-        protected SimpleDateFormat initialValue() {
-          return createTimestampFormat();
-        }
-      };
-
-  private static SimpleDateFormat createTimestampFormat() {
-    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
-    GregorianCalendar calendar =
-      new GregorianCalendar(TimeZone.getTimeZone("UTC"));
-    // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
-    // backwards to year one) for timestamp formating.
-    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
-    sdf.setCalendar(calendar);
-    return sdf;
-  }
 
   private TimeUtil() {}
 
@@ -90,27 +67,11 @@
    * @return The string representation of the given timestamp.
    * @throws IllegalArgumentException if the given timestamp is not in the
    *         valid range.
+   * @deprecated Use {@link Timestamps#toString} instead.
    */
-  public static String toString(Timestamp timestamp)
-    throws IllegalArgumentException {
-    StringBuilder result = new StringBuilder();
-    // Format the seconds part.
-    if (timestamp.getSeconds() < TIMESTAMP_SECONDS_MIN
-        || timestamp.getSeconds() > TIMESTAMP_SECONDS_MAX) {
-      throw new IllegalArgumentException("Timestamp is out of range.");
-    }
-    Date date = new Date(timestamp.getSeconds() * MILLIS_PER_SECOND);
-    result.append(timestampFormat.get().format(date));
-    // Format the nanos part.
-    if (timestamp.getNanos() < 0 || timestamp.getNanos() >= NANOS_PER_SECOND) {
-      throw new IllegalArgumentException("Timestamp has invalid nanos value.");
-    }
-    if (timestamp.getNanos() != 0) {
-      result.append(".");
-      result.append(formatNanos(timestamp.getNanos()));
-    }
-    result.append("Z");
-    return result.toString();
+  @Deprecated
+  public static String toString(Timestamp timestamp) {
+    return Timestamps.toString(timestamp);
   }
 
   /**
@@ -123,59 +84,11 @@
    *
    * @return A Timestamp parsed from the string.
    * @throws ParseException if parsing fails.
+   * @deprecated Use {@link Timestamps#parse} instead.
    */
-
+  @Deprecated
   public static Timestamp parseTimestamp(String value) throws ParseException {
-    int dayOffset = value.indexOf('T');
-    if (dayOffset == -1) {
-      throw new ParseException(
-        "Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
-    }
-    int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
-    if (timezoneOffsetPosition == -1) {
-      timezoneOffsetPosition = value.indexOf('+', dayOffset);
-    }
-    if (timezoneOffsetPosition == -1) {
-      timezoneOffsetPosition = value.indexOf('-', dayOffset);
-    }
-    if (timezoneOffsetPosition == -1) {
-      throw new ParseException(
-        "Failed to parse timestamp: missing valid timezone offset.", 0);
-    }
-    // Parse seconds and nanos.
-    String timeValue = value.substring(0, timezoneOffsetPosition);
-    String secondValue = timeValue;
-    String nanoValue = "";
-    int pointPosition = timeValue.indexOf('.');
-    if (pointPosition != -1) {
-      secondValue = timeValue.substring(0, pointPosition);
-      nanoValue = timeValue.substring(pointPosition + 1);
-    }
-    Date date = timestampFormat.get().parse(secondValue);
-    long seconds = date.getTime() / MILLIS_PER_SECOND;
-    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
-    // Parse timezone offsets.
-    if (value.charAt(timezoneOffsetPosition) == 'Z') {
-      if (value.length() != timezoneOffsetPosition + 1) {
-        throw new ParseException(
-          "Failed to parse timestamp: invalid trailing data \""
-          + value.substring(timezoneOffsetPosition) + "\"", 0);
-      }
-    } else {
-      String offsetValue = value.substring(timezoneOffsetPosition + 1);
-      long offset = parseTimezoneOffset(offsetValue);
-      if (value.charAt(timezoneOffsetPosition) == '+') {
-        seconds -= offset;
-      } else {
-        seconds += offset;
-      }
-    }
-    try {
-      return normalizedTimestamp(seconds, nanos);
-    } catch (IllegalArgumentException e) {
-      throw new ParseException(
-        "Failed to parse timestmap: timestamp is out of range.", 0);
-    }
+    return Timestamps.parse(value);
   }
 
   /**
@@ -188,33 +101,11 @@
    * @return The string representation of the given duration.
    * @throws IllegalArgumentException if the given duration is not in the valid
    *         range.
+   * @deprecated Use {@link Durations#toString} instead.
    */
-  public static String toString(Duration duration)
-    throws IllegalArgumentException {
-    if (duration.getSeconds() < DURATION_SECONDS_MIN
-      || duration.getSeconds() > DURATION_SECONDS_MAX) {
-      throw new IllegalArgumentException("Duration is out of valid range.");
-    }
-    StringBuilder result = new StringBuilder();
-    long seconds = duration.getSeconds();
-    int nanos = duration.getNanos();
-    if (seconds < 0 || nanos < 0) {
-      if (seconds > 0 || nanos > 0) {
-        throw new IllegalArgumentException(
-            "Invalid duration: seconds value and nanos value must have the same"
-            + "sign.");
-      }
-      result.append("-");
-      seconds = -seconds;
-      nanos = -nanos;
-    }
-    result.append(seconds);
-    if (nanos != 0) {
-      result.append(".");
-      result.append(formatNanos(nanos));
-    }
-    result.append("s");
-    return result.toString();
+  @Deprecated
+  public static String toString(Duration duration) {
+    return Durations.toString(duration);
   }
 
   /**
@@ -222,54 +113,31 @@
    *
    * @return A Duration parsed from the string.
    * @throws ParseException if parsing fails.
+   * @deprecated Use {@link Durations#parse} instead.
    */
+  @Deprecated
   public static Duration parseDuration(String value) throws ParseException {
-    // Must ended with "s".
-    if (value.isEmpty() || value.charAt(value.length() - 1) != 's') {
-      throw new ParseException("Invalid duration string: " + value, 0);
-    }
-    boolean negative = false;
-    if (value.charAt(0) == '-') {
-      negative = true;
-      value = value.substring(1);
-    }
-    String secondValue = value.substring(0, value.length() - 1);
-    String nanoValue = "";
-    int pointPosition = secondValue.indexOf('.');
-    if (pointPosition != -1) {
-      nanoValue = secondValue.substring(pointPosition + 1);
-      secondValue = secondValue.substring(0, pointPosition);
-    }
-    long seconds = Long.parseLong(secondValue);
-    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
-    if (seconds < 0) {
-      throw new ParseException("Invalid duration string: " + value, 0);
-    }
-    if (negative) {
-      seconds = -seconds;
-      nanos = -nanos;
-    }
-    try {
-      return normalizedDuration(seconds, nanos);
-    } catch (IllegalArgumentException e) {
-      throw new ParseException("Duration value is out of range.", 0);
-    }
+    return Durations.parse(value);
   }
 
   /**
    * Create a Timestamp from the number of milliseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromMillis} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromMillis(long milliseconds) {
-    return normalizedTimestamp(milliseconds / MILLIS_PER_SECOND,
-      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+    return Timestamps.fromMillis(milliseconds);
   }
 
   /**
    * Create a Duration from the number of milliseconds.
+   *
+   * @deprecated Use {@link Durations#fromMillis} instead.
    */
+  @Deprecated
   public static Duration createDurationFromMillis(long milliseconds) {
-    return normalizedDuration(milliseconds / MILLIS_PER_SECOND,
-      (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+    return Durations.fromMillis(milliseconds);
   }
 
   /**
@@ -278,36 +146,44 @@
    * <p>The result will be rounded down to the nearest millisecond. E.g., if the
    * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
    * to -1 millisecond.
+   *
+   * @deprecated Use {@link Timestamps#toMillis} instead.
    */
+  @Deprecated
   public static long toMillis(Timestamp timestamp) {
-    return timestamp.getSeconds() * MILLIS_PER_SECOND + timestamp.getNanos()
-      / NANOS_PER_MILLISECOND;
+    return Timestamps.toMillis(timestamp);
   }
 
   /**
    * Convert a Duration to the number of milliseconds.The result will be
    * rounded towards 0 to the nearest millisecond. E.g., if the duration
    * represents -1 nanosecond, it will be rounded to 0.
+   *
+   * @deprecated Use {@link Durations#toMillis} instead.
    */
+  @Deprecated
   public static long toMillis(Duration duration) {
-    return duration.getSeconds() * MILLIS_PER_SECOND + duration.getNanos()
-      / NANOS_PER_MILLISECOND;
+    return Durations.toMillis(duration);
   }
 
   /**
    * Create a Timestamp from the number of microseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromMicros} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromMicros(long microseconds) {
-    return normalizedTimestamp(microseconds / MICROS_PER_SECOND,
-      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+    return Timestamps.fromMicros(microseconds);
   }
 
   /**
    * Create a Duration from the number of microseconds.
+   *
+   * @deprecated Use {@link Durations#fromMicros} instead.
    */
+  @Deprecated
   public static Duration createDurationFromMicros(long microseconds) {
-    return normalizedDuration(microseconds / MICROS_PER_SECOND,
-      (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+    return Durations.fromMicros(microseconds);
   }
 
   /**
@@ -316,111 +192,141 @@
    * <p>The result will be rounded down to the nearest microsecond. E.g., if the
    * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
    * to -1 millisecond.
+   *
+   * @deprecated Use {@link Timestamps#toMicros} instead.
    */
+  @Deprecated
   public static long toMicros(Timestamp timestamp) {
-    return timestamp.getSeconds() * MICROS_PER_SECOND + timestamp.getNanos()
-      / NANOS_PER_MICROSECOND;
+    return Timestamps.toMicros(timestamp);
   }
 
   /**
    * Convert a Duration to the number of microseconds.The result will be
    * rounded towards 0 to the nearest microseconds. E.g., if the duration
    * represents -1 nanosecond, it will be rounded to 0.
+   *
+   * @deprecated Use {@link Durations#toMicros} instead.
    */
+  @Deprecated
   public static long toMicros(Duration duration) {
-    return duration.getSeconds() * MICROS_PER_SECOND + duration.getNanos()
-      / NANOS_PER_MICROSECOND;
+    return Durations.toMicros(duration);
   }
 
   /**
    * Create a Timestamp from the number of nanoseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#fromNanos} instead.
    */
+  @Deprecated
   public static Timestamp createTimestampFromNanos(long nanoseconds) {
-    return normalizedTimestamp(nanoseconds / NANOS_PER_SECOND,
-      (int) (nanoseconds % NANOS_PER_SECOND));
+    return Timestamps.fromNanos(nanoseconds);
   }
 
   /**
    * Create a Duration from the number of nanoseconds.
+   *
+   * @deprecated Use {@link Durations#fromNanos} instead.
    */
+  @Deprecated
   public static Duration createDurationFromNanos(long nanoseconds) {
-    return normalizedDuration(nanoseconds / NANOS_PER_SECOND,
-      (int) (nanoseconds % NANOS_PER_SECOND));
+    return Durations.fromNanos(nanoseconds);
   }
 
   /**
    * Convert a Timestamp to the number of nanoseconds elapsed from the epoch.
+   *
+   * @deprecated Use {@link Timestamps#toNanos} instead.
    */
+  @Deprecated
   public static long toNanos(Timestamp timestamp) {
-    return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
+    return Timestamps.toNanos(timestamp);
   }
 
   /**
    * Convert a Duration to the number of nanoseconds.
+   *
+   * @deprecated Use {@link Durations#toNanos} instead.
    */
+  @Deprecated
   public static long toNanos(Duration duration) {
-    return duration.getSeconds() * NANOS_PER_SECOND + duration.getNanos();
+    return Durations.toNanos(duration);
   }
 
   /**
    * Get the current time.
+   *
+   * @deprecated Use {@code Timestamps.fromMillis(System.currentTimeMillis())} instead.
    */
+  @Deprecated
   public static Timestamp getCurrentTime() {
-    return createTimestampFromMillis(System.currentTimeMillis());
+    return Timestamps.fromMillis(System.currentTimeMillis());
   }
 
   /**
    * Get the epoch.
+   *
+   * @deprecated Use {@code Timestamps.fromMillis(0)} instead.
    */
+  @Deprecated
   public static Timestamp getEpoch() {
     return Timestamp.getDefaultInstance();
   }
 
   /**
    * Calculate the difference between two timestamps.
+   *
+   * @deprecated Use {@link Timestamps#between} instead.
    */
+  @Deprecated
   public static Duration distance(Timestamp from, Timestamp to) {
-    return normalizedDuration(to.getSeconds() - from.getSeconds(),
-      to.getNanos() - from.getNanos());
+    return Timestamps.between(from, to);
   }
 
   /**
    * Add a duration to a timestamp.
+   *
+   * @deprecated Use {@link Timestamps#add} instead.
    */
+  @Deprecated
   public static Timestamp add(Timestamp start, Duration length) {
-    return normalizedTimestamp(start.getSeconds() + length.getSeconds(),
-      start.getNanos() + length.getNanos());
+    return Timestamps.add(start, length);
   }
 
   /**
    * Subtract a duration from a timestamp.
+   *
+   * @deprecated Use {@link Timestamps#subtract} instead.
    */
+  @Deprecated
   public static Timestamp subtract(Timestamp start, Duration length) {
-    return normalizedTimestamp(start.getSeconds() - length.getSeconds(),
-      start.getNanos() - length.getNanos());
+    return Timestamps.subtract(start, length);
   }
 
   /**
    * Add two durations.
+   *
+   * @deprecated Use {@link Durations#add} instead.
    */
+  @Deprecated
   public static Duration add(Duration d1, Duration d2) {
-    return normalizedDuration(d1.getSeconds() + d2.getSeconds(),
-      d1.getNanos() + d2.getNanos());
+    return Durations.add(d1, d2);
   }
 
   /**
    * Subtract a duration from another.
+   *
+   * @deprecated Use {@link Durations#subtract} instead.
    */
+  @Deprecated
   public static Duration subtract(Duration d1, Duration d2) {
-    return normalizedDuration(d1.getSeconds() - d2.getSeconds(),
-      d1.getNanos() - d2.getNanos());
+    return Durations.subtract(d1, d2);
   }
 
   // Multiplications and divisions.
 
+  // TODO(kak): Delete this.
   public static Duration multiply(Duration duration, double times) {
-    double result = duration.getSeconds() * times + duration.getNanos() * times
-      / 1000000000.0;
+    double result = duration.getSeconds() * times + duration.getNanos() * times / 1000000000.0;
     if (result < Long.MIN_VALUE || result > Long.MAX_VALUE) {
       throw new IllegalArgumentException("Result is out of valid range.");
     }
@@ -428,50 +334,49 @@
     int nanos = (int) ((result - seconds) * 1000000000);
     return normalizedDuration(seconds, nanos);
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration divide(Duration duration, double value) {
     return multiply(duration, 1.0 / value);
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration multiply(Duration duration, long times) {
-    return createDurationFromBigInteger(
-      toBigInteger(duration).multiply(toBigInteger(times)));
+    return createDurationFromBigInteger(toBigInteger(duration).multiply(toBigInteger(times)));
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration divide(Duration duration, long times) {
-    return createDurationFromBigInteger(
-      toBigInteger(duration).divide(toBigInteger(times)));
+    return createDurationFromBigInteger(toBigInteger(duration).divide(toBigInteger(times)));
   }
-  
+
+  // TODO(kak): Delete this.
   public static long divide(Duration d1, Duration d2) {
     return toBigInteger(d1).divide(toBigInteger(d2)).longValue();
   }
-  
+
+  // TODO(kak): Delete this.
   public static Duration remainder(Duration d1, Duration d2) {
-    return createDurationFromBigInteger(
-      toBigInteger(d1).remainder(toBigInteger(d2)));
+    return createDurationFromBigInteger(toBigInteger(d1).remainder(toBigInteger(d2)));
   }
-  
+
   private static final BigInteger NANOS_PER_SECOND_BIG_INTEGER =
       new BigInteger(String.valueOf(NANOS_PER_SECOND));
-  
+
   private static BigInteger toBigInteger(Duration duration) {
     return toBigInteger(duration.getSeconds())
-      .multiply(NANOS_PER_SECOND_BIG_INTEGER)
-      .add(toBigInteger(duration.getNanos()));
+        .multiply(NANOS_PER_SECOND_BIG_INTEGER)
+        .add(toBigInteger(duration.getNanos()));
   }
-  
+
   private static BigInteger toBigInteger(long value) {
     return new BigInteger(String.valueOf(value));
   }
-  
+
   private static Duration createDurationFromBigInteger(BigInteger value) {
-    long seconds = value.divide(
-      new BigInteger(String.valueOf(NANOS_PER_SECOND))).longValue();
-    int nanos = value.remainder(
-      new BigInteger(String.valueOf(NANOS_PER_SECOND))).intValue();
+    long seconds = value.divide(new BigInteger(String.valueOf(NANOS_PER_SECOND))).longValue();
+    int nanos = value.remainder(new BigInteger(String.valueOf(NANOS_PER_SECOND))).intValue();
     return normalizedDuration(seconds, nanos);
-    
   }
 
   private static Duration normalizedDuration(long seconds, int nanos) {
@@ -492,58 +397,4 @@
     }
     return Duration.newBuilder().setSeconds(seconds).setNanos(nanos).build();
   }
-
-  private static Timestamp normalizedTimestamp(long seconds, int nanos) {
-    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
-      seconds += nanos / NANOS_PER_SECOND;
-      nanos %= NANOS_PER_SECOND;
-    }
-    if (nanos < 0) {
-      nanos += NANOS_PER_SECOND;
-      seconds -= 1;
-    }
-    if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
-      throw new IllegalArgumentException("Timestamp is out of valid range.");
-    }
-    return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
-  }
-
-  /**
-   * Format the nano part of a timestamp or a duration.
-   */
-  private static String formatNanos(int nanos) {
-    assert nanos >= 1 && nanos <= 999999999;
-    // Determine whether to use 3, 6, or 9 digits for the nano part.
-    if (nanos % NANOS_PER_MILLISECOND == 0) {
-      return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);
-    } else if (nanos % NANOS_PER_MICROSECOND == 0) {
-      return String.format("%1$06d", nanos / NANOS_PER_MICROSECOND);
-    } else {
-      return String.format("%1$09d", nanos);
-    }
-  }
-
-  private static int parseNanos(String value) throws ParseException {
-    int result = 0;
-    for (int i = 0; i < 9; ++i) {
-      result = result * 10;
-      if (i < value.length()) {
-        if (value.charAt(i) < '0' || value.charAt(i) > '9') {
-          throw new ParseException("Invalid nanosecnds.", 0);
-        }
-        result += value.charAt(i) - '0';
-      }
-    }
-    return result;
-  }
-
-  private static long parseTimezoneOffset(String value) throws ParseException {
-    int pos = value.indexOf(':');
-    if (pos == -1) {
-      throw new ParseException("Invalid offset value: " + value, 0);
-    }
-    String hours = value.substring(0, pos);
-    String minutes = value.substring(pos + 1);
-    return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
-  }
 }
diff --git a/java/util/src/main/java/com/google/protobuf/util/Timestamps.java b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
new file mode 100644
index 0000000..f1f202d
--- /dev/null
+++ b/java/util/src/main/java/com/google/protobuf/util/Timestamps.java
@@ -0,0 +1,349 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.util;
+
+import com.google.protobuf.Duration;
+import com.google.protobuf.Timestamp;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+
+/**
+ * Utilities to help create/manipulate {@code protobuf/timestamp.proto}.
+ */
+public final class Timestamps {
+  // Timestamp for "0001-01-01T00:00:00Z"
+  static final long TIMESTAMP_SECONDS_MIN = -62135596800L;
+
+  // Timestamp for "9999-12-31T23:59:59Z"
+  static final long TIMESTAMP_SECONDS_MAX = 253402300799L;
+
+  static final long NANOS_PER_SECOND = 1000000000;
+  static final long NANOS_PER_MILLISECOND = 1000000;
+  static final long NANOS_PER_MICROSECOND = 1000;
+  static final long MILLIS_PER_SECOND = 1000;
+  static final long MICROS_PER_SECOND = 1000000;
+
+  // TODO(kak): Do we want to expose Timestamp constants for MAX/MIN?
+
+  private static final ThreadLocal<SimpleDateFormat> timestampFormat =
+      new ThreadLocal<SimpleDateFormat>() {
+        protected SimpleDateFormat initialValue() {
+          return createTimestampFormat();
+        }
+      };
+
+  private static SimpleDateFormat createTimestampFormat() {
+    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+    GregorianCalendar calendar = new GregorianCalendar(TimeZone.getTimeZone("UTC"));
+    // We use Proleptic Gregorian Calendar (i.e., Gregorian calendar extends
+    // backwards to year one) for timestamp formating.
+    calendar.setGregorianChange(new Date(Long.MIN_VALUE));
+    sdf.setCalendar(calendar);
+    return sdf;
+  }
+
+  private Timestamps() {}
+
+  /**
+   * Returns true if the given {@link Timestamp} is valid. The {@code seconds} value must be in the
+   * range [-62,135,596,800, +253,402,300,799] (i.e., between 0001-01-01T00:00:00Z and
+   * 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range [0, +999,999,999].
+   *
+   * <p>Note: Negative second values with fractions must still have non-negative nanos value that
+   * counts forward in time.
+   */
+  public static boolean isValid(Timestamp timestamp) {
+    return isValid(timestamp.getSeconds(), timestamp.getNanos());
+  }
+
+  /**
+   * Returns true if the given number of seconds and nanos is a valid {@link Timestamp}. The
+   * {@code seconds} value must be in the range [-62,135,596,800, +253,402,300,799] (i.e., between
+   * 0001-01-01T00:00:00Z and 9999-12-31T23:59:59Z). The {@code nanos} value must be in the range
+   * [0, +999,999,999].
+   *
+   * <p>Note: Negative second values with fractions must still have non-negative nanos value that
+   * counts forward in time.
+   */
+  public static boolean isValid(long seconds, long nanos) {
+    if (seconds < TIMESTAMP_SECONDS_MIN || seconds > TIMESTAMP_SECONDS_MAX) {
+      return false;
+    }
+    if (nanos < 0 || nanos >= NANOS_PER_SECOND) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Throws an {@link IllegalArgumentException} if the given seconds/nanos are not
+   * a valid {@link Timestamp}.
+   */
+  private static void checkValid(long seconds, int nanos) {
+    if (!isValid(seconds, nanos)) {
+      throw new IllegalArgumentException(String.format(
+          "Timestamp is not valid. See proto definition for valid values. "
+          + "Seconds (%s) must be in range [-62,135,596,800, +253,402,300,799]."
+          + "Nanos (%s) must be in range [0, +999,999,999].",
+          seconds, nanos));
+    }
+  }
+
+  /**
+   * Convert Timestamp to RFC 3339 date string format. The output will always
+   * be Z-normalized and uses 3, 6 or 9 fractional digits as required to
+   * represent the exact value. Note that Timestamp can only represent time
+   * from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. See
+   * https://www.ietf.org/rfc/rfc3339.txt
+   *
+   * <p>Example of generated format: "1972-01-01T10:00:20.021Z"
+   *
+   * @return The string representation of the given timestamp.
+   * @throws IllegalArgumentException if the given timestamp is not in the
+   *         valid range.
+   */
+  public static String toString(Timestamp timestamp) {
+    long seconds = timestamp.getSeconds();
+    int nanos = timestamp.getNanos();
+    checkValid(seconds, nanos);
+    StringBuilder result = new StringBuilder();
+    // Format the seconds part.
+    Date date = new Date(seconds * MILLIS_PER_SECOND);
+    result.append(timestampFormat.get().format(date));
+    // Format the nanos part.
+    if (nanos != 0) {
+      result.append(".");
+      result.append(formatNanos(nanos));
+    }
+    result.append("Z");
+    return result.toString();
+  }
+
+  /**
+   * Parse from RFC 3339 date string to Timestamp. This method accepts all
+   * outputs of {@link #toString(Timestamp)} and it also accepts any fractional
+   * digits (or none) and any offset as long as they fit into nano-seconds
+   * precision.
+   *
+   * <p>Example of accepted format: "1972-01-01T10:00:20.021-05:00"
+   *
+   * @return A Timestamp parsed from the string.
+   * @throws ParseException if parsing fails.
+   */
+  public static Timestamp parse(String value) throws ParseException {
+    int dayOffset = value.indexOf('T');
+    if (dayOffset == -1) {
+      throw new ParseException("Failed to parse timestamp: invalid timestamp \"" + value + "\"", 0);
+    }
+    int timezoneOffsetPosition = value.indexOf('Z', dayOffset);
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('+', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      timezoneOffsetPosition = value.indexOf('-', dayOffset);
+    }
+    if (timezoneOffsetPosition == -1) {
+      throw new ParseException("Failed to parse timestamp: missing valid timezone offset.", 0);
+    }
+    // Parse seconds and nanos.
+    String timeValue = value.substring(0, timezoneOffsetPosition);
+    String secondValue = timeValue;
+    String nanoValue = "";
+    int pointPosition = timeValue.indexOf('.');
+    if (pointPosition != -1) {
+      secondValue = timeValue.substring(0, pointPosition);
+      nanoValue = timeValue.substring(pointPosition + 1);
+    }
+    Date date = timestampFormat.get().parse(secondValue);
+    long seconds = date.getTime() / MILLIS_PER_SECOND;
+    int nanos = nanoValue.isEmpty() ? 0 : parseNanos(nanoValue);
+    // Parse timezone offsets.
+    if (value.charAt(timezoneOffsetPosition) == 'Z') {
+      if (value.length() != timezoneOffsetPosition + 1) {
+        throw new ParseException(
+            "Failed to parse timestamp: invalid trailing data \""
+                + value.substring(timezoneOffsetPosition)
+                + "\"",
+            0);
+      }
+    } else {
+      String offsetValue = value.substring(timezoneOffsetPosition + 1);
+      long offset = parseTimezoneOffset(offsetValue);
+      if (value.charAt(timezoneOffsetPosition) == '+') {
+        seconds -= offset;
+      } else {
+        seconds += offset;
+      }
+    }
+    try {
+      return normalizedTimestamp(seconds, nanos);
+    } catch (IllegalArgumentException e) {
+      throw new ParseException("Failed to parse timestmap: timestamp is out of range.", 0);
+    }
+  }
+
+  /**
+   * Create a Timestamp from the number of milliseconds elapsed from the epoch.
+   */
+  public static Timestamp fromMillis(long milliseconds) {
+    return normalizedTimestamp(
+        milliseconds / MILLIS_PER_SECOND,
+        (int) (milliseconds % MILLIS_PER_SECOND * NANOS_PER_MILLISECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of milliseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest millisecond. E.g., if the
+   * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
+   * to -1 millisecond.
+   */
+  public static long toMillis(Timestamp timestamp) {
+    return timestamp.getSeconds() * MILLIS_PER_SECOND
+        + timestamp.getNanos() / NANOS_PER_MILLISECOND;
+  }
+
+  /**
+   * Create a Timestamp from the number of microseconds elapsed from the epoch.
+   */
+  public static Timestamp fromMicros(long microseconds) {
+    return normalizedTimestamp(
+        microseconds / MICROS_PER_SECOND,
+        (int) (microseconds % MICROS_PER_SECOND * NANOS_PER_MICROSECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of microseconds elapsed from the epoch.
+   *
+   * <p>The result will be rounded down to the nearest microsecond. E.g., if the
+   * timestamp represents "1969-12-31T23:59:59.999999999Z", it will be rounded
+   * to -1 millisecond.
+   */
+  public static long toMicros(Timestamp timestamp) {
+    return timestamp.getSeconds() * MICROS_PER_SECOND
+        + timestamp.getNanos() / NANOS_PER_MICROSECOND;
+  }
+
+  /**
+   * Create a Timestamp from the number of nanoseconds elapsed from the epoch.
+   */
+  public static Timestamp fromNanos(long nanoseconds) {
+    return normalizedTimestamp(
+        nanoseconds / NANOS_PER_SECOND, (int) (nanoseconds % NANOS_PER_SECOND));
+  }
+
+  /**
+   * Convert a Timestamp to the number of nanoseconds elapsed from the epoch.
+   */
+  public static long toNanos(Timestamp timestamp) {
+    return timestamp.getSeconds() * NANOS_PER_SECOND + timestamp.getNanos();
+  }
+
+  /**
+   * Calculate the difference between two timestamps.
+   */
+  public static Duration between(Timestamp from, Timestamp to) {
+    return Durations.normalizedDuration(
+        to.getSeconds() - from.getSeconds(), to.getNanos() - from.getNanos());
+  }
+
+  /**
+   * Add a duration to a timestamp.
+   */
+  public static Timestamp add(Timestamp start, Duration length) {
+    return normalizedTimestamp(
+        start.getSeconds() + length.getSeconds(), start.getNanos() + length.getNanos());
+  }
+
+  /**
+   * Subtract a duration from a timestamp.
+   */
+  public static Timestamp subtract(Timestamp start, Duration length) {
+    return normalizedTimestamp(
+        start.getSeconds() - length.getSeconds(), start.getNanos() - length.getNanos());
+  }
+
+  private static Timestamp normalizedTimestamp(long seconds, int nanos) {
+    if (nanos <= -NANOS_PER_SECOND || nanos >= NANOS_PER_SECOND) {
+      seconds += nanos / NANOS_PER_SECOND;
+      nanos %= NANOS_PER_SECOND;
+    }
+    if (nanos < 0) {
+      nanos += NANOS_PER_SECOND;
+      seconds -= 1;
+    }
+    checkValid(seconds, nanos);
+    return Timestamp.newBuilder().setSeconds(seconds).setNanos(nanos).build();
+  }
+
+  private static long parseTimezoneOffset(String value) throws ParseException {
+    int pos = value.indexOf(':');
+    if (pos == -1) {
+      throw new ParseException("Invalid offset value: " + value, 0);
+    }
+    String hours = value.substring(0, pos);
+    String minutes = value.substring(pos + 1);
+    return (Long.parseLong(hours) * 60 + Long.parseLong(minutes)) * 60;
+  }
+
+  static int parseNanos(String value) throws ParseException {
+    int result = 0;
+    for (int i = 0; i < 9; ++i) {
+      result = result * 10;
+      if (i < value.length()) {
+        if (value.charAt(i) < '0' || value.charAt(i) > '9') {
+          throw new ParseException("Invalid nanosecnds.", 0);
+        }
+        result += value.charAt(i) - '0';
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Format the nano part of a timestamp or a duration.
+   */
+  static String formatNanos(int nanos) {
+    assert nanos >= 1 && nanos <= 999999999;
+    // Determine whether to use 3, 6, or 9 digits for the nano part.
+    if (nanos % NANOS_PER_MILLISECOND == 0) {
+      return String.format("%1$03d", nanos / NANOS_PER_MILLISECOND);
+    } else if (nanos % NANOS_PER_MICROSECOND == 0) {
+      return String.format("%1$06d", nanos / NANOS_PER_MICROSECOND);
+    } else {
+      return String.format("%1$09d", nanos);
+    }
+  }
+}
diff --git a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
index 194f7b9..1a99857 100644
--- a/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/FieldMaskUtilTest.java
@@ -41,52 +41,55 @@
   public void testIsValid() throws Exception {
     assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload"));
     assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "nonexist"));
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_int32"));
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.repeated_int32"));
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_nested_message"));
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.repeated_nested_message"));
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.nonexist"));
-    
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")));
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")));
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")));
-    
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32"));
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_int32"));
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message"));
+    assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.nonexist"));
+
+    assertTrue(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("payload")));
+    assertFalse(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, FieldMaskUtil.fromString("nonexist")));
+    assertFalse(
+        FieldMaskUtil.isValid(
+            NestedTestAllTypes.class, FieldMaskUtil.fromString("payload,nonexist")));
+
     assertTrue(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "payload"));
     assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.getDescriptor(), "nonexist"));
-    
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
-    
-    assertTrue(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
+
+    assertTrue(
+        FieldMaskUtil.isValid(
+            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("payload")));
+    assertFalse(
+        FieldMaskUtil.isValid(
+            NestedTestAllTypes.getDescriptor(), FieldMaskUtil.fromString("nonexist")));
+
+    assertTrue(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_nested_message.bb"));
     // Repeated fields cannot have sub-paths.
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
+    assertFalse(
+        FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.repeated_nested_message.bb"));
     // Non-message fields cannot have sub-paths.
-    assertFalse(FieldMaskUtil.isValid(
-        NestedTestAllTypes.class, "payload.optional_int32.bb"));
+    assertFalse(FieldMaskUtil.isValid(NestedTestAllTypes.class, "payload.optional_int32.bb"));
   }
-  
+
   public void testToString() throws Exception {
     assertEquals("", FieldMaskUtil.toString(FieldMask.getDefaultInstance()));
     FieldMask mask = FieldMask.newBuilder().addPaths("foo").build();
     assertEquals("foo", FieldMaskUtil.toString(mask));
     mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar").build();
     assertEquals("foo,bar", FieldMaskUtil.toString(mask));
-    
+
     // Empty field paths are ignored.
-    mask = FieldMask.newBuilder().addPaths("").addPaths("foo").addPaths("").
-      addPaths("bar").addPaths("").build();
+    mask =
+        FieldMask.newBuilder()
+            .addPaths("")
+            .addPaths("foo")
+            .addPaths("")
+            .addPaths("bar")
+            .addPaths("")
+            .build();
     assertEquals("foo,bar", FieldMaskUtil.toString(mask));
   }
 
@@ -111,8 +114,7 @@
     mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, ",payload");
 
     try {
-      mask = FieldMaskUtil.fromString(
-          NestedTestAllTypes.class, "payload,nonexist");
+      mask = FieldMaskUtil.fromString(NestedTestAllTypes.class, "payload,nonexist");
       fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
       // Expected.
@@ -143,7 +145,33 @@
     } catch (IllegalArgumentException expected) {
     }
   }
-  
+
+  public void testToJsonString() throws Exception {
+    FieldMask mask = FieldMask.getDefaultInstance();
+    assertEquals("", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo").build();
+    assertEquals("foo", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo.bar_baz").addPaths("").build();
+    assertEquals("foo.barBaz", FieldMaskUtil.toJsonString(mask));
+    mask = FieldMask.newBuilder().addPaths("foo").addPaths("bar_baz").build();
+    assertEquals("foo,barBaz", FieldMaskUtil.toJsonString(mask));
+  }
+
+  public void testFromJsonString() throws Exception {
+    FieldMask mask = FieldMaskUtil.fromJsonString("");
+    assertEquals(0, mask.getPathsCount());
+    mask = FieldMaskUtil.fromJsonString("foo");
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    mask = FieldMaskUtil.fromJsonString("foo.barBaz");
+    assertEquals(1, mask.getPathsCount());
+    assertEquals("foo.bar_baz", mask.getPaths(0));
+    mask = FieldMaskUtil.fromJsonString("foo,barBaz");
+    assertEquals(2, mask.getPathsCount());
+    assertEquals("foo", mask.getPaths(0));
+    assertEquals("bar_baz", mask.getPaths(1));
+  }
+
   public void testUnion() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testAddFieldPath} to cover all scenarios.
@@ -161,7 +189,7 @@
     FieldMask result = FieldMaskUtil.union(mask1, mask2, mask3, mask4);
     assertEquals("bar,foo", FieldMaskUtil.toString(result));
   }
-  
+
   public void testIntersection() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testIntersectFieldPath} to cover all scenarios.
@@ -170,13 +198,14 @@
     FieldMask result = FieldMaskUtil.intersection(mask1, mask2);
     assertEquals("bar.baz,bar.quz,foo.bar", FieldMaskUtil.toString(result));
   }
-  
+
   public void testMerge() throws Exception {
     // Only test a simple case here and expect
     // {@link FieldMaskTreeTest#testMerge} to cover all scenarios.
-    NestedTestAllTypes source = NestedTestAllTypes.newBuilder()
-        .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
-        .build();
+    NestedTestAllTypes source =
+        NestedTestAllTypes.newBuilder()
+            .setPayload(TestAllTypes.newBuilder().setOptionalInt32(1234))
+            .build();
     NestedTestAllTypes.Builder builder = NestedTestAllTypes.newBuilder();
     FieldMaskUtil.merge(FieldMaskUtil.fromString("payload"), source, builder);
     assertEquals(1234, builder.getPayload().getOptionalInt32());
diff --git a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
index d95b626..4d9a417 100644
--- a/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/JsonFormatTest.java
@@ -41,6 +41,7 @@
 import com.google.protobuf.InvalidProtocolBufferException;
 import com.google.protobuf.ListValue;
 import com.google.protobuf.Message;
+import com.google.protobuf.NullValue;
 import com.google.protobuf.StringValue;
 import com.google.protobuf.Struct;
 import com.google.protobuf.UInt32Value;
@@ -82,7 +83,7 @@
     builder.setOptionalDouble(1.25);
     builder.setOptionalBool(true);
     builder.setOptionalString("Hello world!");
-    builder.setOptionalBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.setOptionalBytes(ByteString.copyFrom(new byte[] {0, 1, 2}));
     builder.setOptionalNestedEnum(NestedEnum.BAR);
     builder.getOptionalNestedMessageBuilder().setValue(100);
 
@@ -100,7 +101,7 @@
     builder.addRepeatedDouble(1.25);
     builder.addRepeatedBool(true);
     builder.addRepeatedString("Hello world!");
-    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{0, 1, 2}));
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {0, 1, 2}));
     builder.addRepeatedNestedEnum(NestedEnum.BAR);
     builder.addRepeatedNestedMessageBuilder().setValue(100);
 
@@ -118,7 +119,7 @@
     builder.addRepeatedDouble(11.25);
     builder.addRepeatedBool(true);
     builder.addRepeatedString("ello world!");
-    builder.addRepeatedBytes(ByteString.copyFrom(new byte[]{1, 2}));
+    builder.addRepeatedBytes(ByteString.copyFrom(new byte[] {1, 2}));
     builder.addRepeatedNestedEnum(NestedEnum.BAZ);
     builder.addRepeatedNestedMessageBuilder().setValue(200);
   }
@@ -198,20 +199,22 @@
   }
 
   public void testUnknownEnumValues() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        .setOptionalNestedEnumValue(12345)
-        .addRepeatedNestedEnumValue(12345)
-        .addRepeatedNestedEnumValue(0)
-        .build();
+    TestAllTypes message =
+        TestAllTypes.newBuilder()
+            .setOptionalNestedEnumValue(12345)
+            .addRepeatedNestedEnumValue(12345)
+            .addRepeatedNestedEnumValue(0)
+            .build();
     assertEquals(
         "{\n"
-        + "  \"optionalNestedEnum\": 12345,\n"
-        + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
-        + "}", toJsonString(message));
+            + "  \"optionalNestedEnum\": 12345,\n"
+            + "  \"repeatedNestedEnum\": [12345, \"FOO\"]\n"
+            + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
 
     TestMap.Builder mapBuilder = TestMap.newBuilder();
-    mapBuilder.getMutableInt32ToEnumMapValue().put(1, 0);
+    mapBuilder.putInt32ToEnumMapValue(1, 0);
     mapBuilder.getMutableInt32ToEnumMapValue().put(2, 12345);
     TestMap mapMessage = mapBuilder.build();
     assertEquals(
@@ -226,19 +229,21 @@
   }
 
   public void testSpecialFloatValues() throws Exception {
-    TestAllTypes message = TestAllTypes.newBuilder()
-        .addRepeatedFloat(Float.NaN)
-        .addRepeatedFloat(Float.POSITIVE_INFINITY)
-        .addRepeatedFloat(Float.NEGATIVE_INFINITY)
-        .addRepeatedDouble(Double.NaN)
-        .addRepeatedDouble(Double.POSITIVE_INFINITY)
-        .addRepeatedDouble(Double.NEGATIVE_INFINITY)
-        .build();
+    TestAllTypes message =
+        TestAllTypes.newBuilder()
+            .addRepeatedFloat(Float.NaN)
+            .addRepeatedFloat(Float.POSITIVE_INFINITY)
+            .addRepeatedFloat(Float.NEGATIVE_INFINITY)
+            .addRepeatedDouble(Double.NaN)
+            .addRepeatedDouble(Double.POSITIVE_INFINITY)
+            .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+            .build();
     assertEquals(
         "{\n"
-        + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
-        + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
-        + "}", toJsonString(message));
+            + "  \"repeatedFloat\": [\"NaN\", \"Infinity\", \"-Infinity\"],\n"
+            + "  \"repeatedDouble\": [\"NaN\", \"Infinity\", \"-Infinity\"]\n"
+            + "}",
+        toJsonString(message));
 
     assertRoundTripEquals(message);
   }
@@ -247,15 +252,16 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
         "{\n"
-        + "  \"optionalInt32\": \"1234\",\n"
-        + "  \"optionalUint32\": \"5678\",\n"
-        + "  \"optionalSint32\": \"9012\",\n"
-        + "  \"optionalFixed32\": \"3456\",\n"
-        + "  \"optionalSfixed32\": \"7890\",\n"
-        + "  \"optionalFloat\": \"1.5\",\n"
-        + "  \"optionalDouble\": \"1.25\",\n"
-        + "  \"optionalBool\": \"true\"\n"
-        + "}", builder);
+            + "  \"optionalInt32\": \"1234\",\n"
+            + "  \"optionalUint32\": \"5678\",\n"
+            + "  \"optionalSint32\": \"9012\",\n"
+            + "  \"optionalFixed32\": \"3456\",\n"
+            + "  \"optionalSfixed32\": \"7890\",\n"
+            + "  \"optionalFloat\": \"1.5\",\n"
+            + "  \"optionalDouble\": \"1.25\",\n"
+            + "  \"optionalBool\": \"true\"\n"
+            + "}",
+        builder);
     TestAllTypes message = builder.build();
     assertEquals(1234, message.getOptionalInt32());
     assertEquals(5678, message.getOptionalUint32());
@@ -276,8 +282,9 @@
             + "  \"repeatedUint32\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
             + "  \"repeatedInt64\": [1.000, 1e5, \"1.000\", \"1e5\"],\n"
             + "  \"repeatedUint64\": [1.000, 1e5, \"1.000\", \"1e5\"]\n"
-            + "}", builder);
-    int[] expectedValues = new int[]{1, 100000, 1, 100000};
+            + "}",
+        builder);
+    int[] expectedValues = new int[] {1, 100000, 1, 100000};
     assertEquals(4, builder.getRepeatedInt32Count());
     assertEquals(4, builder.getRepeatedUint32Count());
     assertEquals(4, builder.getRepeatedInt64Count());
@@ -366,51 +373,49 @@
     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
     mergeFromJson(
         "{\n"
-        + "  \"optionalInt32\": null,\n"
-        + "  \"optionalInt64\": null,\n"
-        + "  \"optionalUint32\": null,\n"
-        + "  \"optionalUint64\": null,\n"
-        + "  \"optionalSint32\": null,\n"
-        + "  \"optionalSint64\": null,\n"
-        + "  \"optionalFixed32\": null,\n"
-        + "  \"optionalFixed64\": null,\n"
-        + "  \"optionalSfixed32\": null,\n"
-        + "  \"optionalSfixed64\": null,\n"
-        + "  \"optionalFloat\": null,\n"
-        + "  \"optionalDouble\": null,\n"
-        + "  \"optionalBool\": null,\n"
-        + "  \"optionalString\": null,\n"
-        + "  \"optionalBytes\": null,\n"
-        + "  \"optionalNestedMessage\": null,\n"
-        + "  \"optionalNestedEnum\": null,\n"
-        + "  \"repeatedInt32\": null,\n"
-        + "  \"repeatedInt64\": null,\n"
-        + "  \"repeatedUint32\": null,\n"
-        + "  \"repeatedUint64\": null,\n"
-        + "  \"repeatedSint32\": null,\n"
-        + "  \"repeatedSint64\": null,\n"
-        + "  \"repeatedFixed32\": null,\n"
-        + "  \"repeatedFixed64\": null,\n"
-        + "  \"repeatedSfixed32\": null,\n"
-        + "  \"repeatedSfixed64\": null,\n"
-        + "  \"repeatedFloat\": null,\n"
-        + "  \"repeatedDouble\": null,\n"
-        + "  \"repeatedBool\": null,\n"
-        + "  \"repeatedString\": null,\n"
-        + "  \"repeatedBytes\": null,\n"
-        + "  \"repeatedNestedMessage\": null,\n"
-        + "  \"repeatedNestedEnum\": null\n"
-        + "}", builder);
+            + "  \"optionalInt32\": null,\n"
+            + "  \"optionalInt64\": null,\n"
+            + "  \"optionalUint32\": null,\n"
+            + "  \"optionalUint64\": null,\n"
+            + "  \"optionalSint32\": null,\n"
+            + "  \"optionalSint64\": null,\n"
+            + "  \"optionalFixed32\": null,\n"
+            + "  \"optionalFixed64\": null,\n"
+            + "  \"optionalSfixed32\": null,\n"
+            + "  \"optionalSfixed64\": null,\n"
+            + "  \"optionalFloat\": null,\n"
+            + "  \"optionalDouble\": null,\n"
+            + "  \"optionalBool\": null,\n"
+            + "  \"optionalString\": null,\n"
+            + "  \"optionalBytes\": null,\n"
+            + "  \"optionalNestedMessage\": null,\n"
+            + "  \"optionalNestedEnum\": null,\n"
+            + "  \"repeatedInt32\": null,\n"
+            + "  \"repeatedInt64\": null,\n"
+            + "  \"repeatedUint32\": null,\n"
+            + "  \"repeatedUint64\": null,\n"
+            + "  \"repeatedSint32\": null,\n"
+            + "  \"repeatedSint64\": null,\n"
+            + "  \"repeatedFixed32\": null,\n"
+            + "  \"repeatedFixed64\": null,\n"
+            + "  \"repeatedSfixed32\": null,\n"
+            + "  \"repeatedSfixed64\": null,\n"
+            + "  \"repeatedFloat\": null,\n"
+            + "  \"repeatedDouble\": null,\n"
+            + "  \"repeatedBool\": null,\n"
+            + "  \"repeatedString\": null,\n"
+            + "  \"repeatedBytes\": null,\n"
+            + "  \"repeatedNestedMessage\": null,\n"
+            + "  \"repeatedNestedEnum\": null\n"
+            + "}",
+        builder);
     TestAllTypes message = builder.build();
     assertEquals(TestAllTypes.getDefaultInstance(), message);
 
     // Repeated field elements cannot be null.
     try {
       builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"repeatedInt32\": [null, null],\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"repeatedInt32\": [null, null],\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -418,16 +423,21 @@
 
     try {
       builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"repeatedNestedMessage\": [null, null],\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"repeatedNestedMessage\": [null, null],\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
     }
   }
 
+  public void testNullInOneof() throws Exception {
+    TestOneof.Builder builder = TestOneof.newBuilder();
+    mergeFromJson("{\n" + "  \"oneofNullValue\": null \n" + "}", builder);
+    TestOneof message = builder.build();
+    assertEquals(TestOneof.OneofFieldCase.ONEOF_NULL_VALUE, message.getOneofFieldCase());
+    assertEquals(NullValue.NULL_VALUE, message.getOneofNullValue());
+  }
+
   public void testParserRejectDuplicatedFields() throws Exception {
     // TODO(xiaofeng): The parser we are currently using (GSON) will accept and keep the last
     // one if multiple entries have the same name. This is not the desired behavior but it can
@@ -441,7 +451,8 @@
           "{\n"
               + "  \"optionalNestedMessage\": {},\n"
               + "  \"optional_nested_message\": {}\n"
-          + "}", builder);
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -452,9 +463,10 @@
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"repeatedNestedMessage\": [null, null],\n"
-          + "  \"repeated_nested_message\": [null, null]\n"
-          + "}", builder);
+              + "  \"repeatedNestedMessage\": [null, null],\n"
+              + "  \"repeated_nested_message\": [null, null]\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -463,11 +475,7 @@
     // Duplicated oneof fields.
     try {
       TestOneof.Builder builder = TestOneof.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"oneofInt32\": 1,\n"
-          + "  \"oneof_int32\": 2\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"oneofInt32\": 1,\n" + "  \"oneof_int32\": 2\n" + "}", builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -476,143 +484,138 @@
 
   public void testMapFields() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Map().put(1, 10);
-    builder.getMutableInt64ToInt32Map().put(1234567890123456789L, 10);
-    builder.getMutableUint32ToInt32Map().put(2, 20);
-    builder.getMutableUint64ToInt32Map().put(2234567890123456789L, 20);
-    builder.getMutableSint32ToInt32Map().put(3, 30);
-    builder.getMutableSint64ToInt32Map().put(3234567890123456789L, 30);
-    builder.getMutableFixed32ToInt32Map().put(4, 40);
-    builder.getMutableFixed64ToInt32Map().put(4234567890123456789L, 40);
-    builder.getMutableSfixed32ToInt32Map().put(5, 50);
-    builder.getMutableSfixed64ToInt32Map().put(5234567890123456789L, 50);
-    builder.getMutableBoolToInt32Map().put(false, 6);
-    builder.getMutableStringToInt32Map().put("Hello", 10);
+    builder.putInt32ToInt32Map(1, 10);
+    builder.putInt64ToInt32Map(1234567890123456789L, 10);
+    builder.putUint32ToInt32Map(2, 20);
+    builder.putUint64ToInt32Map(2234567890123456789L, 20);
+    builder.putSint32ToInt32Map(3, 30);
+    builder.putSint64ToInt32Map(3234567890123456789L, 30);
+    builder.putFixed32ToInt32Map(4, 40);
+    builder.putFixed64ToInt32Map(4234567890123456789L, 40);
+    builder.putSfixed32ToInt32Map(5, 50);
+    builder.putSfixed64ToInt32Map(5234567890123456789L, 50);
+    builder.putBoolToInt32Map(false, 6);
+    builder.putStringToInt32Map("Hello", 10);
 
-    builder.getMutableInt32ToInt64Map().put(1, 1234567890123456789L);
-    builder.getMutableInt32ToUint32Map().put(2, 20);
-    builder.getMutableInt32ToUint64Map().put(2, 2234567890123456789L);
-    builder.getMutableInt32ToSint32Map().put(3, 30);
-    builder.getMutableInt32ToSint64Map().put(3, 3234567890123456789L);
-    builder.getMutableInt32ToFixed32Map().put(4, 40);
-    builder.getMutableInt32ToFixed64Map().put(4, 4234567890123456789L);
-    builder.getMutableInt32ToSfixed32Map().put(5, 50);
-    builder.getMutableInt32ToSfixed64Map().put(5, 5234567890123456789L);
-    builder.getMutableInt32ToFloatMap().put(6, 1.5f);
-    builder.getMutableInt32ToDoubleMap().put(6, 1.25);
-    builder.getMutableInt32ToBoolMap().put(7, false);
-    builder.getMutableInt32ToStringMap().put(7, "World");
-    builder.getMutableInt32ToBytesMap().put(
-        8, ByteString.copyFrom(new byte[]{1, 2, 3}));
-    builder.getMutableInt32ToMessageMap().put(
-        8, NestedMessage.newBuilder().setValue(1234).build());
-    builder.getMutableInt32ToEnumMap().put(9, NestedEnum.BAR);
+    builder.putInt32ToInt64Map(1, 1234567890123456789L);
+    builder.putInt32ToUint32Map(2, 20);
+    builder.putInt32ToUint64Map(2, 2234567890123456789L);
+    builder.putInt32ToSint32Map(3, 30);
+    builder.putInt32ToSint64Map(3, 3234567890123456789L);
+    builder.putInt32ToFixed32Map(4, 40);
+    builder.putInt32ToFixed64Map(4, 4234567890123456789L);
+    builder.putInt32ToSfixed32Map(5, 50);
+    builder.putInt32ToSfixed64Map(5, 5234567890123456789L);
+    builder.putInt32ToFloatMap(6, 1.5f);
+    builder.putInt32ToDoubleMap(6, 1.25);
+    builder.putInt32ToBoolMap(7, false);
+    builder.putInt32ToStringMap(7, "World");
+    builder.putInt32ToBytesMap(8, ByteString.copyFrom(new byte[] {1, 2, 3}));
+    builder.putInt32ToMessageMap(8, NestedMessage.newBuilder().setValue(1234).build());
+    builder.putInt32ToEnumMap(9, NestedEnum.BAR);
     TestMap message = builder.build();
 
     assertEquals(
         "{\n"
-        + "  \"int32ToInt32Map\": {\n"
-        + "    \"1\": 10\n"
-        + "  },\n"
-        + "  \"int64ToInt32Map\": {\n"
-        + "    \"1234567890123456789\": 10\n"
-        + "  },\n"
-        + "  \"uint32ToInt32Map\": {\n"
-        + "    \"2\": 20\n"
-        + "  },\n"
-        + "  \"uint64ToInt32Map\": {\n"
-        + "    \"2234567890123456789\": 20\n"
-        + "  },\n"
-        + "  \"sint32ToInt32Map\": {\n"
-        + "    \"3\": 30\n"
-        + "  },\n"
-        + "  \"sint64ToInt32Map\": {\n"
-        + "    \"3234567890123456789\": 30\n"
-        + "  },\n"
-        + "  \"fixed32ToInt32Map\": {\n"
-        + "    \"4\": 40\n"
-        + "  },\n"
-        + "  \"fixed64ToInt32Map\": {\n"
-        + "    \"4234567890123456789\": 40\n"
-        + "  },\n"
-        + "  \"sfixed32ToInt32Map\": {\n"
-        + "    \"5\": 50\n"
-        + "  },\n"
-        + "  \"sfixed64ToInt32Map\": {\n"
-        + "    \"5234567890123456789\": 50\n"
-        + "  },\n"
-        + "  \"boolToInt32Map\": {\n"
-        + "    \"false\": 6\n"
-        + "  },\n"
-        + "  \"stringToInt32Map\": {\n"
-        + "    \"Hello\": 10\n"
-        + "  },\n"
-        + "  \"int32ToInt64Map\": {\n"
-        + "    \"1\": \"1234567890123456789\"\n"
-        + "  },\n"
-        + "  \"int32ToUint32Map\": {\n"
-        + "    \"2\": 20\n"
-        + "  },\n"
-        + "  \"int32ToUint64Map\": {\n"
-        + "    \"2\": \"2234567890123456789\"\n"
-        + "  },\n"
-        + "  \"int32ToSint32Map\": {\n"
-        + "    \"3\": 30\n"
-        + "  },\n"
-        + "  \"int32ToSint64Map\": {\n"
-        + "    \"3\": \"3234567890123456789\"\n"
-        + "  },\n"
-        + "  \"int32ToFixed32Map\": {\n"
-        + "    \"4\": 40\n"
-        + "  },\n"
-        + "  \"int32ToFixed64Map\": {\n"
-        + "    \"4\": \"4234567890123456789\"\n"
-        + "  },\n"
-        + "  \"int32ToSfixed32Map\": {\n"
-        + "    \"5\": 50\n"
-        + "  },\n"
-        + "  \"int32ToSfixed64Map\": {\n"
-        + "    \"5\": \"5234567890123456789\"\n"
-        + "  },\n"
-        + "  \"int32ToFloatMap\": {\n"
-        + "    \"6\": 1.5\n"
-        + "  },\n"
-        + "  \"int32ToDoubleMap\": {\n"
-        + "    \"6\": 1.25\n"
-        + "  },\n"
-        + "  \"int32ToBoolMap\": {\n"
-        + "    \"7\": false\n"
-        + "  },\n"
-        + "  \"int32ToStringMap\": {\n"
-        + "    \"7\": \"World\"\n"
-        + "  },\n"
-        + "  \"int32ToBytesMap\": {\n"
-        + "    \"8\": \"AQID\"\n"
-        + "  },\n"
-        + "  \"int32ToMessageMap\": {\n"
-        + "    \"8\": {\n"
-        + "      \"value\": 1234\n"
-        + "    }\n"
-        + "  },\n"
-        + "  \"int32ToEnumMap\": {\n"
-        + "    \"9\": \"BAR\"\n"
-        + "  }\n"
-        + "}", toJsonString(message));
+            + "  \"int32ToInt32Map\": {\n"
+            + "    \"1\": 10\n"
+            + "  },\n"
+            + "  \"int64ToInt32Map\": {\n"
+            + "    \"1234567890123456789\": 10\n"
+            + "  },\n"
+            + "  \"uint32ToInt32Map\": {\n"
+            + "    \"2\": 20\n"
+            + "  },\n"
+            + "  \"uint64ToInt32Map\": {\n"
+            + "    \"2234567890123456789\": 20\n"
+            + "  },\n"
+            + "  \"sint32ToInt32Map\": {\n"
+            + "    \"3\": 30\n"
+            + "  },\n"
+            + "  \"sint64ToInt32Map\": {\n"
+            + "    \"3234567890123456789\": 30\n"
+            + "  },\n"
+            + "  \"fixed32ToInt32Map\": {\n"
+            + "    \"4\": 40\n"
+            + "  },\n"
+            + "  \"fixed64ToInt32Map\": {\n"
+            + "    \"4234567890123456789\": 40\n"
+            + "  },\n"
+            + "  \"sfixed32ToInt32Map\": {\n"
+            + "    \"5\": 50\n"
+            + "  },\n"
+            + "  \"sfixed64ToInt32Map\": {\n"
+            + "    \"5234567890123456789\": 50\n"
+            + "  },\n"
+            + "  \"boolToInt32Map\": {\n"
+            + "    \"false\": 6\n"
+            + "  },\n"
+            + "  \"stringToInt32Map\": {\n"
+            + "    \"Hello\": 10\n"
+            + "  },\n"
+            + "  \"int32ToInt64Map\": {\n"
+            + "    \"1\": \"1234567890123456789\"\n"
+            + "  },\n"
+            + "  \"int32ToUint32Map\": {\n"
+            + "    \"2\": 20\n"
+            + "  },\n"
+            + "  \"int32ToUint64Map\": {\n"
+            + "    \"2\": \"2234567890123456789\"\n"
+            + "  },\n"
+            + "  \"int32ToSint32Map\": {\n"
+            + "    \"3\": 30\n"
+            + "  },\n"
+            + "  \"int32ToSint64Map\": {\n"
+            + "    \"3\": \"3234567890123456789\"\n"
+            + "  },\n"
+            + "  \"int32ToFixed32Map\": {\n"
+            + "    \"4\": 40\n"
+            + "  },\n"
+            + "  \"int32ToFixed64Map\": {\n"
+            + "    \"4\": \"4234567890123456789\"\n"
+            + "  },\n"
+            + "  \"int32ToSfixed32Map\": {\n"
+            + "    \"5\": 50\n"
+            + "  },\n"
+            + "  \"int32ToSfixed64Map\": {\n"
+            + "    \"5\": \"5234567890123456789\"\n"
+            + "  },\n"
+            + "  \"int32ToFloatMap\": {\n"
+            + "    \"6\": 1.5\n"
+            + "  },\n"
+            + "  \"int32ToDoubleMap\": {\n"
+            + "    \"6\": 1.25\n"
+            + "  },\n"
+            + "  \"int32ToBoolMap\": {\n"
+            + "    \"7\": false\n"
+            + "  },\n"
+            + "  \"int32ToStringMap\": {\n"
+            + "    \"7\": \"World\"\n"
+            + "  },\n"
+            + "  \"int32ToBytesMap\": {\n"
+            + "    \"8\": \"AQID\"\n"
+            + "  },\n"
+            + "  \"int32ToMessageMap\": {\n"
+            + "    \"8\": {\n"
+            + "      \"value\": 1234\n"
+            + "    }\n"
+            + "  },\n"
+            + "  \"int32ToEnumMap\": {\n"
+            + "    \"9\": \"BAR\"\n"
+            + "  }\n"
+            + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
 
     // Test multiple entries.
     builder = TestMap.newBuilder();
-    builder.getMutableInt32ToInt32Map().put(1, 2);
-    builder.getMutableInt32ToInt32Map().put(3, 4);
+    builder.putInt32ToInt32Map(1, 2);
+    builder.putInt32ToInt32Map(3, 4);
     message = builder.build();
 
     assertEquals(
-        "{\n"
-        + "  \"int32ToInt32Map\": {\n"
-        + "    \"1\": 2,\n"
-        + "    \"3\": 4\n"
-        + "  }\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"int32ToInt32Map\": {\n" + "    \"1\": 2,\n" + "    \"3\": 4\n" + "  }\n" + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
   }
 
@@ -621,9 +624,10 @@
       TestMap.Builder builder = TestMap.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"int32ToInt32Map\": {null: 1},\n"
-          + "  \"int32ToMessageMap\": {null: 2}\n"
-          + "}", builder);
+              + "  \"int32ToInt32Map\": {null: 1},\n"
+              + "  \"int32ToMessageMap\": {null: 2}\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -633,9 +637,10 @@
       TestMap.Builder builder = TestMap.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"int32ToInt32Map\": {\"1\": null},\n"
-          + "  \"int32ToMessageMap\": {\"2\": null}\n"
-          + "}", builder);
+              + "  \"int32ToInt32Map\": {\"1\": null},\n"
+              + "  \"int32ToMessageMap\": {\"2\": null}\n"
+              + "}",
+          builder);
       fail();
     } catch (InvalidProtocolBufferException e) {
       // Exception expected.
@@ -645,10 +650,7 @@
   public void testParserAcceptNonQuotedObjectKey() throws Exception {
     TestMap.Builder builder = TestMap.newBuilder();
     mergeFromJson(
-        "{\n"
-        + "  int32ToInt32Map: {1: 2},\n"
-        + "  stringToInt32Map: {hello: 3}\n"
-        + "}", builder);
+        "{\n" + "  int32ToInt32Map: {1: 2},\n" + "  stringToInt32Map: {hello: 3}\n" + "}", builder);
     TestMap message = builder.build();
     assertEquals(2, message.getInt32ToInt32Map().get(1).intValue());
     assertEquals(3, message.getStringToInt32Map().get("hello").intValue());
@@ -669,16 +671,17 @@
 
     assertEquals(
         "{\n"
-        + "  \"int32Value\": 0,\n"
-        + "  \"uint32Value\": 0,\n"
-        + "  \"int64Value\": \"0\",\n"
-        + "  \"uint64Value\": \"0\",\n"
-        + "  \"floatValue\": 0.0,\n"
-        + "  \"doubleValue\": 0.0,\n"
-        + "  \"boolValue\": false,\n"
-        + "  \"stringValue\": \"\",\n"
-        + "  \"bytesValue\": \"\"\n"
-        + "}", toJsonString(message));
+            + "  \"int32Value\": 0,\n"
+            + "  \"uint32Value\": 0,\n"
+            + "  \"int64Value\": \"0\",\n"
+            + "  \"uint64Value\": \"0\",\n"
+            + "  \"floatValue\": 0.0,\n"
+            + "  \"doubleValue\": 0.0,\n"
+            + "  \"boolValue\": false,\n"
+            + "  \"stringValue\": \"\",\n"
+            + "  \"bytesValue\": \"\"\n"
+            + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
 
     builder = TestWrappers.newBuilder();
@@ -690,57 +693,52 @@
     builder.getFloatValueBuilder().setValue(5.0f);
     builder.getDoubleValueBuilder().setValue(6.0);
     builder.getStringValueBuilder().setValue("7");
-    builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[]{8}));
+    builder.getBytesValueBuilder().setValue(ByteString.copyFrom(new byte[] {8}));
     message = builder.build();
 
     assertEquals(
         "{\n"
-        + "  \"int32Value\": 1,\n"
-        + "  \"uint32Value\": 3,\n"
-        + "  \"int64Value\": \"2\",\n"
-        + "  \"uint64Value\": \"4\",\n"
-        + "  \"floatValue\": 5.0,\n"
-        + "  \"doubleValue\": 6.0,\n"
-        + "  \"boolValue\": true,\n"
-        + "  \"stringValue\": \"7\",\n"
-        + "  \"bytesValue\": \"CA==\"\n"
-        + "}", toJsonString(message));
+            + "  \"int32Value\": 1,\n"
+            + "  \"uint32Value\": 3,\n"
+            + "  \"int64Value\": \"2\",\n"
+            + "  \"uint64Value\": \"4\",\n"
+            + "  \"floatValue\": 5.0,\n"
+            + "  \"doubleValue\": 6.0,\n"
+            + "  \"boolValue\": true,\n"
+            + "  \"stringValue\": \"7\",\n"
+            + "  \"bytesValue\": \"CA==\"\n"
+            + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
   }
 
   public void testTimestamp() throws Exception {
-    TestTimestamp message = TestTimestamp.newBuilder()
-        .setTimestampValue(TimeUtil.parseTimestamp("1970-01-01T00:00:00Z"))
-        .build();
+    TestTimestamp message =
+        TestTimestamp.newBuilder()
+            .setTimestampValue(Timestamps.parse("1970-01-01T00:00:00Z"))
+            .build();
 
     assertEquals(
-        "{\n"
-        + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"timestampValue\": \"1970-01-01T00:00:00Z\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
 
   public void testDuration() throws Exception {
-    TestDuration message = TestDuration.newBuilder()
-        .setDurationValue(TimeUtil.parseDuration("12345s"))
-        .build();
+    TestDuration message =
+        TestDuration.newBuilder().setDurationValue(Durations.parse("12345s")).build();
 
-    assertEquals(
-        "{\n"
-        + "  \"durationValue\": \"12345s\"\n"
-        + "}", toJsonString(message));
+    assertEquals("{\n" + "  \"durationValue\": \"12345s\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
 
   public void testFieldMask() throws Exception {
-    TestFieldMask message = TestFieldMask.newBuilder()
-        .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz"))
-        .build();
+    TestFieldMask message =
+        TestFieldMask.newBuilder()
+            .setFieldMaskValue(FieldMaskUtil.fromString("foo.bar,baz,foo_bar.baz"))
+            .build();
 
     assertEquals(
-        "{\n"
-        + "  \"fieldMaskValue\": \"foo.bar,baz\"\n"
-        + "}", toJsonString(message));
+        "{\n" + "  \"fieldMaskValue\": \"foo.bar,baz,fooBar.baz\"\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
 
@@ -748,45 +746,39 @@
     // Build a struct with all possible values.
     TestStruct.Builder builder = TestStruct.newBuilder();
     Struct.Builder structBuilder = builder.getStructValueBuilder();
-    structBuilder.getMutableFields().put(
-        "null_value", Value.newBuilder().setNullValueValue(0).build());
-    structBuilder.getMutableFields().put(
-        "number_value", Value.newBuilder().setNumberValue(1.25).build());
-    structBuilder.getMutableFields().put(
-        "string_value", Value.newBuilder().setStringValue("hello").build());
+    structBuilder.putFields("null_value", Value.newBuilder().setNullValueValue(0).build());
+    structBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1.25).build());
+    structBuilder.putFields("string_value", Value.newBuilder().setStringValue("hello").build());
     Struct.Builder subStructBuilder = Struct.newBuilder();
-    subStructBuilder.getMutableFields().put(
-        "number_value", Value.newBuilder().setNumberValue(1234).build());
-    structBuilder.getMutableFields().put(
+    subStructBuilder.putFields("number_value", Value.newBuilder().setNumberValue(1234).build());
+    structBuilder.putFields(
         "struct_value", Value.newBuilder().setStructValue(subStructBuilder.build()).build());
     ListValue.Builder listBuilder = ListValue.newBuilder();
     listBuilder.addValues(Value.newBuilder().setNumberValue(1.125).build());
     listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
-    structBuilder.getMutableFields().put(
+    structBuilder.putFields(
         "list_value", Value.newBuilder().setListValue(listBuilder.build()).build());
     TestStruct message = builder.build();
 
     assertEquals(
         "{\n"
-        + "  \"structValue\": {\n"
-        + "    \"null_value\": null,\n"
-        + "    \"number_value\": 1.25,\n"
-        + "    \"string_value\": \"hello\",\n"
-        + "    \"struct_value\": {\n"
-        + "      \"number_value\": 1234.0\n"
-        + "    },\n"
-        + "    \"list_value\": [1.125, null]\n"
-        + "  }\n"
-        + "}", toJsonString(message));
+            + "  \"structValue\": {\n"
+            + "    \"null_value\": null,\n"
+            + "    \"number_value\": 1.25,\n"
+            + "    \"string_value\": \"hello\",\n"
+            + "    \"struct_value\": {\n"
+            + "      \"number_value\": 1234.0\n"
+            + "    },\n"
+            + "    \"list_value\": [1.125, null]\n"
+            + "  }\n"
+            + "}",
+        toJsonString(message));
     assertRoundTripEquals(message);
 
     builder = TestStruct.newBuilder();
     builder.setValue(Value.newBuilder().setNullValueValue(0).build());
     message = builder.build();
-    assertEquals(
-        "{\n"
-        + "  \"value\": null\n"
-        + "}", toJsonString(message));
+    assertEquals("{\n" + "  \"value\": null\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
 
     builder = TestStruct.newBuilder();
@@ -794,10 +786,7 @@
     listBuilder.addValues(Value.newBuilder().setNumberValue(31831.125).build());
     listBuilder.addValues(Value.newBuilder().setNullValueValue(0).build());
     message = builder.build();
-    assertEquals(
-        "{\n"
-        + "  \"listValue\": [31831.125, null]\n"
-        + "}", toJsonString(message));
+    assertEquals("{\n" + "  \"listValue\": [31831.125, null]\n" + "}", toJsonString(message));
     assertRoundTripEquals(message);
   }
 
@@ -813,158 +802,169 @@
       // Expected.
     }
 
-    JsonFormat.TypeRegistry registry = JsonFormat.TypeRegistry.newBuilder()
-        .add(TestAllTypes.getDescriptor()).build();
+    JsonFormat.TypeRegistry registry =
+        JsonFormat.TypeRegistry.newBuilder().add(TestAllTypes.getDescriptor()).build();
     JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(registry);
 
     assertEquals(
         "{\n"
-        + "  \"anyValue\": {\n"
-        + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-        + "    \"optionalInt32\": 1234\n"
-        + "  }\n"
-        + "}" , printer.print(message));
+            + "  \"anyValue\": {\n"
+            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+            + "    \"optionalInt32\": 1234\n"
+            + "  }\n"
+            + "}",
+        printer.print(message));
     assertRoundTripEquals(message, registry);
 
-
     // Well-known types have a special formatting when embedded in Any.
     //
     // 1. Any in Any.
     Any anyMessage = Any.pack(Any.pack(content));
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
-        + "  \"value\": {\n"
-        + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-        + "    \"optionalInt32\": 1234\n"
-        + "  }\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Any\",\n"
+            + "  \"value\": {\n"
+            + "    \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+            + "    \"optionalInt32\": 1234\n"
+            + "  }\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 2. Wrappers in Any.
     anyMessage = Any.pack(Int32Value.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
-        + "  \"value\": 12345\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int32Value\",\n"
+            + "  \"value\": 12345\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(UInt32Value.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
-        + "  \"value\": 12345\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt32Value\",\n"
+            + "  \"value\": 12345\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(Int64Value.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
-        + "  \"value\": \"12345\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Int64Value\",\n"
+            + "  \"value\": \"12345\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(UInt64Value.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
-        + "  \"value\": \"12345\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.UInt64Value\",\n"
+            + "  \"value\": \"12345\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(FloatValue.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
-        + "  \"value\": 12345.0\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.FloatValue\",\n"
+            + "  \"value\": 12345.0\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(DoubleValue.newBuilder().setValue(12345).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
-        + "  \"value\": 12345.0\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.DoubleValue\",\n"
+            + "  \"value\": 12345.0\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(BoolValue.newBuilder().setValue(true).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
-        + "  \"value\": true\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BoolValue\",\n"
+            + "  \"value\": true\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     anyMessage = Any.pack(StringValue.newBuilder().setValue("Hello").build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
-        + "  \"value\": \"Hello\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.StringValue\",\n"
+            + "  \"value\": \"Hello\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
-    anyMessage = Any.pack(BytesValue.newBuilder().setValue(
-        ByteString.copyFrom(new byte[]{1, 2})).build());
+    anyMessage =
+        Any.pack(BytesValue.newBuilder().setValue(ByteString.copyFrom(new byte[] {1, 2})).build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
-        + "  \"value\": \"AQI=\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.BytesValue\",\n"
+            + "  \"value\": \"AQI=\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 3. Timestamp in Any.
-    anyMessage = Any.pack(TimeUtil.parseTimestamp("1969-12-31T23:59:59Z"));
+    anyMessage = Any.pack(Timestamps.parse("1969-12-31T23:59:59Z"));
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
-        + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\",\n"
+            + "  \"value\": \"1969-12-31T23:59:59Z\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 4. Duration in Any
-    anyMessage = Any.pack(TimeUtil.parseDuration("12345.10s"));
+    anyMessage = Any.pack(Durations.parse("12345.10s"));
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
-        + "  \"value\": \"12345.100s\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n"
+            + "  \"value\": \"12345.100s\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 5. FieldMask in Any
     anyMessage = Any.pack(FieldMaskUtil.fromString("foo.bar,baz"));
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
-        + "  \"value\": \"foo.bar,baz\"\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.FieldMask\",\n"
+            + "  \"value\": \"foo.bar,baz\"\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
 
     // 6. Struct in Any
     Struct.Builder structBuilder = Struct.newBuilder();
-    structBuilder.getMutableFields().put(
-        "number", Value.newBuilder().setNumberValue(1.125).build());
+    structBuilder.putFields("number", Value.newBuilder().setNumberValue(1.125).build());
     anyMessage = Any.pack(structBuilder.build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
-        + "  \"value\": {\n"
-        + "    \"number\": 1.125\n"
-        + "  }\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Struct\",\n"
+            + "  \"value\": {\n"
+            + "    \"number\": 1.125\n"
+            + "  }\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
     Value.Builder valueBuilder = Value.newBuilder();
     valueBuilder.setNumberValue(1);
     anyMessage = Any.pack(valueBuilder.build());
     assertEquals(
         "{\n"
-        + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
-        + "  \"value\": 1.0\n"
-        + "}", printer.print(anyMessage));
+            + "  \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n"
+            + "  \"value\": 1.0\n"
+            + "}",
+        printer.print(anyMessage));
     assertRoundTripEquals(anyMessage, registry);
   }
 
   public void testParserMissingTypeUrl() throws Exception {
     try {
       Any.Builder builder = Any.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalInt32\": 1234\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalInt32\": 1234\n" + "}", builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
@@ -976,9 +976,10 @@
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
       mergeFromJson(
           "{\n"
-          + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
-          + "  \"optionalInt32\": 12345\n"
-          + "}", builder);
+              + "  \"@type\": \"type.googleapis.com/json_test.TestAllTypes\",\n"
+              + "  \"optionalInt32\": 12345\n"
+              + "}",
+          builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
@@ -988,10 +989,7 @@
   public void testParserRejectTrailingComma() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalInt32\": 12345,\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalInt32\": 12345,\n" + "}", builder);
       fail("Exception is expected.");
     } catch (IOException e) {
       // Expected.
@@ -1022,10 +1020,7 @@
   public void testParserRejectInvalidEnumValue() throws Exception {
     try {
       TestAllTypes.Builder builder = TestAllTypes.newBuilder();
-      mergeFromJson(
-          "{\n"
-          + "  \"optionalNestedEnum\": \"XXX\"\n"
-          + "}", builder);
+      mergeFromJson("{\n" + "  \"optionalNestedEnum\": \"XXX\"\n" + "}", builder);
       fail("Exception is expected.");
     } catch (InvalidProtocolBufferException e) {
       // Expected.
diff --git a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
index 4c31b2b..a41528e 100644
--- a/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
+++ b/java/util/src/test/java/com/google/protobuf/util/TimeUtilTest.java
@@ -84,6 +84,7 @@
   private class ParseTimestampThread extends Thread {
     private final String[] strings;
     private final Timestamp[] values;
+
     public ParseTimestampThread(String[] strings, Timestamp[] values) {
       this.strings = strings;
       this.values = values;
@@ -102,8 +103,8 @@
         }
         if (result.getSeconds() != values[index].getSeconds()
             || result.getNanos() != values[index].getNanos()) {
-          errorMessage = "Actual result: " + result.toString() + ", expected: "
-              + values[index].toString();
+          errorMessage =
+              "Actual result: " + result.toString() + ", expected: " + values[index].toString();
           break;
         }
         index = (index + 1) % strings.length;
@@ -112,26 +113,26 @@
   }
 
   public void testTimestampConcurrentParsing() throws Exception {
-    String[] timestampStrings = new String[]{
-      "0001-01-01T00:00:00Z",
-      "9999-12-31T23:59:59.999999999Z",
-      "1970-01-01T00:00:00Z",
-      "1969-12-31T23:59:59.999Z",
-    };
+    String[] timestampStrings =
+        new String[] {
+          "0001-01-01T00:00:00Z",
+          "9999-12-31T23:59:59.999999999Z",
+          "1970-01-01T00:00:00Z",
+          "1969-12-31T23:59:59.999Z",
+        };
     Timestamp[] timestampValues = new Timestamp[timestampStrings.length];
     for (int i = 0; i < timestampStrings.length; i++) {
       timestampValues[i] = TimeUtil.parseTimestamp(timestampStrings[i]);
     }
 
     final int THREAD_COUNT = 16;
-    final int RUNNING_TIME = 5000;  // in milliseconds.
+    final int RUNNING_TIME = 5000; // in milliseconds.
     final List<Thread> threads = new ArrayList<Thread>();
 
     stopParsingThreads = false;
     errorMessage = "";
     for (int i = 0; i < THREAD_COUNT; i++) {
-      Thread thread = new ParseTimestampThread(
-          timestampStrings, timestampValues);
+      Thread thread = new ParseTimestampThread(timestampStrings, timestampValues);
       thread.start();
       threads.add(thread);
     }
@@ -146,8 +147,8 @@
   public void testTimetampInvalidFormat() throws Exception {
     try {
       // Value too small.
-      Timestamp value = Timestamp.newBuilder()
-        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MIN - 1).build();
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(TimeUtil.TIMESTAMP_SECONDS_MIN - 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -156,14 +157,14 @@
 
     try {
       // Value too large.
-      Timestamp value = Timestamp.newBuilder()
-        .setSeconds(TimeUtil.TIMESTAMP_SECONDS_MAX + 1).build();
+      Timestamp value =
+          Timestamp.newBuilder().setSeconds(TimeUtil.TIMESTAMP_SECONDS_MAX + 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
       // Expected.
     }
-    
+
     try {
       // Invalid nanos value.
       Timestamp value = Timestamp.newBuilder().setNanos(-1).build();
@@ -279,8 +280,7 @@
   public void testDurationInvalidFormat() throws Exception {
     try {
       // Value too small.
-      Duration value = Duration.newBuilder()
-        .setSeconds(TimeUtil.DURATION_SECONDS_MIN - 1).build();
+      Duration value = Duration.newBuilder().setSeconds(TimeUtil.DURATION_SECONDS_MIN - 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -289,18 +289,7 @@
 
     try {
       // Value too large.
-      Duration value = Duration.newBuilder()
-        .setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
-      TimeUtil.toString(value);
-      Assert.fail("Exception is expected.");
-    } catch (IllegalArgumentException e) {
-      // Expected.
-    }
-    
-    try {
-      // Invalid nanos value.
-      Duration value = Duration.newBuilder().setSeconds(1).setNanos(-1)
-          .build();
+      Duration value = Duration.newBuilder().setSeconds(TimeUtil.DURATION_SECONDS_MAX + 1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -309,8 +298,16 @@
 
     try {
       // Invalid nanos value.
-      Duration value = Duration.newBuilder().setSeconds(-1).setNanos(1)
-          .build();
+      Duration value = Duration.newBuilder().setSeconds(1).setNanos(-1).build();
+      TimeUtil.toString(value);
+      Assert.fail("Exception is expected.");
+    } catch (IllegalArgumentException e) {
+      // Expected.
+    }
+
+    try {
+      // Invalid nanos value.
+      Duration value = Duration.newBuilder().setSeconds(-1).setNanos(1).build();
       TimeUtil.toString(value);
       Assert.fail("Exception is expected.");
     } catch (IllegalArgumentException e) {
@@ -367,8 +364,7 @@
   }
 
   public void testTimestampConversion() throws Exception {
-    Timestamp timestamp =
-      TimeUtil.parseTimestamp("1970-01-01T00:00:01.111111111Z");
+    Timestamp timestamp = TimeUtil.parseTimestamp("1970-01-01T00:00:01.111111111Z");
     assertEquals(1111111111, TimeUtil.toNanos(timestamp));
     assertEquals(1111111, TimeUtil.toMicros(timestamp));
     assertEquals(1111, TimeUtil.toMillis(timestamp));
@@ -378,7 +374,7 @@
     assertEquals("1970-01-01T00:00:01.111111Z", TimeUtil.toString(timestamp));
     timestamp = TimeUtil.createTimestampFromMillis(1111);
     assertEquals("1970-01-01T00:00:01.111Z", TimeUtil.toString(timestamp));
-    
+
     timestamp = TimeUtil.parseTimestamp("1969-12-31T23:59:59.111111111Z");
     assertEquals(-888888889, TimeUtil.toNanos(timestamp));
     assertEquals(-888889, TimeUtil.toMicros(timestamp));
@@ -402,7 +398,7 @@
     assertEquals("1.111111s", TimeUtil.toString(duration));
     duration = TimeUtil.createDurationFromMillis(1111);
     assertEquals("1.111s", TimeUtil.toString(duration));
-    
+
     duration = TimeUtil.parseDuration("-1.111111111s");
     assertEquals(-1111111111, TimeUtil.toNanos(duration));
     assertEquals(-1111111, TimeUtil.toMicros(duration));
@@ -459,29 +455,28 @@
 
     duration = TimeUtil.add(duration, duration);
     assertEquals("-2.250s", TimeUtil.toString(duration));
-    
+
     duration = TimeUtil.subtract(duration, TimeUtil.parseDuration("-1s"));
     assertEquals("-1.250s", TimeUtil.toString(duration));
-    
+
     // Multiplications (with results larger than Long.MAX_VALUE in nanoseconds).
     duration = TimeUtil.parseDuration("0.999999999s");
-    assertEquals("315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    assertEquals(
+        "315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
     duration = TimeUtil.parseDuration("-0.999999999s");
-    assertEquals("-315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
-    assertEquals("315575999684.424s",
-      TimeUtil.toString(TimeUtil.multiply(duration, -315576000000L)));
-    
+    assertEquals(
+        "-315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, 315576000000L)));
+    assertEquals(
+        "315575999684.424s", TimeUtil.toString(TimeUtil.multiply(duration, -315576000000L)));
+
     // Divisions (with values larger than Long.MAX_VALUE in nanoseconds).
     Duration d1 = TimeUtil.parseDuration("315576000000s");
     Duration d2 = TimeUtil.subtract(d1, TimeUtil.createDurationFromNanos(1));
     assertEquals(1, TimeUtil.divide(d1, d2));
     assertEquals(0, TimeUtil.divide(d2, d1));
     assertEquals("0.000000001s", TimeUtil.toString(TimeUtil.remainder(d1, d2)));
-    assertEquals("315575999999.999999999s",
-      TimeUtil.toString(TimeUtil.remainder(d2, d1)));
-    
+    assertEquals("315575999999.999999999s", TimeUtil.toString(TimeUtil.remainder(d2, d1)));
+
     // Divisions involving negative values.
     //
     // (-5) / 2 = -2, remainder = -1
diff --git a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
index 686edc4..4bf223f 100644
--- a/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
+++ b/java/util/src/test/proto/com/google/protobuf/util/json_test.proto
@@ -124,6 +124,7 @@
   oneof oneof_field {
     int32 oneof_int32 = 1;
     TestAllTypes.NestedMessage oneof_nested_message = 2;
+    google.protobuf.NullValue oneof_null_value = 3;
   }
 }
 
diff --git a/js/binary/constants.js b/js/binary/constants.js
index 836216b..ef5fecd 100644
--- a/js/binary/constants.js
+++ b/js/binary/constants.js
@@ -141,8 +141,8 @@
 
 /**
  * A writer function serializes a message to a BinaryWriter.
- * @typedef {!function(!jspb.Message, !jspb.BinaryWriter):void |
- *           !function(!jspb.ConstBinaryMessage, !jspb.BinaryWriter):void}
+ * @typedef {function((!jspb.Message|!jspb.ConstBinaryMessage),
+ *                    !jspb.BinaryWriter):void}
  */
 jspb.WriterFunction;
 
diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js
index d045e91..ac31264 100644
--- a/js/binary/decoder_test.js
+++ b/js/binary/decoder_test.js
@@ -147,9 +147,8 @@
 describe('binaryDecoderTest', function() {
   /**
    * Tests the decoder instance cache.
-   * @suppress {visibility}
    */
-  it('testInstanceCache', function() {
+  it('testInstanceCache', /** @suppress {visibility} */ function() {
     // Empty the instance caches.
     jspb.BinaryDecoder.instanceCache_ = [];
 
diff --git a/js/binary/reader_test.js b/js/binary/reader_test.js
index db674cf..9571138 100644
--- a/js/binary/reader_test.js
+++ b/js/binary/reader_test.js
@@ -52,9 +52,8 @@
 describe('binaryReaderTest', function() {
   /**
    * Tests the reader instance cache.
-   * @suppress {visibility}
    */
-  it('testInstanceCaches', function() {
+  it('testInstanceCaches', /** @suppress {visibility} */ function() {
     var writer = new jspb.BinaryWriter();
     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
     writer.writeMessage(1, dummyMessage, goog.nullFunction);
@@ -131,9 +130,8 @@
 
   /**
    * Verifies that misuse of the reader class triggers assertions.
-   * @suppress {checkTypes|visibility}
    */
-  it('testReadErrors', function() {
+  it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() {
     // Calling readMessage on a non-delimited field should trigger an
     // assertion.
     var reader = jspb.BinaryReader.alloc([8, 1]);
@@ -200,7 +198,7 @@
    * @private
    * @suppress {missingProperties}
    */
-  function doTestUnsignedField_(readField,
+  var doTestUnsignedField_ = function(readField,
       writeField, epsilon, upperLimit, filter) {
     assertNotNull(readField);
     assertNotNull(writeField);
@@ -252,7 +250,7 @@
    * @private
    * @suppress {missingProperties}
    */
-  function doTestSignedField_(readField,
+  var doTestSignedField_ = function(readField,
       writeField, epsilon, lowerLimit, upperLimit, filter) {
     var writer = new jspb.BinaryWriter();
 
@@ -321,12 +319,12 @@
    * Tests fields that use varint encoding.
    */
   it('testVarintFields', function() {
-    assertNotNull(jspb.BinaryReader.prototype.readUint32);
-    assertNotNull(jspb.BinaryReader.prototype.writeUint32);
-    assertNotNull(jspb.BinaryReader.prototype.readUint64);
-    assertNotNull(jspb.BinaryReader.prototype.writeUint64);
-    assertNotNull(jspb.BinaryReader.prototype.readBool);
-    assertNotNull(jspb.BinaryReader.prototype.writeBool);
+    assertNotUndefined(jspb.BinaryReader.prototype.readUint32);
+    assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32);
+    assertNotUndefined(jspb.BinaryReader.prototype.readUint64);
+    assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64);
+    assertNotUndefined(jspb.BinaryReader.prototype.readBool);
+    assertNotUndefined(jspb.BinaryWriter.prototype.writeBool);
     doTestUnsignedField_(
         jspb.BinaryReader.prototype.readUint32,
         jspb.BinaryWriter.prototype.writeUint32,
@@ -369,8 +367,7 @@
     var bytesCount = (hexString.length + 1) / 3;
     var bytes = new Uint8Array(bytesCount);
     for (var i = 0; i < bytesCount; i++) {
-      byte = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
-      bytes[i] = byte;
+      bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
     }
     var reader = jspb.BinaryReader.alloc(bytes);
     reader.nextField();
diff --git a/js/binary/writer.js b/js/binary/writer.js
index be4478e..3eb2f1b 100644
--- a/js/binary/writer.js
+++ b/js/binary/writer.js
@@ -717,11 +717,19 @@
 
 /**
  * Writes a message to the buffer.
- * @template MessageType
  * @param {number} field The field number.
  * @param {?MessageType} value The message to write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- *     to write and the writer to write it with.
+ * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
+ *     Will be invoked with the value to write and the writer to write it with.
+ * @template MessageType
+ * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
+ * the null in blah|null with none.  This is necessary because the compiler will
+ * infer MessageType to be nullable if the value parameter is nullable.
+ * @template MessageTypeNonNull :=
+ *     cond(isUnknown(MessageType), unknown(),
+ *       mapunion(MessageType, (X) =>
+ *         cond(eq(X, 'null'), none(), X)))
+ * =:
  */
 jspb.BinaryWriter.prototype.writeMessage = function(
     field, value, writerCallback) {
@@ -735,12 +743,20 @@
 /**
  * Writes a group message to the buffer.
  *
- * @template MessageType
  * @param {number} field The field number.
  * @param {?MessageType} value The message to write, wrapped with START_GROUP /
  *     END_GROUP tags. Will be a no-op if 'value' is null.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- *     to write and the writer to write it with.
+ * @param {function(MessageTypeNonNull, !jspb.BinaryWriter)} writerCallback
+ *     Will be invoked with the value to write and the writer to write it with.
+ * @template MessageType
+ * Use go/closure-ttl to declare a non-nullable version of MessageType.  Replace
+ * the null in blah|null with none.  This is necessary because the compiler will
+ * infer MessageType to be nullable if the value parameter is nullable.
+ * @template MessageTypeNonNull :=
+ *     cond(isUnknown(MessageType), unknown(),
+ *       mapunion(MessageType, (X) =>
+ *         cond(eq(X, 'null'), none(), X)))
+ * =:
  */
 jspb.BinaryWriter.prototype.writeGroup = function(
     field, value, writerCallback) {
@@ -1122,8 +1138,8 @@
  * @param {number} field The field number.
  * @param {?Array.<MessageType>} value The array of messages to
  *    write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- *     to write and the writer to write it with.
+ * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
+ *     Will be invoked with the value to write and the writer to write it with.
  */
 jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
     field, value, writerCallback) {
@@ -1142,8 +1158,8 @@
  * @param {number} field The field number.
  * @param {?Array.<MessageType>} value The array of messages to
  *    write.
- * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
- *     to write and the writer to write it with.
+ * @param {function(MessageType, !jspb.BinaryWriter)} writerCallback
+ *     Will be invoked with the value to write and the writer to write it with.
  */
 jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
     field, value, writerCallback) {
diff --git a/js/message.js b/js/message.js
index 813e6b8..3863bac 100644
--- a/js/message.js
+++ b/js/message.js
@@ -41,6 +41,7 @@
 goog.require('goog.asserts');
 goog.require('goog.crypt.base64');
 goog.require('goog.json');
+goog.require('jspb.Map');
 
 // Not needed in compilation units that have no protos with xids.
 goog.forwardDeclare('xid.String');
@@ -371,7 +372,8 @@
     // the object is not an array, since arrays are valid field values.
     // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug
     // in Safari on iOS 8. See the description of CL/86511464 for details.
-    if (obj && typeof obj == 'object' && !goog.isArray(obj)) {
+    if (obj && typeof obj == 'object' && !goog.isArray(obj) &&
+       !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) {
       msg.pivot_ = foundIndex - msg.arrayIndexOffset_;
       msg.extensionObject_ = obj;
       return;
@@ -738,6 +740,62 @@
 
 
 /**
+ * Gets the value of a map field, lazily creating the map container if
+ * necessary.
+ *
+ * This should only be called from generated code, because it requires knowledge
+ * of serialization/parsing callbacks (which are required by the map at
+ * construction time, and the map may be constructed here).
+ *
+ * The below callbacks are used to allow the map to serialize and parse its
+ * binary wire format data. Their purposes are described in more detail in
+ * `jspb.Map`'s constructor documentation.
+ *
+ * @template K, V
+ * @param {!jspb.Message} msg
+ * @param {number} fieldNumber
+ * @param {boolean|undefined} noLazyCreate
+ * @param {?=} opt_valueCtor
+ * @param {function(number,K)=} opt_keyWriterFn
+ * @param {function():K=} opt_keyReaderFn
+ * @param {function(number,V)|function(number,V,?)|
+ *         function(number,V,?,?,?,?)=} opt_valueWriterFn
+ * @param {function():V|
+ *         function(V,function(?,?))=} opt_valueReaderFn
+ * @param {function(?,?)|function(?,?,?,?,?)=} opt_valueWriterCallback
+ * @param {function(?,?)=} opt_valueReaderCallback
+ * @return {!jspb.Map<K, V>|undefined}
+ * @protected
+ */
+jspb.Message.getMapField = function(msg, fieldNumber, noLazyCreate,
+    opt_valueCtor, opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
+    opt_valueReaderFn, opt_valueWriterCallback, opt_valueReaderCallback) {
+  if (!msg.wrappers_) {
+    msg.wrappers_ = {};
+  }
+  // If we already have a map in the map wrappers, return that.
+  if (fieldNumber in msg.wrappers_) {
+    return msg.wrappers_[fieldNumber];
+  } else if (noLazyCreate) {
+    return undefined;
+  } else {
+    // Wrap the underlying elements array with a Map.
+    var arr = jspb.Message.getField(msg, fieldNumber);
+    if (!arr) {
+      arr = [];
+      jspb.Message.setField(msg, fieldNumber, arr);
+    }
+    return msg.wrappers_[fieldNumber] =
+        new jspb.Map(
+            /** @type {!Array<!Array<!Object>>} */ (arr),
+            opt_keyWriterFn, opt_keyReaderFn, opt_valueWriterFn,
+            opt_valueReaderFn, opt_valueCtor, opt_valueWriterCallback,
+            opt_valueReaderCallback);
+  }
+};
+
+
+/**
  * Sets the value of a non-extension field.
  * @param {!jspb.Message} msg A jspb proto.
  * @param {number} fieldNumber The field number.
@@ -953,12 +1011,45 @@
 
 
 /**
+ * Syncs all map fields' contents back to their underlying arrays.
+ * @private
+ */
+jspb.Message.prototype.syncMapFields_ = function() {
+  // This iterates over submessage, map, and repeated fields, which is intended.
+  // Submessages can contain maps which also need to be synced.
+  //
+  // There is a lot of opportunity for optimization here.  For example we could
+  // statically determine that some messages have no submessages with maps and
+  // optimize this method away for those just by generating one extra static
+  // boolean per message type.
+  if (this.wrappers_) {
+    for (var fieldNumber in this.wrappers_) {
+      var val = this.wrappers_[fieldNumber];
+      if (goog.isArray(val)) {
+        for (var i = 0; i < val.length; i++) {
+          if (val[i]) {
+            val[i].toArray();
+          }
+        }
+      } else {
+        // Works for submessages and maps.
+        if (val) {
+          val.toArray();
+        }
+      }
+    }
+  }
+};
+
+
+/**
  * Returns the internal array of this proto.
  * <p>Note: If you use this array to construct a second proto, the content
  * would then be partially shared between the two protos.
  * @return {!Array} The proto represented as an array.
  */
 jspb.Message.prototype.toArray = function() {
+  this.syncMapFields_();
   return this.array;
 };
 
@@ -972,6 +1063,7 @@
  * @override
  */
 jspb.Message.prototype.toString = function() {
+  this.syncMapFields_();
   return this.array.toString();
 };
 
@@ -1293,6 +1385,9 @@
     }
     return clonedArray;
   }
+  if (jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array) {
+    return new Uint8Array(obj);
+  }
   var clone = {};
   for (var key in obj) {
     if ((o = obj[key]) != null) {
diff --git a/js/message_test.js b/js/message_test.js
index 01add5f..0b0c017 100644
--- a/js/message_test.js
+++ b/js/message_test.js
@@ -34,6 +34,7 @@
 
 goog.require('goog.json');
 goog.require('goog.testing.asserts');
+goog.require('goog.userAgent');
 
 // CommonJS-LoadFromFile: google-protobuf jspb
 goog.require('jspb.Message');
@@ -66,6 +67,7 @@
 goog.require('proto.jspb.test.Simple2');
 goog.require('proto.jspb.test.SpecialCases');
 goog.require('proto.jspb.test.TestClone');
+goog.require('proto.jspb.test.TestEndsWithBytes');
 goog.require('proto.jspb.test.TestGroup');
 goog.require('proto.jspb.test.TestGroup1');
 goog.require('proto.jspb.test.TestMessageWithOneof');
@@ -438,6 +440,8 @@
   });
 
   it('testClone', function() {
+    var supportsUint8Array =
+        !goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10');
     var original = new proto.jspb.test.TestClone();
     original.setStr('v1');
     var simple1 = new proto.jspb.test.Simple1(['x1', ['y1', 'z1']]);
@@ -445,12 +449,14 @@
     var simple3 = new proto.jspb.test.Simple1(['x3', ['y3', 'z3']]);
     original.setSimple1(simple1);
     original.setSimple2List([simple2, simple3]);
+    var bytes1 = supportsUint8Array ? new Uint8Array([1, 2, 3]) : '123';
+    original.setBytesField(bytes1);
     var extension = new proto.jspb.test.CloneExtension();
     extension.setExt('e1');
     original.setExtension(proto.jspb.test.IsExtension.extField, extension);
     var clone = original.cloneMessage();
     assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
-      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
         clone.toArray());
     clone.setStr('v2');
     var simple4 = new proto.jspb.test.Simple1(['a1', ['b1', 'c1']]);
@@ -458,18 +464,26 @@
     var simple6 = new proto.jspb.test.Simple1(['a3', ['b3', 'c3']]);
     clone.setSimple1(simple4);
     clone.setSimple2List([simple5, simple6]);
+    if (supportsUint8Array) {
+      clone.getBytesField()[0] = 4;
+      assertObjectEquals(bytes1, original.getBytesField());
+    }
+    var bytes2 = supportsUint8Array ? new Uint8Array([4, 5, 6]) : '456';
+    clone.setBytesField(bytes2);
     var newExtension = new proto.jspb.test.CloneExtension();
     newExtension.setExt('e2');
     clone.setExtension(proto.jspb.test.CloneExtension.extField, newExtension);
     assertArrayEquals(['v2',, ['a1', ['b1', 'c1']],,
-      [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]],,, { 100: [, 'e2'] }],
+      [['a2', ['b2', 'c2']], ['a3', ['b3', 'c3']]], bytes2,, { 100: [, 'e2'] }],
         clone.toArray());
     assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],,
-      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]],,, { 100: [, 'e1'] }],
+      [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }],
         original.toArray());
   });
 
   it('testCopyInto', function() {
+    var supportsUint8Array =
+        !goog.userAgent.IE || goog.userAgent.isVersionOrHigher('10');
     var original = new proto.jspb.test.TestClone();
     original.setStr('v1');
     var dest = new proto.jspb.test.TestClone();
@@ -484,6 +498,10 @@
     original.setSimple2List([simple2, simple3]);
     dest.setSimple1(destSimple1);
     dest.setSimple2List([destSimple2, destSimple3]);
+    var bytes1 = supportsUint8Array ? new Uint8Array([1, 2, 3]) : '123';
+    var bytes2 = supportsUint8Array ? new Uint8Array([4, 5, 6]) : '456';
+    original.setBytesField(bytes1);
+    dest.setBytesField(bytes2);
     var extension = new proto.jspb.test.CloneExtension();
     extension.setExt('e1');
     original.setExtension(proto.jspb.test.CloneExtension.extField, extension);
@@ -496,6 +514,15 @@
     dest.getSimple1().setAString('new value');
     assertNotEquals(dest.getSimple1().getAString(),
         original.getSimple1().getAString());
+    if (supportsUint8Array) {
+      dest.getBytesField()[0] = 7;
+      assertObjectEquals(bytes1, original.getBytesField());
+      assertObjectEquals(new Uint8Array([7, 2, 3]), dest.getBytesField());
+    } else {
+      dest.setBytesField('789');
+      assertObjectEquals(bytes1, original.getBytesField());
+      assertObjectEquals('789', dest.getBytesField());
+    }
     dest.getExtension(proto.jspb.test.CloneExtension.extField).
         setExt('new value');
     assertNotEquals(
diff --git a/js/test.proto b/js/test.proto
index 6b9dc89..06eb79a 100644
--- a/js/test.proto
+++ b/js/test.proto
@@ -160,6 +160,7 @@
   optional string str = 1;
   optional Simple1 simple1 = 3;
   repeated Simple1 simple2 = 5;
+  optional bytes bytes_field = 6;
   optional string unused = 7;
   extensions 10 to max;
 }
diff --git a/js/testbinary.proto b/js/testbinary.proto
index 60c7019..a3fcb5f 100644
--- a/js/testbinary.proto
+++ b/js/testbinary.proto
@@ -183,3 +183,32 @@
       [packed=true];
 
 }
+
+message TestMapFields {
+  option (jspb.generate_from_object) = true;
+
+  map<string, string> map_string_string = 1;
+  map<string, int32> map_string_int32 = 2;
+  map<string, int64> map_string_int64 = 3;
+  map<string, bool> map_string_bool = 4;
+  map<string, double> map_string_double = 5;
+  map<string, MapValueEnum> map_string_enum = 6;
+  map<string, MapValueMessage> map_string_msg = 7;
+
+  map<int32, string> map_int32_string = 8;
+  map<int64, string> map_int64_string = 9;
+  map<bool, string> map_bool_string = 10;
+
+  optional TestMapFields test_map_fields = 11;
+  map<string, TestMapFields> map_string_testmapfields = 12;
+}
+
+enum MapValueEnum {
+  MAP_VALUE_FOO = 0;
+  MAP_VALUE_BAR = 1;
+  MAP_VALUE_BAZ = 2;
+}
+
+message MapValueMessage {
+  optional int32 foo = 1;
+}
diff --git a/python/google/protobuf/descriptor.py b/python/google/protobuf/descriptor.py
index 3209b34..2eba123 100755
--- a/python/google/protobuf/descriptor.py
+++ b/python/google/protobuf/descriptor.py
@@ -258,7 +258,7 @@
     def __new__(cls, name, full_name, filename, containing_type, fields,
                 nested_types, enum_types, extensions, options=None,
                 is_extendable=True, extension_ranges=None, oneofs=None,
-                file=None, serialized_start=None, serialized_end=None,
+                file=None, serialized_start=None, serialized_end=None,  # pylint: disable=redefined-builtin
                 syntax=None):
       _message.Message._CheckCalledFromGeneratedFile()
       return _message.default_pool.FindMessageTypeByName(full_name)
@@ -269,8 +269,8 @@
   def __init__(self, name, full_name, filename, containing_type, fields,
                nested_types, enum_types, extensions, options=None,
                is_extendable=True, extension_ranges=None, oneofs=None,
-               file=None, serialized_start=None, serialized_end=None,
-               syntax=None):  # pylint:disable=redefined-builtin
+               file=None, serialized_start=None, serialized_end=None,  # pylint: disable=redefined-builtin
+               syntax=None):
     """Arguments to __init__() are as described in the description
     of Descriptor fields above.
 
@@ -665,7 +665,7 @@
     self.type = type
 
 
-class OneofDescriptor(object):
+class OneofDescriptor(DescriptorBase):
   """Descriptor for a oneof field.
 
     name: (str) Name of the oneof field.
@@ -682,12 +682,15 @@
   if _USE_C_DESCRIPTORS:
     _C_DESCRIPTOR_CLASS = _message.OneofDescriptor
 
-    def __new__(cls, name, full_name, index, containing_type, fields):
+    def __new__(
+        cls, name, full_name, index, containing_type, fields, options=None):
       _message.Message._CheckCalledFromGeneratedFile()
       return _message.default_pool.FindOneofByName(full_name)
 
-  def __init__(self, name, full_name, index, containing_type, fields):
+  def __init__(
+      self, name, full_name, index, containing_type, fields, options=None):
     """Arguments are as described in the attribute description above."""
+    super(OneofDescriptor, self).__init__(options, 'OneofOptions')
     self.name = name
     self.full_name = full_name
     self.index = index
@@ -705,11 +708,22 @@
       definition appears withing the .proto file.
     methods: (list of MethodDescriptor) List of methods provided by this
       service.
+    methods_by_name: (dict str -> MethodDescriptor) Same MethodDescriptor
+      objects as in |methods_by_name|, but indexed by "name" attribute in each
+      MethodDescriptor.
     options: (descriptor_pb2.ServiceOptions) Service options message or
       None to use default service options.
     file: (FileDescriptor) Reference to file info.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.ServiceDescriptor
+
+    def __new__(cls, name, full_name, index, methods, options=None, file=None,  # pylint: disable=redefined-builtin
+                serialized_start=None, serialized_end=None):
+      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
+      return _message.default_pool.FindServiceByName(full_name)
+
   def __init__(self, name, full_name, index, methods, options=None, file=None,
                serialized_start=None, serialized_end=None):
     super(ServiceDescriptor, self).__init__(
@@ -718,16 +732,14 @@
         serialized_end=serialized_end)
     self.index = index
     self.methods = methods
+    self.methods_by_name = dict((m.name, m) for m in methods)
     # Set the containing service for each method in this service.
     for method in self.methods:
       method.containing_service = self
 
   def FindMethodByName(self, name):
     """Searches for the specified method, and returns its descriptor."""
-    for method in self.methods:
-      if name == method.name:
-        return method
-    return None
+    return self.methods_by_name.get(name, None)
 
   def CopyToProto(self, proto):
     """Copies this to a descriptor_pb2.ServiceDescriptorProto.
@@ -754,6 +766,14 @@
     None to use default method options.
   """
 
+  if _USE_C_DESCRIPTORS:
+    _C_DESCRIPTOR_CLASS = _message.MethodDescriptor
+
+    def __new__(cls, name, full_name, index, containing_service,
+                input_type, output_type, options=None):
+      _message.Message._CheckCalledFromGeneratedFile()  # pylint: disable=protected-access
+      return _message.default_pool.FindMethodByName(full_name)
+
   def __init__(self, name, full_name, index, containing_service,
                input_type, output_type, options=None):
     """The arguments are as described in the description of MethodDescriptor
@@ -788,6 +808,7 @@
   message_types_by_name: Dict of message names of their descriptors.
   enum_types_by_name: Dict of enum names and their descriptors.
   extensions_by_name: Dict of extension names and their descriptors.
+  services_by_name: Dict of services names and their descriptors.
   pool: the DescriptorPool this descriptor belongs to.  When not passed to the
     constructor, the global default pool is used.
   """
@@ -825,6 +846,7 @@
 
     self.enum_types_by_name = {}
     self.extensions_by_name = {}
+    self.services_by_name = {}
     self.dependencies = (dependencies or [])
     self.public_dependencies = (public_dependencies or [])
 
diff --git a/python/google/protobuf/descriptor_pool.py b/python/google/protobuf/descriptor_pool.py
index 20a3370..5c055ab 100644
--- a/python/google/protobuf/descriptor_pool.py
+++ b/python/google/protobuf/descriptor_pool.py
@@ -394,6 +394,11 @@
               desc_proto_prefix, desc_proto.name, scope)
           file_descriptor.message_types_by_name[desc_proto.name] = desc
 
+        for index, service_proto in enumerate(file_proto.service):
+          file_descriptor.services_by_name[service_proto.name] = (
+              self._MakeServiceDescriptor(service_proto, index, scope,
+                                          file_proto.package, file_descriptor))
+
       self.Add(file_proto)
       self._file_descriptors[file_proto.name] = file_descriptor
 
@@ -441,7 +446,7 @@
         for index, extension in enumerate(desc_proto.extension)]
     oneofs = [
         descriptor.OneofDescriptor(desc.name, '.'.join((desc_name, desc.name)),
-                                   index, None, [])
+                                   index, None, [], desc.options)
         for index, desc in enumerate(desc_proto.oneof_decl)]
     extension_ranges = [(r.start, r.end) for r in desc_proto.extension_range]
     if extension_ranges:
@@ -679,6 +684,64 @@
         options=value_proto.options,
         type=None)
 
+  def _MakeServiceDescriptor(self, service_proto, service_index, scope,
+                             package, file_desc):
+    """Make a protobuf ServiceDescriptor given a ServiceDescriptorProto.
+
+    Args:
+      service_proto: The descriptor_pb2.ServiceDescriptorProto protobuf message.
+      service_index: The index of the service in the File.
+      scope: Dict mapping short and full symbols to message and enum types.
+      package: Optional package name for the new message EnumDescriptor.
+      file_desc: The file containing the service descriptor.
+
+    Returns:
+      The added descriptor.
+    """
+
+    if package:
+      service_name = '.'.join((package, service_proto.name))
+    else:
+      service_name = service_proto.name
+
+    methods = [self._MakeMethodDescriptor(method_proto, service_name, package,
+                                          scope, index)
+               for index, method_proto in enumerate(service_proto.method)]
+    desc = descriptor.ServiceDescriptor(name=service_proto.name,
+                                        full_name=service_name,
+                                        index=service_index,
+                                        methods=methods,
+                                        options=service_proto.options,
+                                        file=file_desc)
+    return desc
+
+  def _MakeMethodDescriptor(self, method_proto, service_name, package, scope,
+                            index):
+    """Creates a method descriptor from a MethodDescriptorProto.
+
+    Args:
+      method_proto: The proto describing the method.
+      service_name: The name of the containing service.
+      package: Optional package name to look up for types.
+      scope: Scope containing available types.
+      index: Index of the method in the service.
+
+    Returns:
+      An initialized MethodDescriptor object.
+    """
+    full_name = '.'.join((service_name, method_proto.name))
+    input_type = self._GetTypeFromScope(
+        package, method_proto.input_type, scope)
+    output_type = self._GetTypeFromScope(
+        package, method_proto.output_type, scope)
+    return descriptor.MethodDescriptor(name=method_proto.name,
+                                       full_name=full_name,
+                                       index=index,
+                                       containing_service=None,
+                                       input_type=input_type,
+                                       output_type=output_type,
+                                       options=method_proto.options)
+
   def _ExtractSymbols(self, descriptors):
     """Pulls out all the symbols from descriptor protos.
 
diff --git a/python/google/protobuf/internal/containers.py b/python/google/protobuf/internal/containers.py
index 97cdd84..ce46d08 100755
--- a/python/google/protobuf/internal/containers.py
+++ b/python/google/protobuf/internal/containers.py
@@ -594,7 +594,11 @@
 
   def MergeFrom(self, other):
     for key in other:
-      self[key].MergeFrom(other[key])
+      # According to documentation: "When parsing from the wire or when merging,
+      # if there are duplicate map keys the last key seen is used".
+      if key in self:
+        del self[key]
+      self[key].CopyFrom(other[key])
     # self._message_listener.Modified() not required here, because
     # mutations to submessages already propagate.
 
diff --git a/python/google/protobuf/internal/descriptor_pool_test.py b/python/google/protobuf/internal/descriptor_pool_test.py
index 6a13e0b..3c8c793 100644
--- a/python/google/protobuf/internal/descriptor_pool_test.py
+++ b/python/google/protobuf/internal/descriptor_pool_test.py
@@ -51,6 +51,7 @@
 from google.protobuf.internal import descriptor_pool_test2_pb2
 from google.protobuf.internal import factory_test1_pb2
 from google.protobuf.internal import factory_test2_pb2
+from google.protobuf.internal import file_options_test_pb2
 from google.protobuf.internal import more_messages_pb2
 from google.protobuf import descriptor
 from google.protobuf import descriptor_database
@@ -630,6 +631,23 @@
     self.assertEqual(pool.FindMessageTypeByName('package.Message').name,
                      'Message')
 
+  def testFileDescriptorOptionsWithCustomDescriptorPool(self):
+    # Create a descriptor pool, and add a new FileDescriptorProto to it.
+    pool = descriptor_pool.DescriptorPool()
+    file_name = 'file_descriptor_options_with_custom_descriptor_pool.proto'
+    file_descriptor_proto = descriptor_pb2.FileDescriptorProto(name=file_name)
+    extension_id = file_options_test_pb2.foo_options
+    file_descriptor_proto.options.Extensions[extension_id].foo_name = 'foo'
+    pool.Add(file_descriptor_proto)
+    # The options set on the FileDescriptorProto should be available in the
+    # descriptor even if they contain extensions that cannot be deserialized
+    # using the pool.
+    file_descriptor = pool.FindFileByName(file_name)
+    options = file_descriptor.GetOptions()
+    self.assertEqual('foo', options.Extensions[extension_id].foo_name)
+    # The object returned by GetOptions() is cached.
+    self.assertIs(options, file_descriptor.GetOptions())
+
 
 @unittest.skipIf(
     api_implementation.Type() != 'cpp',
diff --git a/python/google/protobuf/internal/descriptor_test.py b/python/google/protobuf/internal/descriptor_test.py
index b8e7555..623198c 100755
--- a/python/google/protobuf/internal/descriptor_test.py
+++ b/python/google/protobuf/internal/descriptor_test.py
@@ -77,27 +77,24 @@
     enum_proto.value.add(name='FOREIGN_BAR', number=5)
     enum_proto.value.add(name='FOREIGN_BAZ', number=6)
 
+    file_proto.message_type.add(name='ResponseMessage')
+    service_proto = file_proto.service.add(
+        name='Service')
+    method_proto = service_proto.method.add(
+        name='CallMethod',
+        input_type='.protobuf_unittest.NestedMessage',
+        output_type='.protobuf_unittest.ResponseMessage')
+
+    # Note: Calling DescriptorPool.Add() multiple times with the same file only
+    # works if the input is canonical; in particular, all type names must be
+    # fully qualified.
     self.pool = self.GetDescriptorPool()
     self.pool.Add(file_proto)
     self.my_file = self.pool.FindFileByName(file_proto.name)
     self.my_message = self.my_file.message_types_by_name[message_proto.name]
     self.my_enum = self.my_message.enum_types_by_name[enum_proto.name]
-
-    self.my_method = descriptor.MethodDescriptor(
-        name='Bar',
-        full_name='protobuf_unittest.TestService.Bar',
-        index=0,
-        containing_service=None,
-        input_type=None,
-        output_type=None)
-    self.my_service = descriptor.ServiceDescriptor(
-        name='TestServiceWithOptions',
-        full_name='protobuf_unittest.TestServiceWithOptions',
-        file=self.my_file,
-        index=0,
-        methods=[
-            self.my_method
-        ])
+    self.my_service = self.my_file.services_by_name[service_proto.name]
+    self.my_method = self.my_service.methods_by_name[method_proto.name]
 
   def GetDescriptorPool(self):
     return symbol_database.Default().pool
@@ -139,13 +136,14 @@
     file_descriptor = unittest_custom_options_pb2.DESCRIPTOR
     message_descriptor =\
         unittest_custom_options_pb2.TestMessageWithCustomOptions.DESCRIPTOR
-    field_descriptor = message_descriptor.fields_by_name["field1"]
-    enum_descriptor = message_descriptor.enum_types_by_name["AnEnum"]
+    field_descriptor = message_descriptor.fields_by_name['field1']
+    oneof_descriptor = message_descriptor.oneofs_by_name['AnOneof']
+    enum_descriptor = message_descriptor.enum_types_by_name['AnEnum']
     enum_value_descriptor =\
-        message_descriptor.enum_values_by_name["ANENUM_VAL2"]
+        message_descriptor.enum_values_by_name['ANENUM_VAL2']
     service_descriptor =\
         unittest_custom_options_pb2.TestServiceWithCustomOptions.DESCRIPTOR
-    method_descriptor = service_descriptor.FindMethodByName("Foo")
+    method_descriptor = service_descriptor.FindMethodByName('Foo')
 
     file_options = file_descriptor.GetOptions()
     file_opt1 = unittest_custom_options_pb2.file_opt1
@@ -158,6 +156,9 @@
     self.assertEqual(8765432109, field_options.Extensions[field_opt1])
     field_opt2 = unittest_custom_options_pb2.field_opt2
     self.assertEqual(42, field_options.Extensions[field_opt2])
+    oneof_options = oneof_descriptor.GetOptions()
+    oneof_opt1 = unittest_custom_options_pb2.oneof_opt1
+    self.assertEqual(-99, oneof_options.Extensions[oneof_opt1])
     enum_options = enum_descriptor.GetOptions()
     enum_opt1 = unittest_custom_options_pb2.enum_opt1
     self.assertEqual(-789, enum_options.Extensions[enum_opt1])
diff --git a/python/google/protobuf/internal/file_options_test.proto b/python/google/protobuf/internal/file_options_test.proto
new file mode 100644
index 0000000..4eceeb0
--- /dev/null
+++ b/python/google/protobuf/internal/file_options_test.proto
@@ -0,0 +1,43 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+syntax = "proto2";
+
+import "google/protobuf/descriptor.proto";
+
+package google.protobuf.python.internal;
+
+message FooOptions {
+  optional string foo_name = 1;
+}
+
+extend .google.protobuf.FileOptions {
+  optional FooOptions foo_options = 120436268;
+}
diff --git a/python/google/protobuf/internal/json_format_test.py b/python/google/protobuf/internal/json_format_test.py
index 9e32ea4..6df12be 100644
--- a/python/google/protobuf/internal/json_format_test.py
+++ b/python/google/protobuf/internal/json_format_test.py
@@ -643,6 +643,19 @@
                     'Message type "proto3.TestMessage" has no field named '
                     '"unknownName".')
 
+  def testIgnoreUnknownField(self):
+    text = '{"unknownName": 1}'
+    parsed_message = json_format_proto3_pb2.TestMessage()
+    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+    text = ('{\n'
+            '  "repeatedValue": [ {\n'
+            '    "@type": "type.googleapis.com/proto3.MessageType",\n'
+            '    "unknownName": 1\n'
+            '  }]\n'
+            '}\n')
+    parsed_message = json_format_proto3_pb2.TestAny()
+    json_format.Parse(text, parsed_message, ignore_unknown_fields=True)
+
   def testDuplicateField(self):
     # Duplicate key check is not supported for python2.6
     if sys.version_info < (2, 7):
diff --git a/python/google/protobuf/internal/message_test.py b/python/google/protobuf/internal/message_test.py
index 4ee31d8..1e95adf 100755
--- a/python/google/protobuf/internal/message_test.py
+++ b/python/google/protobuf/internal/message_test.py
@@ -1435,6 +1435,8 @@
     msg2.map_int32_int32[12] = 55
     msg2.map_int64_int64[88] = 99
     msg2.map_int32_foreign_message[222].c = 15
+    msg2.map_int32_foreign_message[222].d = 20
+    old_map_value = msg2.map_int32_foreign_message[222]
 
     msg2.MergeFrom(msg)
 
@@ -1444,6 +1446,8 @@
     self.assertEqual(99, msg2.map_int64_int64[88])
     self.assertEqual(5, msg2.map_int32_foreign_message[111].c)
     self.assertEqual(10, msg2.map_int32_foreign_message[222].c)
+    self.assertFalse(msg2.map_int32_foreign_message[222].HasField('d'))
+    self.assertEqual(15, old_map_value.c)
 
     # Verify that there is only one entry per key, even though the MergeFrom
     # may have internally created multiple entries for a single key in the
diff --git a/python/google/protobuf/internal/text_format_test.py b/python/google/protobuf/internal/text_format_test.py
index ab2bf05..0e38e0e 100755
--- a/python/google/protobuf/internal/text_format_test.py
+++ b/python/google/protobuf/internal/text_format_test.py
@@ -40,12 +40,13 @@
 import string
 
 try:
-  import unittest2 as unittest  #PY26
+  import unittest2 as unittest  # PY26, pylint: disable=g-import-not-at-top
 except ImportError:
-  import unittest
+  import unittest  # pylint: disable=g-import-not-at-top
 
 from google.protobuf.internal import _parameterized
 
+from google.protobuf import any_test_pb2
 from google.protobuf import map_unittest_pb2
 from google.protobuf import unittest_mset_pb2
 from google.protobuf import unittest_pb2
@@ -53,6 +54,7 @@
 from google.protobuf.internal import api_implementation
 from google.protobuf.internal import test_util
 from google.protobuf.internal import message_set_extensions_pb2
+from google.protobuf import descriptor_pool
 from google.protobuf import text_format
 
 
@@ -90,13 +92,11 @@
                .replace('e-0','e-').replace('e-0','e-')
     # Floating point fields are printed with .0 suffix even if they are
     # actualy integer numbers.
-    text = re.compile('\.0$', re.MULTILINE).sub('', text)
+    text = re.compile(r'\.0$', re.MULTILINE).sub('', text)
     return text
 
 
-@_parameterized.Parameters(
-    (unittest_pb2),
-    (unittest_proto3_arena_pb2))
+@_parameterized.Parameters((unittest_pb2), (unittest_proto3_arena_pb2))
 class TextFormatTest(TextFormatBase):
 
   def testPrintExotic(self, message_module):
@@ -120,8 +120,10 @@
         'repeated_string: "\\303\\274\\352\\234\\237"\n')
 
   def testPrintExoticUnicodeSubclass(self, message_module):
+
     class UnicodeSub(six.text_type):
       pass
+
     message = message_module.TestAllTypes()
     message.repeated_string.append(UnicodeSub(u'\u00fc\ua71f'))
     self.CompareToGoldenText(
@@ -165,8 +167,8 @@
     message.repeated_string.append('\000\001\a\b\f\n\r\t\v\\\'"')
     message.repeated_string.append(u'\u00fc\ua71f')
     self.CompareToGoldenText(
-        self.RemoveRedundantZeros(
-            text_format.MessageToString(message, as_one_line=True)),
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, as_one_line=True)),
         'repeated_int64: -9223372036854775808'
         ' repeated_uint64: 18446744073709551615'
         ' repeated_double: 123.456'
@@ -187,21 +189,23 @@
     message.repeated_string.append(u'\u00fc\ua71f')
 
     # Test as_utf8 = False.
-    wire_text = text_format.MessageToString(
-        message, as_one_line=True, as_utf8=False)
+    wire_text = text_format.MessageToString(message,
+                                            as_one_line=True,
+                                            as_utf8=False)
     parsed_message = message_module.TestAllTypes()
     r = text_format.Parse(wire_text, parsed_message)
     self.assertIs(r, parsed_message)
     self.assertEqual(message, parsed_message)
 
     # Test as_utf8 = True.
-    wire_text = text_format.MessageToString(
-        message, as_one_line=True, as_utf8=True)
+    wire_text = text_format.MessageToString(message,
+                                            as_one_line=True,
+                                            as_utf8=True)
     parsed_message = message_module.TestAllTypes()
     r = text_format.Parse(wire_text, parsed_message)
     self.assertIs(r, parsed_message)
     self.assertEqual(message, parsed_message,
-                      '\n%s != %s' % (message, parsed_message))
+                     '\n%s != %s' % (message, parsed_message))
 
   def testPrintRawUtf8String(self, message_module):
     message = message_module.TestAllTypes()
@@ -211,7 +215,7 @@
     parsed_message = message_module.TestAllTypes()
     text_format.Parse(text, parsed_message)
     self.assertEqual(message, parsed_message,
-                      '\n%s != %s' % (message, parsed_message))
+                     '\n%s != %s' % (message, parsed_message))
 
   def testPrintFloatFormat(self, message_module):
     # Check that float_format argument is passed to sub-message formatting.
@@ -232,14 +236,15 @@
     message.payload.repeated_double.append(.000078900)
     formatted_fields = ['optional_float: 1.25',
                         'optional_double: -3.45678901234568e-6',
-                        'repeated_float: -5642',
-                        'repeated_double: 7.89e-5']
+                        'repeated_float: -5642', 'repeated_double: 7.89e-5']
     text_message = text_format.MessageToString(message, float_format='.15g')
     self.CompareToGoldenText(
         self.RemoveRedundantZeros(text_message),
-        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(*formatted_fields))
+        'payload {{\n  {0}\n  {1}\n  {2}\n  {3}\n}}\n'.format(
+            *formatted_fields))
     # as_one_line=True is a separate code branch where float_format is passed.
-    text_message = text_format.MessageToString(message, as_one_line=True,
+    text_message = text_format.MessageToString(message,
+                                               as_one_line=True,
                                                float_format='.15g')
     self.CompareToGoldenText(
         self.RemoveRedundantZeros(text_message),
@@ -311,8 +316,7 @@
     self.assertEqual(123.456, message.repeated_double[0])
     self.assertEqual(1.23e22, message.repeated_double[1])
     self.assertEqual(1.23e-18, message.repeated_double[2])
-    self.assertEqual(
-        '\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
+    self.assertEqual('\000\001\a\b\f\n\r\t\v\\\'"', message.repeated_string[0])
     self.assertEqual('foocorgegrault', message.repeated_string[1])
     self.assertEqual(u'\u00fc\ua71f', message.repeated_string[2])
     self.assertEqual(u'\u00fc', message.repeated_string[3])
@@ -371,45 +375,38 @@
   def testParseSingleWord(self, message_module):
     message = message_module.TestAllTypes()
     text = 'foo'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
-         r'"foo".'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+        r'"foo".'), text_format.Parse, text, message)
 
   def testParseUnknownField(self, message_module):
     message = message_module.TestAllTypes()
     text = 'unknown_field: 8\n'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
-         r'"unknown_field".'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+        r'"unknown_field".'), text_format.Parse, text, message)
 
   def testParseBadEnumValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: BARR'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
-         r'has no value named BARR.'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError,
+                          (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+                           r'has no value named BARR.'), text_format.Parse,
+                          text, message)
 
     message = message_module.TestAllTypes()
     text = 'optional_nested_enum: 100'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
-         r'has no value with number 100.'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError,
+                          (r'1:23 : Enum type "\w+.TestAllTypes.NestedEnum" '
+                           r'has no value with number 100.'), text_format.Parse,
+                          text, message)
 
   def testParseBadIntValue(self, message_module):
     message = message_module.TestAllTypes()
     text = 'optional_int32: bork'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        ('1:17 : Couldn\'t parse integer: bork'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError,
+                          ('1:17 : Couldn\'t parse integer: bork'),
+                          text_format.Parse, text, message)
 
   def testParseStringFieldUnescape(self, message_module):
     message = message_module.TestAllTypes()
@@ -419,6 +416,7 @@
                repeated_string: "\\\\xf\\\\x62"
                repeated_string: "\\\\\xf\\\\\x62"
                repeated_string: "\x5cx20"'''
+
     text_format.Parse(text, message)
 
     SLASH = '\\'
@@ -433,8 +431,7 @@
 
   def testMergeDuplicateScalars(self, message_module):
     message = message_module.TestAllTypes()
-    text = ('optional_int32: 42 '
-            'optional_int32: 67')
+    text = ('optional_int32: 42 ' 'optional_int32: 67')
     r = text_format.Merge(text, message)
     self.assertIs(r, message)
     self.assertEqual(67, message.optional_int32)
@@ -455,13 +452,11 @@
     self.assertEqual('oneof_uint32', m2.WhichOneof('oneof_field'))
 
   def testParseMultipleOneof(self, message_module):
-    m_string = '\n'.join([
-        'oneof_uint32: 11',
-        'oneof_string: "foo"'])
+    m_string = '\n'.join(['oneof_uint32: 11', 'oneof_string: "foo"'])
     m2 = message_module.TestAllTypes()
     if message_module is unittest_pb2:
-      with self.assertRaisesRegexp(
-          text_format.ParseError, ' is specified along with field '):
+      with self.assertRaisesRegexp(text_format.ParseError,
+                                   ' is specified along with field '):
         text_format.Parse(m_string, m2)
     else:
       text_format.Parse(m_string, m2)
@@ -477,8 +472,8 @@
     message = unittest_pb2.TestAllTypes()
     test_util.SetAllFields(message)
     self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(
-            text_format.MessageToString(message, pointy_brackets=True)),
+        self.RemoveRedundantZeros(text_format.MessageToString(
+            message, pointy_brackets=True)),
         'text_format_unittest_data_pointy_oneof.txt')
 
   def testParseGolden(self):
@@ -499,14 +494,6 @@
         self.RemoveRedundantZeros(text_format.MessageToString(message)),
         'text_format_unittest_data_oneof_implemented.txt')
 
-  def testPrintAllFieldsPointy(self):
-    message = unittest_pb2.TestAllTypes()
-    test_util.SetAllFields(message)
-    self.CompareToGoldenFile(
-        self.RemoveRedundantZeros(
-            text_format.MessageToString(message, pointy_brackets=True)),
-        'text_format_unittest_data_pointy_oneof.txt')
-
   def testPrintInIndexOrder(self):
     message = unittest_pb2.TestFieldOrderings()
     message.my_string = '115'
@@ -520,8 +507,7 @@
         'my_string: \"115\"\nmy_int: 101\nmy_float: 111\n'
         'optional_nested_message {\n  oo: 0\n  bb: 1\n}\n')
     self.CompareToGoldenText(
-        self.RemoveRedundantZeros(text_format.MessageToString(
-            message)),
+        self.RemoveRedundantZeros(text_format.MessageToString(message)),
         'my_int: 101\nmy_string: \"115\"\nmy_float: 111\n'
         'optional_nested_message {\n  bb: 1\n  oo: 0\n}\n')
 
@@ -552,14 +538,13 @@
     message.map_int64_int64[-2**33] = -2**34
     message.map_uint32_uint32[123] = 456
     message.map_uint64_uint64[2**33] = 2**34
-    message.map_string_string["abc"] = "123"
+    message.map_string_string['abc'] = '123'
     message.map_int32_foreign_message[111].c = 5
 
     # Maps are serialized to text format using their underlying repeated
     # representation.
     self.CompareToGoldenText(
-        text_format.MessageToString(message),
-        'map_int32_int32 {\n'
+        text_format.MessageToString(message), 'map_int32_int32 {\n'
         '  key: -123\n'
         '  value: -456\n'
         '}\n'
@@ -592,9 +577,8 @@
       message.map_string_string[letter] = 'dummy'
     for letter in reversed(string.ascii_uppercase[0:13]):
       message.map_string_string[letter] = 'dummy'
-    golden = ''.join((
-        'map_string_string {\n  key: "%c"\n  value: "dummy"\n}\n' % (letter,)
-        for letter in string.ascii_uppercase))
+    golden = ''.join(('map_string_string {\n  key: "%c"\n  value: "dummy"\n}\n'
+                      % (letter,) for letter in string.ascii_uppercase))
     self.CompareToGoldenText(text_format.MessageToString(message), golden)
 
   def testMapOrderSemantics(self):
@@ -602,9 +586,7 @@
     # The C++ implementation emits defaulted-value fields, while the Python
     # implementation does not.  Adjusting for this is awkward, but it is
     # valuable to test against a common golden file.
-    line_blacklist = ('  key: 0\n',
-                      '  value: 0\n',
-                      '  key: false\n',
+    line_blacklist = ('  key: 0\n', '  value: 0\n', '  key: false\n',
                       '  value: false\n')
     golden_lines = [line for line in golden_lines if line not in line_blacklist]
 
@@ -627,8 +609,7 @@
     message.message_set.Extensions[ext1].i = 23
     message.message_set.Extensions[ext2].str = 'foo'
     self.CompareToGoldenText(
-        text_format.MessageToString(message),
-        'message_set {\n'
+        text_format.MessageToString(message), 'message_set {\n'
         '  [protobuf_unittest.TestMessageSetExtension1] {\n'
         '    i: 23\n'
         '  }\n'
@@ -654,16 +635,14 @@
     message.message_set.Extensions[ext1].i = 23
     message.message_set.Extensions[ext2].str = 'foo'
     text_format.PrintMessage(message, out, use_field_number=True)
-    self.CompareToGoldenText(
-        out.getvalue(),
-        '1 {\n'
-        '  1545008 {\n'
-        '    15: 23\n'
-        '  }\n'
-        '  1547769 {\n'
-        '    25: \"foo\"\n'
-        '  }\n'
-        '}\n')
+    self.CompareToGoldenText(out.getvalue(), '1 {\n'
+                             '  1545008 {\n'
+                             '    15: 23\n'
+                             '  }\n'
+                             '  1547769 {\n'
+                             '    25: \"foo\"\n'
+                             '  }\n'
+                             '}\n')
     out.close()
 
   def testPrintMessageSetAsOneLine(self):
@@ -685,8 +664,7 @@
 
   def testParseMessageSet(self):
     message = unittest_pb2.TestAllTypes()
-    text = ('repeated_uint64: 1\n'
-            'repeated_uint64: 2\n')
+    text = ('repeated_uint64: 1\n' 'repeated_uint64: 2\n')
     text_format.Parse(text, message)
     self.assertEqual(1, message.repeated_uint64[0])
     self.assertEqual(2, message.repeated_uint64[1])
@@ -708,8 +686,7 @@
 
   def testParseMessageByFieldNumber(self):
     message = unittest_pb2.TestAllTypes()
-    text = ('34: 1\n'
-            'repeated_uint64: 2\n')
+    text = ('34: 1\n' 'repeated_uint64: 2\n')
     text_format.Parse(text, message, allow_field_number=True)
     self.assertEqual(1, message.repeated_uint64[0])
     self.assertEqual(2, message.repeated_uint64[1])
@@ -732,12 +709,9 @@
     # Can't parse field number without set allow_field_number=True.
     message = unittest_pb2.TestAllTypes()
     text = '34:1\n'
-    six.assertRaisesRegex(
-        self,
-        text_format.ParseError,
-        (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
-         r'"34".'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        r'1:1 : Message type "\w+.TestAllTypes" has no field named '
+        r'"34".'), text_format.Parse, text, message)
 
     # Can't parse if field number is not found.
     text = '1234:1\n'
@@ -746,7 +720,10 @@
         text_format.ParseError,
         (r'1:1 : Message type "\w+.TestAllTypes" has no field named '
          r'"1234".'),
-        text_format.Parse, text, message, allow_field_number=True)
+        text_format.Parse,
+        text,
+        message,
+        allow_field_number=True)
 
   def testPrintAllExtensions(self):
     message = unittest_pb2.TestAllExtensions()
@@ -824,7 +801,9 @@
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           'Invalid field value: }',
-                          text_format.Parse, malformed, message,
+                          text_format.Parse,
+                          malformed,
+                          message,
                           allow_unknown_extension=True)
 
     message = unittest_mset_pb2.TestMessageSetContainer()
@@ -836,7 +815,9 @@
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           'Invalid field value: "',
-                          text_format.Parse, malformed, message,
+                          text_format.Parse,
+                          malformed,
+                          message,
                           allow_unknown_extension=True)
 
     message = unittest_mset_pb2.TestMessageSetContainer()
@@ -848,7 +829,9 @@
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           'Invalid field value: "',
-                          text_format.Parse, malformed, message,
+                          text_format.Parse,
+                          malformed,
+                          message,
                           allow_unknown_extension=True)
 
     message = unittest_mset_pb2.TestMessageSetContainer()
@@ -860,7 +843,9 @@
     six.assertRaisesRegex(self,
                           text_format.ParseError,
                           '5:1 : Expected ">".',
-                          text_format.Parse, malformed, message,
+                          text_format.Parse,
+                          malformed,
+                          message,
                           allow_unknown_extension=True)
 
     # Don't allow unknown fields with allow_unknown_extension=True.
@@ -874,7 +859,9 @@
                           ('2:3 : Message type '
                            '"proto2_wireformat_unittest.TestMessageSet" has no'
                            ' field named "unknown_field".'),
-                          text_format.Parse, malformed, message,
+                          text_format.Parse,
+                          malformed,
+                          message,
                           allow_unknown_extension=True)
 
     # Parse known extension correcty.
@@ -896,67 +883,57 @@
   def testParseBadExtension(self):
     message = unittest_pb2.TestAllExtensions()
     text = '[unknown_extension]: 8\n'
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        '1:2 : Extension "unknown_extension" not registered.',
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError,
+                          '1:2 : Extension "unknown_extension" not registered.',
+                          text_format.Parse, text, message)
     message = unittest_pb2.TestAllTypes()
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        ('1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
-         'extensions.'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        '1:2 : Message type "protobuf_unittest.TestAllTypes" does not have '
+        'extensions.'), text_format.Parse, text, message)
 
   def testMergeDuplicateExtensionScalars(self):
     message = unittest_pb2.TestAllExtensions()
     text = ('[protobuf_unittest.optional_int32_extension]: 42 '
             '[protobuf_unittest.optional_int32_extension]: 67')
     text_format.Merge(text, message)
-    self.assertEqual(
-        67,
-        message.Extensions[unittest_pb2.optional_int32_extension])
+    self.assertEqual(67,
+                     message.Extensions[unittest_pb2.optional_int32_extension])
 
   def testParseDuplicateExtensionScalars(self):
     message = unittest_pb2.TestAllExtensions()
     text = ('[protobuf_unittest.optional_int32_extension]: 42 '
             '[protobuf_unittest.optional_int32_extension]: 67')
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        ('1:96 : Message type "protobuf_unittest.TestAllExtensions" '
-         'should not have multiple '
-         '"protobuf_unittest.optional_int32_extension" extensions.'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        '1:96 : Message type "protobuf_unittest.TestAllExtensions" '
+        'should not have multiple '
+        '"protobuf_unittest.optional_int32_extension" extensions.'),
+                          text_format.Parse, text, message)
 
   def testParseDuplicateNestedMessageScalars(self):
     message = unittest_pb2.TestAllTypes()
     text = ('optional_nested_message { bb: 1 } '
             'optional_nested_message { bb: 2 }')
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        ('1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
-         'should not have multiple "bb" fields.'),
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        '1:65 : Message type "protobuf_unittest.TestAllTypes.NestedMessage" '
+        'should not have multiple "bb" fields.'), text_format.Parse, text,
+                          message)
 
   def testParseDuplicateScalars(self):
     message = unittest_pb2.TestAllTypes()
-    text = ('optional_int32: 42 '
-            'optional_int32: 67')
-    six.assertRaisesRegex(self,
-        text_format.ParseError,
-        ('1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
-         'have multiple "optional_int32" fields.'),
-        text_format.Parse, text, message)
+    text = ('optional_int32: 42 ' 'optional_int32: 67')
+    six.assertRaisesRegex(self, text_format.ParseError, (
+        '1:36 : Message type "protobuf_unittest.TestAllTypes" should not '
+        'have multiple "optional_int32" fields.'), text_format.Parse, text,
+                          message)
 
   def testParseGroupNotClosed(self):
     message = unittest_pb2.TestAllTypes()
     text = 'RepeatedGroup: <'
-    six.assertRaisesRegex(self,
-        text_format.ParseError, '1:16 : Expected ">".',
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected ">".',
+                          text_format.Parse, text, message)
     text = 'RepeatedGroup: {'
-    six.assertRaisesRegex(self,
-        text_format.ParseError, '1:16 : Expected "}".',
-        text_format.Parse, text, message)
+    six.assertRaisesRegex(self, text_format.ParseError, '1:16 : Expected "}".',
+                          text_format.Parse, text, message)
 
   def testParseEmptyGroup(self):
     message = unittest_pb2.TestAllTypes()
@@ -1007,10 +984,197 @@
     self.assertEqual(-2**34, message.map_int64_int64[-2**33])
     self.assertEqual(456, message.map_uint32_uint32[123])
     self.assertEqual(2**34, message.map_uint64_uint64[2**33])
-    self.assertEqual("123", message.map_string_string["abc"])
+    self.assertEqual('123', message.map_string_string['abc'])
     self.assertEqual(5, message.map_int32_foreign_message[111].c)
 
 
+class Proto3Tests(unittest.TestCase):
+
+  def testPrintMessageExpandAny(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string"\n'
+        '  }\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyRepeated(self):
+    packed_message = unittest_pb2.OneString()
+    message = any_test_pb2.TestAny()
+    packed_message.data = 'string0'
+    message.repeated_any_value.add().Pack(packed_message)
+    packed_message.data = 'string1'
+    message.repeated_any_value.add().Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'repeated_any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string0"\n'
+        '  }\n'
+        '}\n'
+        'repeated_any_value {\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+        '    data: "string1"\n'
+        '  }\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyNoDescriptorPool(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message, descriptor_pool=None),
+        'any_value {\n'
+        '  type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+        '  value: "\\n\\006string"\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyDescriptorPoolMissingType(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    empty_pool = descriptor_pool.DescriptorPool()
+    self.assertEqual(
+        text_format.MessageToString(message, descriptor_pool=empty_pool),
+        'any_value {\n'
+        '  type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+        '  value: "\\n\\006string"\n'
+        '}\n')
+
+  def testPrintMessageExpandAnyPointyBrackets(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    pointy_brackets=True,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value <\n'
+        '  [type.googleapis.com/protobuf_unittest.OneString] <\n'
+        '    data: "string"\n'
+        '  >\n'
+        '>\n')
+
+  def testPrintMessageExpandAnyAsOneLine(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    as_one_line=True,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value {'
+        ' [type.googleapis.com/protobuf_unittest.OneString]'
+        ' { data: "string" } '
+        '}')
+
+  def testPrintMessageExpandAnyAsOneLinePointyBrackets(self):
+    packed_message = unittest_pb2.OneString()
+    packed_message.data = 'string'
+    message = any_test_pb2.TestAny()
+    message.any_value.Pack(packed_message)
+    self.assertEqual(
+        text_format.MessageToString(message,
+                                    as_one_line=True,
+                                    pointy_brackets=True,
+                                    descriptor_pool=descriptor_pool.Default()),
+        'any_value <'
+        ' [type.googleapis.com/protobuf_unittest.OneString]'
+        ' < data: "string" > '
+        '>')
+
+  def testMergeExpandedAny(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+  def testMergeExpandedAnyRepeated(self):
+    message = any_test_pb2.TestAny()
+    text = ('repeated_any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string0"\n'
+            '  }\n'
+            '}\n'
+            'repeated_any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string1"\n'
+            '  }\n'
+            '}\n')
+    text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+    packed_message = unittest_pb2.OneString()
+    message.repeated_any_value[0].Unpack(packed_message)
+    self.assertEqual('string0', packed_message.data)
+    message.repeated_any_value[1].Unpack(packed_message)
+    self.assertEqual('string1', packed_message.data)
+
+  def testMergeExpandedAnyPointyBrackets(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] <\n'
+            '    data: "string"\n'
+            '  >\n'
+            '}\n')
+    text_format.Merge(text, message, descriptor_pool=descriptor_pool.Default())
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+  def testMergeExpandedAnyNoDescriptorPool(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    with self.assertRaises(text_format.ParseError) as e:
+      text_format.Merge(text, message, descriptor_pool=None)
+    self.assertEqual(str(e.exception),
+                     'Descriptor pool required to parse expanded Any field')
+
+  def testMergeExpandedAnyDescriptorPoolMissingType(self):
+    message = any_test_pb2.TestAny()
+    text = ('any_value {\n'
+            '  [type.googleapis.com/protobuf_unittest.OneString] {\n'
+            '    data: "string"\n'
+            '  }\n'
+            '}\n')
+    with self.assertRaises(text_format.ParseError) as e:
+      empty_pool = descriptor_pool.DescriptorPool()
+      text_format.Merge(text, message, descriptor_pool=empty_pool)
+    self.assertEqual(
+        str(e.exception),
+        'Type protobuf_unittest.OneString not found in descriptor pool')
+
+  def testMergeUnexpandedAny(self):
+    text = ('any_value {\n'
+            '  type_url: "type.googleapis.com/protobuf_unittest.OneString"\n'
+            '  value: "\\n\\006string"\n'
+            '}\n')
+    message = any_test_pb2.TestAny()
+    text_format.Merge(text, message)
+    packed_message = unittest_pb2.OneString()
+    message.any_value.Unpack(packed_message)
+    self.assertEqual('string', packed_message.data)
+
+
 class TokenizerTest(unittest.TestCase):
 
   def testSimpleTokenCases(self):
@@ -1021,79 +1185,55 @@
             'ID9: 22 ID10: -111111111111111111 ID11: -22\n'
             'ID12: 2222222222222222222 ID13: 1.23456f ID14: 1.2e+2f '
             'false_bool:  0 true_BOOL:t \n true_bool1:  1 false_BOOL1:f ')
-    tokenizer = text_format._Tokenizer(text.splitlines())
-    methods = [(tokenizer.ConsumeIdentifier, 'identifier1'),
-               ':',
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    methods = [(tokenizer.ConsumeIdentifier, 'identifier1'), ':',
                (tokenizer.ConsumeString, 'string1'),
-               (tokenizer.ConsumeIdentifier, 'identifier2'),
-               ':',
-               (tokenizer.ConsumeInt32, 123),
-               (tokenizer.ConsumeIdentifier, 'identifier3'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'identifier2'), ':',
+               (tokenizer.ConsumeInteger, 123),
+               (tokenizer.ConsumeIdentifier, 'identifier3'), ':',
                (tokenizer.ConsumeString, 'string'),
-               (tokenizer.ConsumeIdentifier, 'identifiER_4'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'identifiER_4'), ':',
                (tokenizer.ConsumeFloat, 1.1e+2),
-               (tokenizer.ConsumeIdentifier, 'ID5'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'ID5'), ':',
                (tokenizer.ConsumeFloat, -0.23),
-               (tokenizer.ConsumeIdentifier, 'ID6'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'ID6'), ':',
                (tokenizer.ConsumeString, 'aaaa\'bbbb'),
-               (tokenizer.ConsumeIdentifier, 'ID7'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'ID7'), ':',
                (tokenizer.ConsumeString, 'aa\"bb'),
-               (tokenizer.ConsumeIdentifier, 'ID8'),
-               ':',
-               '{',
-               (tokenizer.ConsumeIdentifier, 'A'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'ID8'), ':', '{',
+               (tokenizer.ConsumeIdentifier, 'A'), ':',
                (tokenizer.ConsumeFloat, float('inf')),
-               (tokenizer.ConsumeIdentifier, 'B'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'B'), ':',
                (tokenizer.ConsumeFloat, -float('inf')),
-               (tokenizer.ConsumeIdentifier, 'C'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'C'), ':',
                (tokenizer.ConsumeBool, True),
-               (tokenizer.ConsumeIdentifier, 'D'),
-               ':',
-               (tokenizer.ConsumeBool, False),
-               '}',
-               (tokenizer.ConsumeIdentifier, 'ID9'),
-               ':',
-               (tokenizer.ConsumeUint32, 22),
-               (tokenizer.ConsumeIdentifier, 'ID10'),
-               ':',
-               (tokenizer.ConsumeInt64, -111111111111111111),
-               (tokenizer.ConsumeIdentifier, 'ID11'),
-               ':',
-               (tokenizer.ConsumeInt32, -22),
-               (tokenizer.ConsumeIdentifier, 'ID12'),
-               ':',
-               (tokenizer.ConsumeUint64, 2222222222222222222),
-               (tokenizer.ConsumeIdentifier, 'ID13'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'D'), ':',
+               (tokenizer.ConsumeBool, False), '}',
+               (tokenizer.ConsumeIdentifier, 'ID9'), ':',
+               (tokenizer.ConsumeInteger, 22),
+               (tokenizer.ConsumeIdentifier, 'ID10'), ':',
+               (tokenizer.ConsumeInteger, -111111111111111111),
+               (tokenizer.ConsumeIdentifier, 'ID11'), ':',
+               (tokenizer.ConsumeInteger, -22),
+               (tokenizer.ConsumeIdentifier, 'ID12'), ':',
+               (tokenizer.ConsumeInteger, 2222222222222222222),
+               (tokenizer.ConsumeIdentifier, 'ID13'), ':',
                (tokenizer.ConsumeFloat, 1.23456),
-               (tokenizer.ConsumeIdentifier, 'ID14'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'ID14'), ':',
                (tokenizer.ConsumeFloat, 1.2e+2),
-               (tokenizer.ConsumeIdentifier, 'false_bool'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'false_bool'), ':',
                (tokenizer.ConsumeBool, False),
-               (tokenizer.ConsumeIdentifier, 'true_BOOL'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'true_BOOL'), ':',
                (tokenizer.ConsumeBool, True),
-               (tokenizer.ConsumeIdentifier, 'true_bool1'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'true_bool1'), ':',
                (tokenizer.ConsumeBool, True),
-               (tokenizer.ConsumeIdentifier, 'false_BOOL1'),
-               ':',
+               (tokenizer.ConsumeIdentifier, 'false_BOOL1'), ':',
                (tokenizer.ConsumeBool, False)]
 
     i = 0
     while not tokenizer.AtEnd():
       m = methods[i]
-      if type(m) == str:
+      if isinstance(m, str):
         token = tokenizer.token
         self.assertEqual(token, m)
         tokenizer.NextToken()
@@ -1101,59 +1241,119 @@
         self.assertEqual(m[1], m[0]())
       i += 1
 
+  def testConsumeAbstractIntegers(self):
+    # This test only tests the failures in the integer parsing methods as well
+    # as the '0' special cases.
+    int64_max = (1 << 63) - 1
+    uint32_max = (1 << 32) - 1
+    text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(-1, tokenizer.ConsumeInteger())
+
+    self.assertEqual(uint32_max + 1, tokenizer.ConsumeInteger())
+
+    self.assertEqual(int64_max + 1, tokenizer.ConsumeInteger())
+    self.assertTrue(tokenizer.AtEnd())
+
+    text = '-0 0'
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertEqual(0, tokenizer.ConsumeInteger())
+    self.assertTrue(tokenizer.AtEnd())
+
   def testConsumeIntegers(self):
     # This test only tests the failures in the integer parsing methods as well
     # as the '0' special cases.
     int64_max = (1 << 63) - 1
     uint32_max = (1 << 32) - 1
     text = '-1 %d %d' % (uint32_max + 1, int64_max + 1)
-    tokenizer = text_format._Tokenizer(text.splitlines())
-    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
-    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint64)
-    self.assertEqual(-1, tokenizer.ConsumeInt32())
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint32, tokenizer)
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint64, tokenizer)
+    self.assertEqual(-1, text_format._ConsumeInt32(tokenizer))
 
-    self.assertRaises(text_format.ParseError, tokenizer.ConsumeUint32)
-    self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt32)
-    self.assertEqual(uint32_max + 1, tokenizer.ConsumeInt64())
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeUint32, tokenizer)
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeInt32, tokenizer)
+    self.assertEqual(uint32_max + 1, text_format._ConsumeInt64(tokenizer))
 
-    self.assertRaises(text_format.ParseError, tokenizer.ConsumeInt64)
-    self.assertEqual(int64_max + 1, tokenizer.ConsumeUint64())
+    self.assertRaises(text_format.ParseError,
+                      text_format._ConsumeInt64, tokenizer)
+    self.assertEqual(int64_max + 1, text_format._ConsumeUint64(tokenizer))
     self.assertTrue(tokenizer.AtEnd())
 
     text = '-0 -0 0 0'
-    tokenizer = text_format._Tokenizer(text.splitlines())
-    self.assertEqual(0, tokenizer.ConsumeUint32())
-    self.assertEqual(0, tokenizer.ConsumeUint64())
-    self.assertEqual(0, tokenizer.ConsumeUint32())
-    self.assertEqual(0, tokenizer.ConsumeUint64())
+    tokenizer = text_format.Tokenizer(text.splitlines())
+    self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint32(tokenizer))
+    self.assertEqual(0, text_format._ConsumeUint64(tokenizer))
     self.assertTrue(tokenizer.AtEnd())
 
   def testConsumeByteString(self):
     text = '"string1\''
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
 
     text = 'string1"'
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
 
     text = '\n"\\xt"'
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
 
     text = '\n"\\"'
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
 
     text = '\n"\\x"'
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeByteString)
 
   def testConsumeBool(self):
     text = 'not-a-bool'
-    tokenizer = text_format._Tokenizer(text.splitlines())
+    tokenizer = text_format.Tokenizer(text.splitlines())
     self.assertRaises(text_format.ParseError, tokenizer.ConsumeBool)
 
+  def testSkipComment(self):
+    tokenizer = text_format.Tokenizer('# some comment'.splitlines())
+    self.assertTrue(tokenizer.AtEnd())
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+  def testConsumeComment(self):
+    tokenizer = text_format.Tokenizer('# some comment'.splitlines(),
+                                      skip_comments=False)
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeTwoComments(self):
+    text = '# some comment\n# another comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertFalse(tokenizer.AtEnd())
+    self.assertEqual('# another comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
+  def testConsumeTrailingComment(self):
+    text = 'some_number: 4\n# some comment'
+    tokenizer = text_format.Tokenizer(text.splitlines(), skip_comments=False)
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+
+    self.assertEqual('some_number', tokenizer.ConsumeIdentifier())
+    self.assertEqual(tokenizer.token, ':')
+    tokenizer.NextToken()
+    self.assertRaises(text_format.ParseError, tokenizer.ConsumeComment)
+    self.assertEqual(4, tokenizer.ConsumeInteger())
+    self.assertFalse(tokenizer.AtEnd())
+
+    self.assertEqual('# some comment', tokenizer.ConsumeComment())
+    self.assertTrue(tokenizer.AtEnd())
+
 
 if __name__ == '__main__':
   unittest.main()
diff --git a/python/google/protobuf/json_format.py b/python/google/protobuf/json_format.py
index be6a9b6..bb6a199 100644
--- a/python/google/protobuf/json_format.py
+++ b/python/google/protobuf/json_format.py
@@ -53,6 +53,7 @@
 import six
 import sys
 
+from operator import methodcaller
 from google.protobuf import descriptor
 from google.protobuf import symbol_database
 
@@ -98,22 +99,8 @@
   Returns:
     A string containing the JSON formatted protocol buffer message.
   """
-  js = _MessageToJsonObject(message, including_default_value_fields)
-  return json.dumps(js, indent=2)
-
-
-def _MessageToJsonObject(message, including_default_value_fields):
-  """Converts message to an object according to Proto3 JSON Specification."""
-  message_descriptor = message.DESCRIPTOR
-  full_name = message_descriptor.full_name
-  if _IsWrapperMessage(message_descriptor):
-    return _WrapperMessageToJsonObject(message)
-  if full_name in _WKTJSONMETHODS:
-    return _WKTJSONMETHODS[full_name][0](
-        message, including_default_value_fields)
-  js = {}
-  return _RegularMessageToJsonObject(
-      message, js, including_default_value_fields)
+  printer = _Printer(including_default_value_fields)
+  return printer.ToJsonString(message)
 
 
 def _IsMapEntry(field):
@@ -122,115 +109,186 @@
           field.message_type.GetOptions().map_entry)
 
 
-def _RegularMessageToJsonObject(message, js, including_default_value_fields):
-  """Converts normal message according to Proto3 JSON Specification."""
-  fields = message.ListFields()
-  include_default = including_default_value_fields
+class _Printer(object):
+  """JSON format printer for protocol message."""
 
-  try:
-    for field, value in fields:
-      name = field.camelcase_name
-      if _IsMapEntry(field):
-        # Convert a map field.
-        v_field = field.message_type.fields_by_name['value']
-        js_map = {}
-        for key in value:
-          if isinstance(key, bool):
-            if key:
-              recorded_key = 'true'
-            else:
-              recorded_key = 'false'
-          else:
-            recorded_key = key
-          js_map[recorded_key] = _FieldToJsonObject(
-              v_field, value[key], including_default_value_fields)
-        js[name] = js_map
-      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
-        # Convert a repeated field.
-        js[name] = [_FieldToJsonObject(field, k, include_default)
-                    for k in value]
-      else:
-        js[name] = _FieldToJsonObject(field, value, include_default)
+  def __init__(self,
+               including_default_value_fields=False):
+    self.including_default_value_fields = including_default_value_fields
 
-    # Serialize default value if including_default_value_fields is True.
-    if including_default_value_fields:
-      message_descriptor = message.DESCRIPTOR
-      for field in message_descriptor.fields:
-        # Singular message fields and oneof fields will not be affected.
-        if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
-             field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
-            field.containing_oneof):
-          continue
+  def ToJsonString(self, message):
+    js = self._MessageToJsonObject(message)
+    return json.dumps(js, indent=2)
+
+  def _MessageToJsonObject(self, message):
+    """Converts message to an object according to Proto3 JSON Specification."""
+    message_descriptor = message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      return self._WrapperMessageToJsonObject(message)
+    if full_name in _WKTJSONMETHODS:
+      return methodcaller(_WKTJSONMETHODS[full_name][0], message)(self)
+    js = {}
+    return self._RegularMessageToJsonObject(message, js)
+
+  def _RegularMessageToJsonObject(self, message, js):
+    """Converts normal message according to Proto3 JSON Specification."""
+    fields = message.ListFields()
+
+    try:
+      for field, value in fields:
         name = field.camelcase_name
-        if name in js:
-          # Skip the field which has been serailized already.
-          continue
         if _IsMapEntry(field):
-          js[name] = {}
+          # Convert a map field.
+          v_field = field.message_type.fields_by_name['value']
+          js_map = {}
+          for key in value:
+            if isinstance(key, bool):
+              if key:
+                recorded_key = 'true'
+              else:
+                recorded_key = 'false'
+            else:
+              recorded_key = key
+            js_map[recorded_key] = self._FieldToJsonObject(
+                v_field, value[key])
+          js[name] = js_map
         elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
-          js[name] = []
+          # Convert a repeated field.
+          js[name] = [self._FieldToJsonObject(field, k)
+                      for k in value]
         else:
-          js[name] = _FieldToJsonObject(field, field.default_value)
+          js[name] = self._FieldToJsonObject(field, value)
 
-  except ValueError as e:
-    raise SerializeToJsonError(
-        'Failed to serialize {0} field: {1}.'.format(field.name, e))
+      # Serialize default value if including_default_value_fields is True.
+      if self.including_default_value_fields:
+        message_descriptor = message.DESCRIPTOR
+        for field in message_descriptor.fields:
+          # Singular message fields and oneof fields will not be affected.
+          if ((field.label != descriptor.FieldDescriptor.LABEL_REPEATED and
+               field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE) or
+              field.containing_oneof):
+            continue
+          name = field.camelcase_name
+          if name in js:
+            # Skip the field which has been serailized already.
+            continue
+          if _IsMapEntry(field):
+            js[name] = {}
+          elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+            js[name] = []
+          else:
+            js[name] = self._FieldToJsonObject(field, field.default_value)
 
-  return js
+    except ValueError as e:
+      raise SerializeToJsonError(
+          'Failed to serialize {0} field: {1}.'.format(field.name, e))
 
+    return js
 
-def _FieldToJsonObject(
-    field, value, including_default_value_fields=False):
-  """Converts field value according to Proto3 JSON Specification."""
-  if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-    return _MessageToJsonObject(value, including_default_value_fields)
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
-    enum_value = field.enum_type.values_by_number.get(value, None)
-    if enum_value is not None:
-      return enum_value.name
-    else:
-      raise SerializeToJsonError('Enum field contains an integer value '
-                                 'which can not mapped to an enum value.')
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
-    if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
-      # Use base64 Data encoding for bytes
-      return base64.b64encode(value).decode('utf-8')
-    else:
-      return value
-  elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
-    return bool(value)
-  elif field.cpp_type in _INT64_TYPES:
-    return str(value)
-  elif field.cpp_type in _FLOAT_TYPES:
-    if math.isinf(value):
-      if value < 0.0:
-        return _NEG_INFINITY
+  def _FieldToJsonObject(self, field, value):
+    """Converts field value according to Proto3 JSON Specification."""
+    if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+      return self._MessageToJsonObject(value)
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
+      enum_value = field.enum_type.values_by_number.get(value, None)
+      if enum_value is not None:
+        return enum_value.name
       else:
-        return _INFINITY
-    if math.isnan(value):
-      return _NAN
-  return value
+        raise SerializeToJsonError('Enum field contains an integer value '
+                                   'which can not mapped to an enum value.')
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_STRING:
+      if field.type == descriptor.FieldDescriptor.TYPE_BYTES:
+        # Use base64 Data encoding for bytes
+        return base64.b64encode(value).decode('utf-8')
+      else:
+        return value
+    elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_BOOL:
+      return bool(value)
+    elif field.cpp_type in _INT64_TYPES:
+      return str(value)
+    elif field.cpp_type in _FLOAT_TYPES:
+      if math.isinf(value):
+        if value < 0.0:
+          return _NEG_INFINITY
+        else:
+          return _INFINITY
+      if math.isnan(value):
+        return _NAN
+    return value
+
+  def _AnyMessageToJsonObject(self, message):
+    """Converts Any message according to Proto3 JSON Specification."""
+    if not message.ListFields():
+      return {}
+    # Must print @type first, use OrderedDict instead of {}
+    js = OrderedDict()
+    type_url = message.type_url
+    js['@type'] = type_url
+    sub_message = _CreateMessageFromTypeUrl(type_url)
+    sub_message.ParseFromString(message.value)
+    message_descriptor = sub_message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      js['value'] = self._WrapperMessageToJsonObject(sub_message)
+      return js
+    if full_name in _WKTJSONMETHODS:
+      js['value'] = methodcaller(_WKTJSONMETHODS[full_name][0],
+                                 sub_message)(self)
+      return js
+    return self._RegularMessageToJsonObject(sub_message, js)
+
+  def _GenericMessageToJsonObject(self, message):
+    """Converts message according to Proto3 JSON Specification."""
+    # Duration, Timestamp and FieldMask have ToJsonString method to do the
+    # convert. Users can also call the method directly.
+    return message.ToJsonString()
+
+  def _ValueMessageToJsonObject(self, message):
+    """Converts Value message according to Proto3 JSON Specification."""
+    which = message.WhichOneof('kind')
+    # If the Value message is not set treat as null_value when serialize
+    # to JSON. The parse back result will be different from original message.
+    if which is None or which == 'null_value':
+      return None
+    if which == 'list_value':
+      return self._ListValueMessageToJsonObject(message.list_value)
+    if which == 'struct_value':
+      value = message.struct_value
+    else:
+      value = getattr(message, which)
+    oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
+    return self._FieldToJsonObject(oneof_descriptor, value)
+
+  def _ListValueMessageToJsonObject(self, message):
+    """Converts ListValue message according to Proto3 JSON Specification."""
+    return [self._ValueMessageToJsonObject(value)
+            for value in message.values]
+
+  def _StructMessageToJsonObject(self, message):
+    """Converts Struct message according to Proto3 JSON Specification."""
+    fields = message.fields
+    ret = {}
+    for key in fields:
+      ret[key] = self._ValueMessageToJsonObject(fields[key])
+    return ret
+
+  def _WrapperMessageToJsonObject(self, message):
+    return self._FieldToJsonObject(
+        message.DESCRIPTOR.fields_by_name['value'], message.value)
 
 
-def _AnyMessageToJsonObject(message, including_default):
-  """Converts Any message according to Proto3 JSON Specification."""
-  if not message.ListFields():
-    return {}
-  # Must print @type first, use OrderedDict instead of {}
-  js = OrderedDict()
-  type_url = message.type_url
-  js['@type'] = type_url
-  sub_message = _CreateMessageFromTypeUrl(type_url)
-  sub_message.ParseFromString(message.value)
-  message_descriptor = sub_message.DESCRIPTOR
-  full_name = message_descriptor.full_name
-  if _IsWrapperMessage(message_descriptor):
-    js['value'] = _WrapperMessageToJsonObject(sub_message)
-    return js
-  if full_name in _WKTJSONMETHODS:
-    js['value'] = _WKTJSONMETHODS[full_name][0](sub_message, including_default)
-    return js
-  return _RegularMessageToJsonObject(sub_message, js, including_default)
+def _IsWrapperMessage(message_descriptor):
+  return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
+
+
+def _DuplicateChecker(js):
+  result = {}
+  for name, value in js:
+    if name in result:
+      raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name))
+    result[name] = value
+  return result
 
 
 def _CreateMessageFromTypeUrl(type_url):
@@ -247,69 +305,13 @@
   return message_class()
 
 
-def _GenericMessageToJsonObject(message, unused_including_default):
-  """Converts message by ToJsonString according to Proto3 JSON Specification."""
-  # Duration, Timestamp and FieldMask have ToJsonString method to do the
-  # convert. Users can also call the method directly.
-  return message.ToJsonString()
-
-
-def _ValueMessageToJsonObject(message, unused_including_default=False):
-  """Converts Value message according to Proto3 JSON Specification."""
-  which = message.WhichOneof('kind')
-  # If the Value message is not set treat as null_value when serialize
-  # to JSON. The parse back result will be different from original message.
-  if which is None or which == 'null_value':
-    return None
-  if which == 'list_value':
-    return _ListValueMessageToJsonObject(message.list_value)
-  if which == 'struct_value':
-    value = message.struct_value
-  else:
-    value = getattr(message, which)
-  oneof_descriptor = message.DESCRIPTOR.fields_by_name[which]
-  return _FieldToJsonObject(oneof_descriptor, value)
-
-
-def _ListValueMessageToJsonObject(message, unused_including_default=False):
-  """Converts ListValue message according to Proto3 JSON Specification."""
-  return [_ValueMessageToJsonObject(value)
-          for value in message.values]
-
-
-def _StructMessageToJsonObject(message, unused_including_default=False):
-  """Converts Struct message according to Proto3 JSON Specification."""
-  fields = message.fields
-  ret = {}
-  for key in fields:
-    ret[key] = _ValueMessageToJsonObject(fields[key])
-  return ret
-
-
-def _IsWrapperMessage(message_descriptor):
-  return message_descriptor.file.name == 'google/protobuf/wrappers.proto'
-
-
-def _WrapperMessageToJsonObject(message):
-  return _FieldToJsonObject(
-      message.DESCRIPTOR.fields_by_name['value'], message.value)
-
-
-def _DuplicateChecker(js):
-  result = {}
-  for name, value in js:
-    if name in result:
-      raise ParseError('Failed to load JSON: duplicate key {0}.'.format(name))
-    result[name] = value
-  return result
-
-
-def Parse(text, message):
+def Parse(text, message, ignore_unknown_fields=False):
   """Parses a JSON representation of a protocol message into a message.
 
   Args:
     text: Message JSON representation.
     message: A protocol beffer message to merge into.
+    ignore_unknown_fields: If True, do not raise errors for unknown fields.
 
   Returns:
     The same message passed as argument.
@@ -326,213 +328,217 @@
       js = json.loads(text, object_pairs_hook=_DuplicateChecker)
   except ValueError as e:
     raise ParseError('Failed to load JSON: {0}.'.format(str(e)))
-  _ConvertMessage(js, message)
+  parser = _Parser(ignore_unknown_fields)
+  parser.ConvertMessage(js, message)
   return message
 
 
-def _ConvertFieldValuePair(js, message):
-  """Convert field value pairs into regular message.
-
-  Args:
-    js: A JSON object to convert the field value pairs.
-    message: A regular protocol message to record the data.
-
-  Raises:
-    ParseError: In case of problems converting.
-  """
-  names = []
-  message_descriptor = message.DESCRIPTOR
-  for name in js:
-    try:
-      field = message_descriptor.fields_by_camelcase_name.get(name, None)
-      if not field:
-        raise ParseError(
-            'Message type "{0}" has no field named "{1}".'.format(
-                message_descriptor.full_name, name))
-      if name in names:
-        raise ParseError(
-            'Message type "{0}" should not have multiple "{1}" fields.'.format(
-                message.DESCRIPTOR.full_name, name))
-      names.append(name)
-      # Check no other oneof field is parsed.
-      if field.containing_oneof is not None:
-        oneof_name = field.containing_oneof.name
-        if oneof_name in names:
-          raise ParseError('Message type "{0}" should not have multiple "{1}" '
-                           'oneof fields.'.format(
-                               message.DESCRIPTOR.full_name, oneof_name))
-        names.append(oneof_name)
-
-      value = js[name]
-      if value is None:
-        message.ClearField(field.name)
-        continue
-
-      # Parse field value.
-      if _IsMapEntry(field):
-        message.ClearField(field.name)
-        _ConvertMapFieldValue(value, message, field)
-      elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
-        message.ClearField(field.name)
-        if not isinstance(value, list):
-          raise ParseError('repeated field {0} must be in [] which is '
-                           '{1}.'.format(name, value))
-        if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-          # Repeated message field.
-          for item in value:
-            sub_message = getattr(message, field.name).add()
-            # None is a null_value in Value.
-            if (item is None and
-                sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
-              raise ParseError('null is not allowed to be used as an element'
-                               ' in a repeated field.')
-            _ConvertMessage(item, sub_message)
-        else:
-          # Repeated scalar field.
-          for item in value:
-            if item is None:
-              raise ParseError('null is not allowed to be used as an element'
-                               ' in a repeated field.')
-            getattr(message, field.name).append(
-                _ConvertScalarFieldValue(item, field))
-      elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-        sub_message = getattr(message, field.name)
-        _ConvertMessage(value, sub_message)
-      else:
-        setattr(message, field.name, _ConvertScalarFieldValue(value, field))
-    except ParseError as e:
-      if field and field.containing_oneof is None:
-        raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
-      else:
-        raise ParseError(str(e))
-    except ValueError as e:
-      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
-    except TypeError as e:
-      raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
-
-
-def _ConvertMessage(value, message):
-  """Convert a JSON object into a message.
-
-  Args:
-    value: A JSON object.
-    message: A WKT or regular protocol message to record the data.
-
-  Raises:
-    ParseError: In case of convert problems.
-  """
-  message_descriptor = message.DESCRIPTOR
-  full_name = message_descriptor.full_name
-  if _IsWrapperMessage(message_descriptor):
-    _ConvertWrapperMessage(value, message)
-  elif full_name in _WKTJSONMETHODS:
-    _WKTJSONMETHODS[full_name][1](value, message)
-  else:
-    _ConvertFieldValuePair(value, message)
-
-
-def _ConvertAnyMessage(value, message):
-  """Convert a JSON representation into Any message."""
-  if isinstance(value, dict) and not value:
-    return
-  try:
-    type_url = value['@type']
-  except KeyError:
-    raise ParseError('@type is missing when parsing any message.')
-
-  sub_message = _CreateMessageFromTypeUrl(type_url)
-  message_descriptor = sub_message.DESCRIPTOR
-  full_name = message_descriptor.full_name
-  if _IsWrapperMessage(message_descriptor):
-    _ConvertWrapperMessage(value['value'], sub_message)
-  elif full_name in _WKTJSONMETHODS:
-    _WKTJSONMETHODS[full_name][1](value['value'], sub_message)
-  else:
-    del value['@type']
-    _ConvertFieldValuePair(value, sub_message)
-  # Sets Any message
-  message.value = sub_message.SerializeToString()
-  message.type_url = type_url
-
-
-def _ConvertGenericMessage(value, message):
-  """Convert a JSON representation into message with FromJsonString."""
-  # Durantion, Timestamp, FieldMask have FromJsonString method to do the
-  # convert. Users can also call the method directly.
-  message.FromJsonString(value)
-
-
 _INT_OR_FLOAT = six.integer_types + (float,)
 
 
-def _ConvertValueMessage(value, message):
-  """Convert a JSON representation into Value message."""
-  if isinstance(value, dict):
-    _ConvertStructMessage(value, message.struct_value)
-  elif isinstance(value, list):
-    _ConvertListValueMessage(value, message.list_value)
-  elif value is None:
-    message.null_value = 0
-  elif isinstance(value, bool):
-    message.bool_value = value
-  elif isinstance(value, six.string_types):
-    message.string_value = value
-  elif isinstance(value, _INT_OR_FLOAT):
-    message.number_value = value
-  else:
-    raise ParseError('Unexpected type for Value message.')
+class _Parser(object):
+  """JSON format parser for protocol message."""
 
+  def __init__(self,
+               ignore_unknown_fields):
+    self.ignore_unknown_fields = ignore_unknown_fields
 
-def _ConvertListValueMessage(value, message):
-  """Convert a JSON representation into ListValue message."""
-  if not isinstance(value, list):
-    raise ParseError(
-        'ListValue must be in [] which is {0}.'.format(value))
-  message.ClearField('values')
-  for item in value:
-    _ConvertValueMessage(item, message.values.add())
+  def ConvertMessage(self, value, message):
+    """Convert a JSON object into a message.
 
+    Args:
+      value: A JSON object.
+      message: A WKT or regular protocol message to record the data.
 
-def _ConvertStructMessage(value, message):
-  """Convert a JSON representation into Struct message."""
-  if not isinstance(value, dict):
-    raise ParseError(
-        'Struct must be in a dict which is {0}.'.format(value))
-  for key in value:
-    _ConvertValueMessage(value[key], message.fields[key])
-  return
-
-
-def _ConvertWrapperMessage(value, message):
-  """Convert a JSON representation into Wrapper message."""
-  field = message.DESCRIPTOR.fields_by_name['value']
-  setattr(message, 'value', _ConvertScalarFieldValue(value, field))
-
-
-def _ConvertMapFieldValue(value, message, field):
-  """Convert map field value for a message map field.
-
-  Args:
-    value: A JSON object to convert the map field value.
-    message: A protocol message to record the converted data.
-    field: The descriptor of the map field to be converted.
-
-  Raises:
-    ParseError: In case of convert problems.
-  """
-  if not isinstance(value, dict):
-    raise ParseError(
-        'Map field {0} must be in a dict which is {1}.'.format(
-            field.name, value))
-  key_field = field.message_type.fields_by_name['key']
-  value_field = field.message_type.fields_by_name['value']
-  for key in value:
-    key_value = _ConvertScalarFieldValue(key, key_field, True)
-    if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-      _ConvertMessage(value[key], getattr(message, field.name)[key_value])
+    Raises:
+      ParseError: In case of convert problems.
+    """
+    message_descriptor = message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      self._ConvertWrapperMessage(value, message)
+    elif full_name in _WKTJSONMETHODS:
+      methodcaller(_WKTJSONMETHODS[full_name][1], value, message)(self)
     else:
-      getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
-          value[key], value_field)
+      self._ConvertFieldValuePair(value, message)
+
+  def _ConvertFieldValuePair(self, js, message):
+    """Convert field value pairs into regular message.
+
+    Args:
+      js: A JSON object to convert the field value pairs.
+      message: A regular protocol message to record the data.
+
+    Raises:
+      ParseError: In case of problems converting.
+    """
+    names = []
+    message_descriptor = message.DESCRIPTOR
+    for name in js:
+      try:
+        field = message_descriptor.fields_by_camelcase_name.get(name, None)
+        if not field:
+          if self.ignore_unknown_fields:
+            continue
+          raise ParseError(
+              'Message type "{0}" has no field named "{1}".'.format(
+                  message_descriptor.full_name, name))
+        if name in names:
+          raise ParseError('Message type "{0}" should not have multiple '
+                           '"{1}" fields.'.format(
+                               message.DESCRIPTOR.full_name, name))
+        names.append(name)
+        # Check no other oneof field is parsed.
+        if field.containing_oneof is not None:
+          oneof_name = field.containing_oneof.name
+          if oneof_name in names:
+            raise ParseError('Message type "{0}" should not have multiple '
+                             '"{1}" oneof fields.'.format(
+                                 message.DESCRIPTOR.full_name, oneof_name))
+          names.append(oneof_name)
+
+        value = js[name]
+        if value is None:
+          message.ClearField(field.name)
+          continue
+
+        # Parse field value.
+        if _IsMapEntry(field):
+          message.ClearField(field.name)
+          self._ConvertMapFieldValue(value, message, field)
+        elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+          message.ClearField(field.name)
+          if not isinstance(value, list):
+            raise ParseError('repeated field {0} must be in [] which is '
+                             '{1}.'.format(name, value))
+          if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+            # Repeated message field.
+            for item in value:
+              sub_message = getattr(message, field.name).add()
+              # None is a null_value in Value.
+              if (item is None and
+                  sub_message.DESCRIPTOR.full_name != 'google.protobuf.Value'):
+                raise ParseError('null is not allowed to be used as an element'
+                                 ' in a repeated field.')
+              self.ConvertMessage(item, sub_message)
+          else:
+            # Repeated scalar field.
+            for item in value:
+              if item is None:
+                raise ParseError('null is not allowed to be used as an element'
+                                 ' in a repeated field.')
+              getattr(message, field.name).append(
+                  _ConvertScalarFieldValue(item, field))
+        elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+          sub_message = getattr(message, field.name)
+          self.ConvertMessage(value, sub_message)
+        else:
+          setattr(message, field.name, _ConvertScalarFieldValue(value, field))
+      except ParseError as e:
+        if field and field.containing_oneof is None:
+          raise ParseError('Failed to parse {0} field: {1}'.format(name, e))
+        else:
+          raise ParseError(str(e))
+      except ValueError as e:
+        raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+      except TypeError as e:
+        raise ParseError('Failed to parse {0} field: {1}.'.format(name, e))
+
+  def _ConvertAnyMessage(self, value, message):
+    """Convert a JSON representation into Any message."""
+    if isinstance(value, dict) and not value:
+      return
+    try:
+      type_url = value['@type']
+    except KeyError:
+      raise ParseError('@type is missing when parsing any message.')
+
+    sub_message = _CreateMessageFromTypeUrl(type_url)
+    message_descriptor = sub_message.DESCRIPTOR
+    full_name = message_descriptor.full_name
+    if _IsWrapperMessage(message_descriptor):
+      self._ConvertWrapperMessage(value['value'], sub_message)
+    elif full_name in _WKTJSONMETHODS:
+      methodcaller(
+          _WKTJSONMETHODS[full_name][1], value['value'], sub_message)(self)
+    else:
+      del value['@type']
+      self._ConvertFieldValuePair(value, sub_message)
+    # Sets Any message
+    message.value = sub_message.SerializeToString()
+    message.type_url = type_url
+
+  def _ConvertGenericMessage(self, value, message):
+    """Convert a JSON representation into message with FromJsonString."""
+    # Durantion, Timestamp, FieldMask have FromJsonString method to do the
+    # convert. Users can also call the method directly.
+    message.FromJsonString(value)
+
+  def _ConvertValueMessage(self, value, message):
+    """Convert a JSON representation into Value message."""
+    if isinstance(value, dict):
+      self._ConvertStructMessage(value, message.struct_value)
+    elif isinstance(value, list):
+      self. _ConvertListValueMessage(value, message.list_value)
+    elif value is None:
+      message.null_value = 0
+    elif isinstance(value, bool):
+      message.bool_value = value
+    elif isinstance(value, six.string_types):
+      message.string_value = value
+    elif isinstance(value, _INT_OR_FLOAT):
+      message.number_value = value
+    else:
+      raise ParseError('Unexpected type for Value message.')
+
+  def _ConvertListValueMessage(self, value, message):
+    """Convert a JSON representation into ListValue message."""
+    if not isinstance(value, list):
+      raise ParseError(
+          'ListValue must be in [] which is {0}.'.format(value))
+    message.ClearField('values')
+    for item in value:
+      self._ConvertValueMessage(item, message.values.add())
+
+  def _ConvertStructMessage(self, value, message):
+    """Convert a JSON representation into Struct message."""
+    if not isinstance(value, dict):
+      raise ParseError(
+          'Struct must be in a dict which is {0}.'.format(value))
+    for key in value:
+      self._ConvertValueMessage(value[key], message.fields[key])
+    return
+
+  def _ConvertWrapperMessage(self, value, message):
+    """Convert a JSON representation into Wrapper message."""
+    field = message.DESCRIPTOR.fields_by_name['value']
+    setattr(message, 'value', _ConvertScalarFieldValue(value, field))
+
+  def _ConvertMapFieldValue(self, value, message, field):
+    """Convert map field value for a message map field.
+
+    Args:
+      value: A JSON object to convert the map field value.
+      message: A protocol message to record the converted data.
+      field: The descriptor of the map field to be converted.
+
+    Raises:
+      ParseError: In case of convert problems.
+    """
+    if not isinstance(value, dict):
+      raise ParseError(
+          'Map field {0} must be in a dict which is {1}.'.format(
+              field.name, value))
+    key_field = field.message_type.fields_by_name['key']
+    value_field = field.message_type.fields_by_name['value']
+    for key in value:
+      key_value = _ConvertScalarFieldValue(key, key_field, True)
+      if value_field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
+        self.ConvertMessage(value[key], getattr(
+            message, field.name)[key_value])
+      else:
+        getattr(message, field.name)[key_value] = _ConvertScalarFieldValue(
+            value[key], value_field)
 
 
 def _ConvertScalarFieldValue(value, field, require_str=False):
@@ -641,18 +647,18 @@
   return value
 
 _WKTJSONMETHODS = {
-    'google.protobuf.Any': [_AnyMessageToJsonObject,
-                            _ConvertAnyMessage],
-    'google.protobuf.Duration': [_GenericMessageToJsonObject,
-                                 _ConvertGenericMessage],
-    'google.protobuf.FieldMask': [_GenericMessageToJsonObject,
-                                  _ConvertGenericMessage],
-    'google.protobuf.ListValue': [_ListValueMessageToJsonObject,
-                                  _ConvertListValueMessage],
-    'google.protobuf.Struct': [_StructMessageToJsonObject,
-                               _ConvertStructMessage],
-    'google.protobuf.Timestamp': [_GenericMessageToJsonObject,
-                                  _ConvertGenericMessage],
-    'google.protobuf.Value': [_ValueMessageToJsonObject,
-                              _ConvertValueMessage]
+    'google.protobuf.Any': ['_AnyMessageToJsonObject',
+                            '_ConvertAnyMessage'],
+    'google.protobuf.Duration': ['_GenericMessageToJsonObject',
+                                 '_ConvertGenericMessage'],
+    'google.protobuf.FieldMask': ['_GenericMessageToJsonObject',
+                                  '_ConvertGenericMessage'],
+    'google.protobuf.ListValue': ['_ListValueMessageToJsonObject',
+                                  '_ConvertListValueMessage'],
+    'google.protobuf.Struct': ['_StructMessageToJsonObject',
+                               '_ConvertStructMessage'],
+    'google.protobuf.Timestamp': ['_GenericMessageToJsonObject',
+                                  '_ConvertGenericMessage'],
+    'google.protobuf.Value': ['_ValueMessageToJsonObject',
+                              '_ConvertValueMessage']
 }
diff --git a/python/google/protobuf/pyext/descriptor.cc b/python/google/protobuf/pyext/descriptor.cc
index 2355753..e6ef5ef 100644
--- a/python/google/protobuf/pyext/descriptor.cc
+++ b/python/google/protobuf/pyext/descriptor.cc
@@ -172,12 +172,16 @@
 const FileDescriptor* GetFileDescriptor(const OneofDescriptor* descriptor) {
   return descriptor->containing_type()->file();
 }
+template<>
+const FileDescriptor* GetFileDescriptor(const MethodDescriptor* descriptor) {
+  return descriptor->service()->file();
+}
 
 // Converts options into a Python protobuf, and cache the result.
 //
 // This is a bit tricky because options can contain extension fields defined in
 // the same proto file. In this case the options parsed from the serialized_pb
-// have unkown fields, and we need to parse them again.
+// have unknown fields, and we need to parse them again.
 //
 // Always returns a new reference.
 template<class DescriptorClass>
@@ -204,11 +208,12 @@
       cdescriptor_pool::GetMessageClass(pool, message_type));
   if (message_class == NULL) {
     // The Options message was not found in the current DescriptorPool.
-    // In this case, there cannot be extensions to these options, and we can
-    // try to use the basic pool instead.
+    // This means that the pool cannot contain any extensions to the Options
+    // message either, so falling back to the basic pool we can only increase
+    // the chances of successfully parsing the options.
     PyErr_Clear();
-    message_class = cdescriptor_pool::GetMessageClass(
-      GetDefaultDescriptorPool(), message_type);
+    pool = GetDefaultDescriptorPool();
+    message_class = cdescriptor_pool::GetMessageClass(pool, message_type);
   }
   if (message_class == NULL) {
     PyErr_Format(PyExc_TypeError, "Could not retrieve class for Options: %s",
@@ -248,7 +253,7 @@
 
   // Cache the result.
   Py_INCREF(value.get());
-  (*pool->descriptor_options)[descriptor] = value.get();
+  (*descriptor_options)[descriptor] = value.get();
 
   return value.release();
 }
@@ -1091,7 +1096,7 @@
   0,                                    // tp_weaklistoffset
   0,                                    // tp_iter
   0,                                    // tp_iternext
-  enum_descriptor::Methods,             // tp_getset
+  enum_descriptor::Methods,             // tp_methods
   0,                                    // tp_members
   enum_descriptor::Getters,             // tp_getset
   &descriptor::PyBaseDescriptor_Type,   // tp_base
@@ -1275,6 +1280,10 @@
   return NewFileExtensionsByName(_GetDescriptor(self));
 }
 
+static PyObject* GetServicesByName(PyFileDescriptor* self, void *closure) {
+  return NewFileServicesByName(_GetDescriptor(self));
+}
+
 static PyObject* GetDependencies(PyFileDescriptor* self, void *closure) {
   return NewFileDependencies(_GetDescriptor(self));
 }
@@ -1324,6 +1333,7 @@
   { "enum_types_by_name", (getter)GetEnumTypesByName, NULL, "Enums by name"},
   { "extensions_by_name", (getter)GetExtensionsByName, NULL,
     "Extensions by name"},
+  { "services_by_name", (getter)GetServicesByName, NULL, "Services by name"},
   { "dependencies", (getter)GetDependencies, NULL, "Dependencies"},
   { "public_dependencies", (getter)GetPublicDependencies, NULL, "Dependencies"},
 
@@ -1452,16 +1462,45 @@
   }
 }
 
+static PyObject* GetHasOptions(PyBaseDescriptor *self, void *closure) {
+  const OneofOptions& options(_GetDescriptor(self)->options());
+  if (&options != &OneofOptions::default_instance()) {
+    Py_RETURN_TRUE;
+  } else {
+    Py_RETURN_FALSE;
+  }
+}
+static int SetHasOptions(PyBaseDescriptor *self, PyObject *value,
+                         void *closure) {
+  return CheckCalledFromGeneratedFile("has_options");
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static int SetOptions(PyBaseDescriptor *self, PyObject *value,
+                      void *closure) {
+  return CheckCalledFromGeneratedFile("_options");
+}
+
 static PyGetSetDef Getters[] = {
   { "name", (getter)GetName, NULL, "Name"},
   { "full_name", (getter)GetFullName, NULL, "Full name"},
   { "index", (getter)GetIndex, NULL, "Index"},
 
   { "containing_type", (getter)GetContainingType, NULL, "Containing type"},
+  { "has_options", (getter)GetHasOptions, (setter)SetHasOptions, "Has Options"},
+  { "_options", (getter)NULL, (setter)SetOptions, "Options"},
   { "fields", (getter)GetFields, NULL, "Fields"},
   {NULL}
 };
 
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
+  {NULL}
+};
+
 }  // namespace oneof_descriptor
 
 PyTypeObject PyOneofDescriptor_Type = {
@@ -1492,7 +1531,7 @@
   0,                                    // tp_weaklistoffset
   0,                                    // tp_iter
   0,                                    // tp_iternext
-  0,                                    // tp_methods
+  oneof_descriptor::Methods,            // tp_methods
   0,                                    // tp_members
   oneof_descriptor::Getters,            // tp_getset
   &descriptor::PyBaseDescriptor_Type,   // tp_base
@@ -1504,6 +1543,222 @@
       &PyOneofDescriptor_Type, oneof_descriptor, NULL);
 }
 
+namespace service_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const ServiceDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const ServiceDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetMethods(PyBaseDescriptor* self, void *closure) {
+  return NewServiceMethodsSeq(_GetDescriptor(self));
+}
+
+static PyObject* GetMethodsByName(PyBaseDescriptor* self, void *closure) {
+  return NewServiceMethodsByName(_GetDescriptor(self));
+}
+
+static PyObject* FindMethodByName(PyBaseDescriptor *self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const MethodDescriptor* method_descriptor =
+      _GetDescriptor(self)->FindMethodByName(string(name, name_size));
+  if (method_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
+    return NULL;
+  }
+
+  return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<ServiceDescriptorProto>(_GetDescriptor(self),
+                                                   target);
+}
+
+static PyGetSetDef Getters[] = {
+  { "name", (getter)GetName, NULL, "Name", NULL},
+  { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
+  { "index", (getter)GetIndex, NULL, "Index", NULL},
+
+  { "methods", (getter)GetMethods, NULL, "Methods", NULL},
+  { "methods_by_name", (getter)GetMethodsByName, NULL, "Methods by name", NULL},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS },
+  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+  { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O },
+  {NULL}
+};
+
+}  // namespace service_descriptor
+
+PyTypeObject PyServiceDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".ServiceDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // 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
+  "A Service Descriptor",               // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  service_descriptor::Methods,          // tp_methods
+  0,                                    // tp_members
+  service_descriptor::Getters,          // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyServiceDescriptor_FromDescriptor(
+    const ServiceDescriptor* service_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyServiceDescriptor_Type, service_descriptor, NULL);
+}
+
+namespace method_descriptor {
+
+// Unchecked accessor to the C++ pointer.
+static const MethodDescriptor* _GetDescriptor(
+    PyBaseDescriptor *self) {
+  return reinterpret_cast<const MethodDescriptor*>(self->descriptor);
+}
+
+static PyObject* GetName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->name());
+}
+
+static PyObject* GetFullName(PyBaseDescriptor* self, void *closure) {
+  return PyString_FromCppString(_GetDescriptor(self)->full_name());
+}
+
+static PyObject* GetIndex(PyBaseDescriptor *self, void *closure) {
+  return PyInt_FromLong(_GetDescriptor(self)->index());
+}
+
+static PyObject* GetContainingService(PyBaseDescriptor *self, void *closure) {
+  const ServiceDescriptor* containing_service =
+      _GetDescriptor(self)->service();
+  return PyServiceDescriptor_FromDescriptor(containing_service);
+}
+
+static PyObject* GetInputType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* input_type = _GetDescriptor(self)->input_type();
+  return PyMessageDescriptor_FromDescriptor(input_type);
+}
+
+static PyObject* GetOutputType(PyBaseDescriptor *self, void *closure) {
+  const Descriptor* output_type = _GetDescriptor(self)->output_type();
+  return PyMessageDescriptor_FromDescriptor(output_type);
+}
+
+static PyObject* GetOptions(PyBaseDescriptor *self) {
+  return GetOrBuildOptions(_GetDescriptor(self));
+}
+
+static PyObject* CopyToProto(PyBaseDescriptor *self, PyObject *target) {
+  return CopyToPythonProto<MethodDescriptorProto>(_GetDescriptor(self), target);
+}
+
+static PyGetSetDef Getters[] = {
+  { "name", (getter)GetName, NULL, "Name", NULL},
+  { "full_name", (getter)GetFullName, NULL, "Full name", NULL},
+  { "index", (getter)GetIndex, NULL, "Index", NULL},
+  { "containing_service", (getter)GetContainingService, NULL,
+    "Containing service", NULL},
+  { "input_type", (getter)GetInputType, NULL, "Input type", NULL},
+  { "output_type", (getter)GetOutputType, NULL, "Output type", NULL},
+  {NULL}
+};
+
+static PyMethodDef Methods[] = {
+  { "GetOptions", (PyCFunction)GetOptions, METH_NOARGS, },
+  { "CopyToProto", (PyCFunction)CopyToProto, METH_O, },
+  {NULL}
+};
+
+}  // namespace method_descriptor
+
+PyTypeObject PyMethodDescriptor_Type = {
+  PyVarObject_HEAD_INIT(&PyType_Type, 0)
+  FULL_MODULE_NAME ".MethodDescriptor",  // tp_name
+  sizeof(PyBaseDescriptor),             // tp_basicsize
+  0,                                    // tp_itemsize
+  0,                                    // 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
+  "A Method Descriptor",                // tp_doc
+  0,                                    // tp_traverse
+  0,                                    // tp_clear
+  0,                                    // tp_richcompare
+  0,                                    // tp_weaklistoffset
+  0,                                    // tp_iter
+  0,                                    // tp_iternext
+  method_descriptor::Methods,           // tp_methods
+  0,                                    // tp_members
+  method_descriptor::Getters,           // tp_getset
+  &descriptor::PyBaseDescriptor_Type,   // tp_base
+};
+
+PyObject* PyMethodDescriptor_FromDescriptor(
+    const MethodDescriptor* method_descriptor) {
+  return descriptor::NewInternedDescriptor(
+      &PyMethodDescriptor_Type, method_descriptor, NULL);
+}
+
 // Add a enum values to a type dictionary.
 static bool AddEnumValues(PyTypeObject *type,
                           const EnumDescriptor* enum_descriptor) {
@@ -1573,6 +1828,12 @@
   if (PyType_Ready(&PyOneofDescriptor_Type) < 0)
     return false;
 
+  if (PyType_Ready(&PyServiceDescriptor_Type) < 0)
+    return false;
+
+  if (PyType_Ready(&PyMethodDescriptor_Type) < 0)
+    return false;
+
   if (!InitDescriptorMappingTypes())
     return false;
 
diff --git a/python/google/protobuf/pyext/descriptor.h b/python/google/protobuf/pyext/descriptor.h
index eb99df1..1ae0e67 100644
--- a/python/google/protobuf/pyext/descriptor.h
+++ b/python/google/protobuf/pyext/descriptor.h
@@ -47,6 +47,8 @@
 extern PyTypeObject PyEnumValueDescriptor_Type;
 extern PyTypeObject PyFileDescriptor_Type;
 extern PyTypeObject PyOneofDescriptor_Type;
+extern PyTypeObject PyServiceDescriptor_Type;
+extern PyTypeObject PyMethodDescriptor_Type;
 
 // Wraps a Descriptor in a Python object.
 // The C++ pointer is usually borrowed from the global DescriptorPool.
@@ -60,6 +62,10 @@
 PyObject* PyOneofDescriptor_FromDescriptor(const OneofDescriptor* descriptor);
 PyObject* PyFileDescriptor_FromDescriptor(
     const FileDescriptor* file_descriptor);
+PyObject* PyServiceDescriptor_FromDescriptor(
+    const ServiceDescriptor* descriptor);
+PyObject* PyMethodDescriptor_FromDescriptor(
+    const MethodDescriptor* descriptor);
 
 // Alternate constructor of PyFileDescriptor, used when we already have a
 // serialized FileDescriptorProto that can be cached.
diff --git a/python/google/protobuf/pyext/descriptor_containers.cc b/python/google/protobuf/pyext/descriptor_containers.cc
index e505d81..d0aae9c 100644
--- a/python/google/protobuf/pyext/descriptor_containers.cc
+++ b/python/google/protobuf/pyext/descriptor_containers.cc
@@ -608,6 +608,24 @@
   return _NewObj_ByIndex(self, index);
 }
 
+static PyObject *
+SeqSubscript(PyContainer* self, PyObject* item) {
+  if (PyIndex_Check(item)) {
+      Py_ssize_t index;
+      index = PyNumber_AsSsize_t(item, PyExc_IndexError);
+      if (index == -1 && PyErr_Occurred())
+          return NULL;
+      return GetItem(self, index);
+  }
+  // Materialize the list and delegate the operation to it.
+  ScopedPyObjectPtr list(PyObject_CallFunctionObjArgs(
+      reinterpret_cast<PyObject*>(&PyList_Type), self, NULL));
+  if (list == NULL) {
+    return NULL;
+  }
+  return Py_TYPE(list.get())->tp_as_mapping->mp_subscript(list.get(), item);
+}
+
 // Returns the position of the item in the sequence, of -1 if not found.
 // This function never fails.
 int Find(PyContainer* self, PyObject* item) {
@@ -703,14 +721,20 @@
 };
 
 static PySequenceMethods SeqSequenceMethods = {
-    (lenfunc)Length,          // sq_length
-    0,                        // sq_concat
-    0,                        // sq_repeat
-    (ssizeargfunc)GetItem,    // sq_item
-    0,                        // sq_slice
-    0,                        // sq_ass_item
-    0,                        // sq_ass_slice
-    (objobjproc)SeqContains,  // sq_contains
+  (lenfunc)Length,          // sq_length
+  0,                        // sq_concat
+  0,                        // sq_repeat
+  (ssizeargfunc)GetItem,    // sq_item
+  0,                        // sq_slice
+  0,                        // sq_ass_item
+  0,                        // sq_ass_slice
+  (objobjproc)SeqContains,  // sq_contains
+};
+
+static PyMappingMethods SeqMappingMethods = {
+  (lenfunc)Length,           // mp_length
+  (binaryfunc)SeqSubscript,  // mp_subscript
+  0,                         // mp_ass_subscript
 };
 
 PyTypeObject DescriptorSequence_Type = {
@@ -726,7 +750,7 @@
   (reprfunc)ContainerRepr,              // tp_repr
   0,                                    // tp_as_number
   &SeqSequenceMethods,                  // tp_as_sequence
-  0,                                    // tp_as_mapping
+  &SeqMappingMethods,                   // tp_as_mapping
   0,                                    // tp_hash
   0,                                    // tp_call
   0,                                    // tp_str
@@ -1407,6 +1431,68 @@
 
 }  // namespace oneof_descriptor
 
+namespace service_descriptor {
+
+typedef const ServiceDescriptor* ParentDescriptor;
+
+static ParentDescriptor GetDescriptor(PyContainer* self) {
+  return reinterpret_cast<ParentDescriptor>(self->descriptor);
+}
+
+namespace methods {
+
+typedef const MethodDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->method_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindMethodByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->method(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyMethodDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "ServiceMethods",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace methods
+
+PyObject* NewServiceMethodsSeq(ParentDescriptor descriptor) {
+  return descriptor::NewSequence(&methods::ContainerDef, descriptor);
+}
+
+PyObject* NewServiceMethodsByName(ParentDescriptor descriptor) {
+  return descriptor::NewMappingByName(&methods::ContainerDef, descriptor);
+}
+
+}  // namespace service_descriptor
+
 namespace file_descriptor {
 
 typedef const FileDescriptor* ParentDescriptor;
@@ -1459,7 +1545,7 @@
 
 }  // namespace messages
 
-PyObject* NewFileMessageTypesByName(const FileDescriptor* descriptor) {
+PyObject* NewFileMessageTypesByName(ParentDescriptor descriptor) {
   return descriptor::NewMappingByName(&messages::ContainerDef, descriptor);
 }
 
@@ -1507,7 +1593,7 @@
 
 }  // namespace enums
 
-PyObject* NewFileEnumTypesByName(const FileDescriptor* descriptor) {
+PyObject* NewFileEnumTypesByName(ParentDescriptor descriptor) {
   return descriptor::NewMappingByName(&enums::ContainerDef, descriptor);
 }
 
@@ -1555,10 +1641,58 @@
 
 }  // namespace extensions
 
-PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor) {
+PyObject* NewFileExtensionsByName(ParentDescriptor descriptor) {
   return descriptor::NewMappingByName(&extensions::ContainerDef, descriptor);
 }
 
+namespace services {
+
+typedef const ServiceDescriptor* ItemDescriptor;
+
+static int Count(PyContainer* self) {
+  return GetDescriptor(self)->service_count();
+}
+
+static ItemDescriptor GetByName(PyContainer* self, const string& name) {
+  return GetDescriptor(self)->FindServiceByName(name);
+}
+
+static ItemDescriptor GetByIndex(PyContainer* self, int index) {
+  return GetDescriptor(self)->service(index);
+}
+
+static PyObject* NewObjectFromItem(ItemDescriptor item) {
+  return PyServiceDescriptor_FromDescriptor(item);
+}
+
+static const string& GetItemName(ItemDescriptor item) {
+  return item->name();
+}
+
+static int GetItemIndex(ItemDescriptor item) {
+  return item->index();
+}
+
+static DescriptorContainerDef ContainerDef = {
+  "FileServices",
+  (CountMethod)Count,
+  (GetByIndexMethod)GetByIndex,
+  (GetByNameMethod)GetByName,
+  (GetByCamelcaseNameMethod)NULL,
+  (GetByNumberMethod)NULL,
+  (NewObjectFromItemMethod)NewObjectFromItem,
+  (GetItemNameMethod)GetItemName,
+  (GetItemCamelcaseNameMethod)NULL,
+  (GetItemNumberMethod)NULL,
+  (GetItemIndexMethod)GetItemIndex,
+};
+
+}  // namespace services
+
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor) {
+  return descriptor::NewMappingByName(&services::ContainerDef, descriptor);
+}
+
 namespace dependencies {
 
 typedef const FileDescriptor* ItemDescriptor;
diff --git a/python/google/protobuf/pyext/descriptor_containers.h b/python/google/protobuf/pyext/descriptor_containers.h
index ce40747..83de07b 100644
--- a/python/google/protobuf/pyext/descriptor_containers.h
+++ b/python/google/protobuf/pyext/descriptor_containers.h
@@ -43,6 +43,7 @@
 class FileDescriptor;
 class EnumDescriptor;
 class OneofDescriptor;
+class ServiceDescriptor;
 
 namespace python {
 
@@ -89,10 +90,17 @@
 
 PyObject* NewFileExtensionsByName(const FileDescriptor* descriptor);
 
+PyObject* NewFileServicesByName(const FileDescriptor* descriptor);
+
 PyObject* NewFileDependencies(const FileDescriptor* descriptor);
 PyObject* NewFilePublicDependencies(const FileDescriptor* descriptor);
 }  // namespace file_descriptor
 
+namespace service_descriptor {
+PyObject* NewServiceMethodsSeq(const ServiceDescriptor* descriptor);
+PyObject* NewServiceMethodsByName(const ServiceDescriptor* descriptor);
+}  // namespace service_descriptor
+
 
 }  // namespace python
 }  // namespace protobuf
diff --git a/python/google/protobuf/pyext/descriptor_pool.cc b/python/google/protobuf/pyext/descriptor_pool.cc
index 1faff96..cfd9869 100644
--- a/python/google/protobuf/pyext/descriptor_pool.cc
+++ b/python/google/protobuf/pyext/descriptor_pool.cc
@@ -305,6 +305,40 @@
   return PyOneofDescriptor_FromDescriptor(oneof_descriptor);
 }
 
+PyObject* FindServiceByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const ServiceDescriptor* service_descriptor =
+      self->pool->FindServiceByName(string(name, name_size));
+  if (service_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find service %.200s", name);
+    return NULL;
+  }
+
+  return PyServiceDescriptor_FromDescriptor(service_descriptor);
+}
+
+PyObject* FindMethodByName(PyDescriptorPool* self, PyObject* arg) {
+  Py_ssize_t name_size;
+  char* name;
+  if (PyString_AsStringAndSize(arg, &name, &name_size) < 0) {
+    return NULL;
+  }
+
+  const MethodDescriptor* method_descriptor =
+      self->pool->FindMethodByName(string(name, name_size));
+  if (method_descriptor == NULL) {
+    PyErr_Format(PyExc_KeyError, "Couldn't find method %.200s", name);
+    return NULL;
+  }
+
+  return PyMethodDescriptor_FromDescriptor(method_descriptor);
+}
+
 PyObject* FindFileContainingSymbol(PyDescriptorPool* self, PyObject* arg) {
   Py_ssize_t name_size;
   char* name;
@@ -491,6 +525,10 @@
     "Searches for enum type descriptor by full name." },
   { "FindOneofByName", (PyCFunction)FindOneofByName, METH_O,
     "Searches for oneof descriptor by full name." },
+  { "FindServiceByName", (PyCFunction)FindServiceByName, METH_O,
+    "Searches for service descriptor by full name." },
+  { "FindMethodByName", (PyCFunction)FindMethodByName, METH_O,
+    "Searches for method descriptor by full name." },
 
   { "FindFileContainingSymbol", (PyCFunction)FindFileContainingSymbol, METH_O,
     "Gets the FileDescriptor containing the specified symbol." },
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc
index e022406..90438df 100644
--- a/python/google/protobuf/pyext/map_container.cc
+++ b/python/google/protobuf/pyext/map_container.cc
@@ -39,7 +39,6 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/map_field.h>
 #include <google/protobuf/map.h>
 #include <google/protobuf/message.h>
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc
index 83c151f..a9261f2 100644
--- a/python/google/protobuf/pyext/message.cc
+++ b/python/google/protobuf/pyext/message.cc
@@ -1593,23 +1593,20 @@
       parent_(parent) {}
 
   int VisitRepeatedCompositeContainer(RepeatedCompositeContainer* container) {
-    return repeated_composite_container::Release(
-        reinterpret_cast<RepeatedCompositeContainer*>(container));
+    return repeated_composite_container::Release(container);
   }
 
   int VisitRepeatedScalarContainer(RepeatedScalarContainer* container) {
-    return repeated_scalar_container::Release(
-        reinterpret_cast<RepeatedScalarContainer*>(container));
+    return repeated_scalar_container::Release(container);
   }
 
   int VisitMapContainer(MapContainer* container) {
-    return reinterpret_cast<MapContainer*>(container)->Release();
+    return container->Release();
   }
 
   int VisitCMessage(CMessage* cmessage,
                     const FieldDescriptor* field_descriptor) {
-    return ReleaseSubMessage(parent_, field_descriptor,
-        reinterpret_cast<CMessage*>(cmessage));
+    return ReleaseSubMessage(parent_, field_descriptor, cmessage);
   }
 
   CMessage* parent_;
@@ -1903,7 +1900,7 @@
 
 // Provide a method in the module to set allow_oversize_protos to a boolean
 // value. This method returns the newly value of allow_oversize_protos.
-static PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg) {
   if (!arg || !PyBool_Check(arg)) {
     PyErr_SetString(PyExc_TypeError,
                     "Argument to SetAllowOversizeProtos must be boolean");
@@ -3044,6 +3041,10 @@
       &PyFileDescriptor_Type));
   PyModule_AddObject(m, "OneofDescriptor", reinterpret_cast<PyObject*>(
       &PyOneofDescriptor_Type));
+  PyModule_AddObject(m, "ServiceDescriptor", reinterpret_cast<PyObject*>(
+      &PyServiceDescriptor_Type));
+  PyModule_AddObject(m, "MethodDescriptor", reinterpret_cast<PyObject*>(
+      &PyMethodDescriptor_Type));
 
   PyObject* enum_type_wrapper = PyImport_ImportModule(
       "google.protobuf.internal.enum_type_wrapper");
@@ -3081,53 +3082,4 @@
 }  // namespace python
 }  // namespace protobuf
 
-static PyMethodDef ModuleMethods[] = {
-  {"SetAllowOversizeProtos",
-    (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
-    METH_O, "Enable/disable oversize proto parsing."},
-  { NULL, NULL}
-};
-
-#if PY_MAJOR_VERSION >= 3
-static struct PyModuleDef _module = {
-  PyModuleDef_HEAD_INIT,
-  "_message",
-  google::protobuf::python::module_docstring,
-  -1,
-  ModuleMethods,  /* m_methods */
-  NULL,
-  NULL,
-  NULL,
-  NULL
-};
-#define INITFUNC PyInit__message
-#define INITFUNC_ERRORVAL NULL
-#else  // Python 2
-#define INITFUNC init_message
-#define INITFUNC_ERRORVAL
-#endif
-
-extern "C" {
-  PyMODINIT_FUNC INITFUNC(void) {
-    PyObject* m;
-#if PY_MAJOR_VERSION >= 3
-    m = PyModule_Create(&_module);
-#else
-    m = Py_InitModule3("_message", ModuleMethods,
-                       google::protobuf::python::module_docstring);
-#endif
-    if (m == NULL) {
-      return INITFUNC_ERRORVAL;
-    }
-
-    if (!google::protobuf::python::InitProto2MessageModule(m)) {
-      Py_DECREF(m);
-      return INITFUNC_ERRORVAL;
-    }
-
-#if PY_MAJOR_VERSION >= 3
-    return m;
-#endif
-  }
-}
 }  // namespace google
diff --git a/python/google/protobuf/pyext/message.h b/python/google/protobuf/pyext/message.h
index 3a4bec8..8b399e0 100644
--- a/python/google/protobuf/pyext/message.h
+++ b/python/google/protobuf/pyext/message.h
@@ -54,7 +54,7 @@
 
 #ifdef _SHARED_PTR_H
 using std::shared_ptr;
-using ::std::string;
+using std::string;
 #else
 using internal::shared_ptr;
 #endif
@@ -269,6 +269,8 @@
 // even in the case of extensions.
 PyDescriptorPool* GetDescriptorPoolForMessage(CMessage* message);
 
+PyObject* SetAllowOversizeProtos(PyObject* m, PyObject* arg);
+
 }  // namespace cmessage
 
 
@@ -354,6 +356,8 @@
 
 extern PyObject* PickleError_class;
 
+bool InitProto2MessageModule(PyObject *m);
+
 }  // namespace python
 }  // namespace protobuf
 
diff --git a/python/google/protobuf/pyext/message_module.cc b/python/google/protobuf/pyext/message_module.cc
new file mode 100644
index 0000000..d90d9de
--- /dev/null
+++ b/python/google/protobuf/pyext/message_module.cc
@@ -0,0 +1,88 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#include <google/protobuf/pyext/message.h>
+
+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.";
+
+static PyMethodDef ModuleMethods[] = {
+  {"SetAllowOversizeProtos",
+    (PyCFunction)google::protobuf::python::cmessage::SetAllowOversizeProtos,
+    METH_O, "Enable/disable oversize proto parsing."},
+  { NULL, NULL}
+};
+
+#if PY_MAJOR_VERSION >= 3
+static struct PyModuleDef _module = {
+  PyModuleDef_HEAD_INIT,
+  "_message",
+  module_docstring,
+  -1,
+  ModuleMethods,  /* m_methods */
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+#define INITFUNC PyInit__message
+#define INITFUNC_ERRORVAL NULL
+#else  // Python 2
+#define INITFUNC init_message
+#define INITFUNC_ERRORVAL
+#endif
+
+extern "C" {
+  PyMODINIT_FUNC INITFUNC(void) {
+    PyObject* m;
+#if PY_MAJOR_VERSION >= 3
+    m = PyModule_Create(&_module);
+#else
+    m = Py_InitModule3("_message", ModuleMethods,
+                       module_docstring);
+#endif
+    if (m == NULL) {
+      return INITFUNC_ERRORVAL;
+    }
+
+    if (!google::protobuf::python::InitProto2MessageModule(m)) {
+      Py_DECREF(m);
+      return INITFUNC_ERRORVAL;
+    }
+
+#if PY_MAJOR_VERSION >= 3
+    return m;
+#endif
+  }
+}
diff --git a/python/google/protobuf/text_format.py b/python/google/protobuf/text_format.py
index 6f1e3c8..c4b23c3 100755
--- a/python/google/protobuf/text_format.py
+++ b/python/google/protobuf/text_format.py
@@ -48,15 +48,15 @@
 import six
 
 if six.PY3:
-  long = int
+  long = int  # pylint: disable=redefined-builtin,invalid-name
 
+# pylint: disable=g-import-not-at-top
 from google.protobuf.internal import type_checkers
 from google.protobuf import descriptor
 from google.protobuf import text_encoding
 
-__all__ = ['MessageToString', 'PrintMessage', 'PrintField',
-           'PrintFieldValue', 'Merge']
-
+__all__ = ['MessageToString', 'PrintMessage', 'PrintField', 'PrintFieldValue',
+           'Merge']
 
 _INTEGER_CHECKERS = (type_checkers.Uint32ValueChecker(),
                      type_checkers.Int32ValueChecker(),
@@ -67,6 +67,7 @@
 _FLOAT_TYPES = frozenset([descriptor.FieldDescriptor.CPPTYPE_FLOAT,
                           descriptor.FieldDescriptor.CPPTYPE_DOUBLE])
 _QUOTES = frozenset(("'", '"'))
+_ANY_FULL_TYPE_NAME = 'google.protobuf.Any'
 
 
 class Error(Exception):
@@ -74,10 +75,30 @@
 
 
 class ParseError(Error):
-  """Thrown in case of text parsing error."""
+  """Thrown in case of text parsing or tokenizing error."""
+
+  def __init__(self, message=None, line=None, column=None):
+    if message is not None and line is not None:
+      loc = str(line)
+      if column is not None:
+        loc += ':{}'.format(column)
+      message = '{} : {}'.format(loc, message)
+    if message is not None:
+      super(ParseError, self).__init__(message)
+    else:
+      super(ParseError, self).__init__()
+    self._line = line
+    self._column = column
+
+  def GetLine(self):
+    return self._line
+
+  def GetColumn(self):
+    return self._column
 
 
 class TextWriter(object):
+
   def __init__(self, as_utf8):
     if six.PY2:
       self._writer = io.BytesIO()
@@ -97,9 +118,15 @@
     return self._writer.getvalue()
 
 
-def MessageToString(message, as_utf8=False, as_one_line=False,
-                    pointy_brackets=False, use_index_order=False,
-                    float_format=None, use_field_number=False):
+def MessageToString(message,
+                    as_utf8=False,
+                    as_one_line=False,
+                    pointy_brackets=False,
+                    use_index_order=False,
+                    float_format=None,
+                    use_field_number=False,
+                    descriptor_pool=None,
+                    indent=0):
   """Convert protobuf message to text format.
 
   Floating point values can be formatted compactly with 15 digits of
@@ -119,14 +146,16 @@
     float_format: If set, use this to specify floating point number formatting
       (per the "Format Specification Mini-Language"); otherwise, str() is used.
     use_field_number: If True, print field numbers instead of names.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
+    indent: The indent level, in terms of spaces, for pretty print.
 
   Returns:
     A string of the text formatted protocol buffer message.
   """
   out = TextWriter(as_utf8)
-  printer = _Printer(out, 0, as_utf8, as_one_line,
-                     pointy_brackets, use_index_order, float_format,
-                     use_field_number)
+  printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+                     use_index_order, float_format, use_field_number,
+                     descriptor_pool)
   printer.PrintMessage(message)
   result = out.getvalue()
   out.close()
@@ -141,39 +170,87 @@
           field.message_type.GetOptions().map_entry)
 
 
-def PrintMessage(message, out, indent=0, as_utf8=False, as_one_line=False,
-                 pointy_brackets=False, use_index_order=False,
-                 float_format=None, use_field_number=False):
-  printer = _Printer(out, indent, as_utf8, as_one_line,
-                     pointy_brackets, use_index_order, float_format,
-                     use_field_number)
+def PrintMessage(message,
+                 out,
+                 indent=0,
+                 as_utf8=False,
+                 as_one_line=False,
+                 pointy_brackets=False,
+                 use_index_order=False,
+                 float_format=None,
+                 use_field_number=False,
+                 descriptor_pool=None):
+  printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+                     use_index_order, float_format, use_field_number,
+                     descriptor_pool)
   printer.PrintMessage(message)
 
 
-def PrintField(field, value, out, indent=0, as_utf8=False, as_one_line=False,
-               pointy_brackets=False, use_index_order=False, float_format=None):
+def PrintField(field,
+               value,
+               out,
+               indent=0,
+               as_utf8=False,
+               as_one_line=False,
+               pointy_brackets=False,
+               use_index_order=False,
+               float_format=None):
   """Print a single field name/value pair."""
-  printer = _Printer(out, indent, as_utf8, as_one_line,
-                     pointy_brackets, use_index_order, float_format)
+  printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+                     use_index_order, float_format)
   printer.PrintField(field, value)
 
 
-def PrintFieldValue(field, value, out, indent=0, as_utf8=False,
-                    as_one_line=False, pointy_brackets=False,
+def PrintFieldValue(field,
+                    value,
+                    out,
+                    indent=0,
+                    as_utf8=False,
+                    as_one_line=False,
+                    pointy_brackets=False,
                     use_index_order=False,
                     float_format=None):
   """Print a single field value (not including name)."""
-  printer = _Printer(out, indent, as_utf8, as_one_line,
-                     pointy_brackets, use_index_order, float_format)
+  printer = _Printer(out, indent, as_utf8, as_one_line, pointy_brackets,
+                     use_index_order, float_format)
   printer.PrintFieldValue(field, value)
 
 
+def _BuildMessageFromTypeName(type_name, descriptor_pool):
+  """Returns a protobuf message instance.
+
+  Args:
+    type_name: Fully-qualified protobuf  message type name string.
+    descriptor_pool: DescriptorPool instance.
+
+  Returns:
+    A Message instance of type matching type_name, or None if the a Descriptor
+    wasn't found matching type_name.
+  """
+  # pylint: disable=g-import-not-at-top
+  from google.protobuf import message_factory
+  factory = message_factory.MessageFactory(descriptor_pool)
+  try:
+    message_descriptor = descriptor_pool.FindMessageTypeByName(type_name)
+  except KeyError:
+    return None
+  message_type = factory.GetPrototype(message_descriptor)
+  return message_type()
+
+
 class _Printer(object):
   """Text format printer for protocol message."""
 
-  def __init__(self, out, indent=0, as_utf8=False, as_one_line=False,
-               pointy_brackets=False, use_index_order=False, float_format=None,
-               use_field_number=False):
+  def __init__(self,
+               out,
+               indent=0,
+               as_utf8=False,
+               as_one_line=False,
+               pointy_brackets=False,
+               use_index_order=False,
+               float_format=None,
+               use_field_number=False,
+               descriptor_pool=None):
     """Initialize the Printer.
 
     Floating point values can be formatted compactly with 15 digits of
@@ -195,6 +272,7 @@
         (per the "Format Specification Mini-Language"); otherwise, str() is
         used.
       use_field_number: If True, print field numbers instead of names.
+      descriptor_pool: A DescriptorPool used to resolve Any types.
     """
     self.out = out
     self.indent = indent
@@ -204,6 +282,20 @@
     self.use_index_order = use_index_order
     self.float_format = float_format
     self.use_field_number = use_field_number
+    self.descriptor_pool = descriptor_pool
+
+  def _TryPrintAsAnyMessage(self, message):
+    """Serializes if message is a google.protobuf.Any field."""
+    packed_message = _BuildMessageFromTypeName(message.TypeName(),
+                                               self.descriptor_pool)
+    if packed_message:
+      packed_message.MergeFromString(message.value)
+      self.out.write('%s[%s]' % (self.indent * ' ', message.type_url))
+      self._PrintMessageFieldValue(packed_message)
+      self.out.write(' ' if self.as_one_line else '\n')
+      return True
+    else:
+      return False
 
   def PrintMessage(self, message):
     """Convert protobuf message to text format.
@@ -211,6 +303,9 @@
     Args:
       message: The protocol buffers message.
     """
+    if (message.DESCRIPTOR.full_name == _ANY_FULL_TYPE_NAME and
+        self.descriptor_pool and self._TryPrintAsAnyMessage(message)):
+      return
     fields = message.ListFields()
     if self.use_index_order:
       fields.sort(key=lambda x: x[0].index)
@@ -222,8 +317,8 @@
           # of this file to work around.
           #
           # TODO(haberman): refactor and optimize if this becomes an issue.
-          entry_submsg = field.message_type._concrete_class(
-              key=key, value=value[key])
+          entry_submsg = field.message_type._concrete_class(key=key,
+                                                            value=value[key])
           self.PrintField(field, entry_submsg)
       elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
         for element in value:
@@ -264,6 +359,25 @@
     else:
       out.write('\n')
 
+  def _PrintMessageFieldValue(self, value):
+    if self.pointy_brackets:
+      openb = '<'
+      closeb = '>'
+    else:
+      openb = '{'
+      closeb = '}'
+
+    if self.as_one_line:
+      self.out.write(' %s ' % openb)
+      self.PrintMessage(value)
+      self.out.write(closeb)
+    else:
+      self.out.write(' %s\n' % openb)
+      self.indent += 2
+      self.PrintMessage(value)
+      self.indent -= 2
+      self.out.write(' ' * self.indent + closeb)
+
   def PrintFieldValue(self, field, value):
     """Print a single field value (not including name).
 
@@ -274,24 +388,8 @@
       value: The value of the field.
     """
     out = self.out
-    if self.pointy_brackets:
-      openb = '<'
-      closeb = '>'
-    else:
-      openb = '{'
-      closeb = '}'
-
     if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
-      if self.as_one_line:
-        out.write(' %s ' % openb)
-        self.PrintMessage(value)
-        out.write(closeb)
-      else:
-        out.write(' %s\n' % openb)
-        self.indent += 2
-        self.PrintMessage(value)
-        self.indent -= 2
-        out.write(' ' * self.indent + closeb)
+      self._PrintMessageFieldValue(value)
     elif field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_ENUM:
       enum_value = field.enum_type.values_by_number.get(value, None)
       if enum_value is not None:
@@ -322,9 +420,11 @@
       out.write(str(value))
 
 
-def Parse(text, message,
-          allow_unknown_extension=False, allow_field_number=False):
-  """Parses an text representation of a protocol message into a message.
+def Parse(text,
+          message,
+          allow_unknown_extension=False,
+          allow_field_number=False):
+  """Parses a text representation of a protocol message into a message.
 
   Args:
     text: Message text representation.
@@ -341,13 +441,16 @@
   """
   if not isinstance(text, str):
     text = text.decode('utf-8')
-  return ParseLines(text.split('\n'), message, allow_unknown_extension,
-                    allow_field_number)
+  return ParseLines(
+      text.split('\n'), message, allow_unknown_extension, allow_field_number)
 
 
-def Merge(text, message, allow_unknown_extension=False,
-          allow_field_number=False):
-  """Parses an text representation of a protocol message into a message.
+def Merge(text,
+          message,
+          allow_unknown_extension=False,
+          allow_field_number=False,
+          descriptor_pool=None):
+  """Parses a text representation of a protocol message into a message.
 
   Like Parse(), but allows repeated values for a non-repeated field, and uses
   the last one.
@@ -358,6 +461,7 @@
     allow_unknown_extension: if True, skip over missing extensions and keep
       parsing
     allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
 
   Returns:
     The same message passed as argument.
@@ -365,13 +469,19 @@
   Raises:
     ParseError: On text parsing problems.
   """
-  return MergeLines(text.split('\n'), message, allow_unknown_extension,
-                    allow_field_number)
+  return MergeLines(
+      text.split('\n'),
+      message,
+      allow_unknown_extension,
+      allow_field_number,
+      descriptor_pool=descriptor_pool)
 
 
-def ParseLines(lines, message, allow_unknown_extension=False,
+def ParseLines(lines,
+               message,
+               allow_unknown_extension=False,
                allow_field_number=False):
-  """Parses an text representation of a protocol message into a message.
+  """Parses a text representation of a protocol message into a message.
 
   Args:
     lines: An iterable of lines of a message's text representation.
@@ -379,6 +489,7 @@
     allow_unknown_extension: if True, skip over missing extensions and keep
       parsing
     allow_field_number: if True, both field number and field name are allowed.
+    descriptor_pool: A DescriptorPool used to resolve Any types.
 
   Returns:
     The same message passed as argument.
@@ -390,9 +501,12 @@
   return parser.ParseLines(lines, message)
 
 
-def MergeLines(lines, message, allow_unknown_extension=False,
-               allow_field_number=False):
-  """Parses an text representation of a protocol message into a message.
+def MergeLines(lines,
+               message,
+               allow_unknown_extension=False,
+               allow_field_number=False,
+               descriptor_pool=None):
+  """Parses a text representation of a protocol message into a message.
 
   Args:
     lines: An iterable of lines of a message's text representation.
@@ -407,41 +521,47 @@
   Raises:
     ParseError: On text parsing problems.
   """
-  parser = _Parser(allow_unknown_extension, allow_field_number)
+  parser = _Parser(allow_unknown_extension,
+                   allow_field_number,
+                   descriptor_pool=descriptor_pool)
   return parser.MergeLines(lines, message)
 
 
 class _Parser(object):
   """Text format parser for protocol message."""
 
-  def __init__(self, allow_unknown_extension=False, allow_field_number=False):
+  def __init__(self,
+               allow_unknown_extension=False,
+               allow_field_number=False,
+               descriptor_pool=None):
     self.allow_unknown_extension = allow_unknown_extension
     self.allow_field_number = allow_field_number
+    self.descriptor_pool = descriptor_pool
 
   def ParseFromString(self, text, message):
-    """Parses an text representation of a protocol message into a message."""
+    """Parses a text representation of a protocol message into a message."""
     if not isinstance(text, str):
       text = text.decode('utf-8')
     return self.ParseLines(text.split('\n'), message)
 
   def ParseLines(self, lines, message):
-    """Parses an text representation of a protocol message into a message."""
+    """Parses a text representation of a protocol message into a message."""
     self._allow_multiple_scalars = False
     self._ParseOrMerge(lines, message)
     return message
 
   def MergeFromString(self, text, message):
-    """Merges an text representation of a protocol message into a message."""
+    """Merges a text representation of a protocol message into a message."""
     return self._MergeLines(text.split('\n'), message)
 
   def MergeLines(self, lines, message):
-    """Merges an text representation of a protocol message into a message."""
+    """Merges a text representation of a protocol message into a message."""
     self._allow_multiple_scalars = True
     self._ParseOrMerge(lines, message)
     return message
 
   def _ParseOrMerge(self, lines, message):
-    """Converts an text representation of a protocol message into a message.
+    """Converts a text representation of a protocol message into a message.
 
     Args:
       lines: Lines of a message's text representation.
@@ -450,7 +570,7 @@
     Raises:
       ParseError: On text parsing problems.
     """
-    tokenizer = _Tokenizer(lines)
+    tokenizer = Tokenizer(lines)
     while not tokenizer.AtEnd():
       self._MergeField(tokenizer, message)
 
@@ -491,13 +611,13 @@
               'Extension "%s" not registered.' % name)
       elif message_descriptor != field.containing_type:
         raise tokenizer.ParseErrorPreviousToken(
-            'Extension "%s" does not extend message type "%s".' % (
-                name, message_descriptor.full_name))
+            'Extension "%s" does not extend message type "%s".' %
+            (name, message_descriptor.full_name))
 
       tokenizer.Consume(']')
 
     else:
-      name = tokenizer.ConsumeIdentifier()
+      name = tokenizer.ConsumeIdentifierOrNumber()
       if self.allow_field_number and name.isdigit():
         number = ParseInteger(name, True, True)
         field = message_descriptor.fields_by_number.get(number, None)
@@ -520,8 +640,8 @@
 
       if not field:
         raise tokenizer.ParseErrorPreviousToken(
-            'Message type "%s" has no field named "%s".' % (
-                message_descriptor.full_name, name))
+            'Message type "%s" has no field named "%s".' %
+            (message_descriptor.full_name, name))
 
     if field:
       if not self._allow_multiple_scalars and field.containing_oneof:
@@ -532,9 +652,9 @@
         if which_oneof is not None and which_oneof != field.name:
           raise tokenizer.ParseErrorPreviousToken(
               'Field "%s" is specified along with field "%s", another member '
-              'of oneof "%s" for message type "%s".' % (
-                  field.name, which_oneof, field.containing_oneof.name,
-                  message_descriptor.full_name))
+              'of oneof "%s" for message type "%s".' %
+              (field.name, which_oneof, field.containing_oneof.name,
+               message_descriptor.full_name))
 
       if field.cpp_type == descriptor.FieldDescriptor.CPPTYPE_MESSAGE:
         tokenizer.TryConsume(':')
@@ -543,12 +663,13 @@
         tokenizer.Consume(':')
         merger = self._MergeScalarField
 
-      if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED
-          and tokenizer.TryConsume('[')):
+      if (field.label == descriptor.FieldDescriptor.LABEL_REPEATED and
+          tokenizer.TryConsume('[')):
         # Short repeated format, e.g. "foo: [1, 2, 3]"
         while True:
           merger(tokenizer, message, field)
-          if tokenizer.TryConsume(']'): break
+          if tokenizer.TryConsume(']'):
+            break
           tokenizer.Consume(',')
 
       else:
@@ -563,6 +684,21 @@
     if not tokenizer.TryConsume(','):
       tokenizer.TryConsume(';')
 
+  def _ConsumeAnyTypeUrl(self, tokenizer):
+    """Consumes a google.protobuf.Any type URL and returns the type name."""
+    # Consume "type.googleapis.com/".
+    tokenizer.ConsumeIdentifier()
+    tokenizer.Consume('.')
+    tokenizer.ConsumeIdentifier()
+    tokenizer.Consume('.')
+    tokenizer.ConsumeIdentifier()
+    tokenizer.Consume('/')
+    # Consume the fully-qualified type name.
+    name = [tokenizer.ConsumeIdentifier()]
+    while tokenizer.TryConsume('.'):
+      name.append(tokenizer.ConsumeIdentifier())
+    return '.'.join(name)
+
   def _MergeMessageField(self, tokenizer, message, field):
     """Merges a single scalar field into a message.
 
@@ -582,7 +718,34 @@
       tokenizer.Consume('{')
       end_token = '}'
 
-    if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+    if (field.message_type.full_name == _ANY_FULL_TYPE_NAME and
+        tokenizer.TryConsume('[')):
+      packed_type_name = self._ConsumeAnyTypeUrl(tokenizer)
+      tokenizer.Consume(']')
+      tokenizer.TryConsume(':')
+      if tokenizer.TryConsume('<'):
+        expanded_any_end_token = '>'
+      else:
+        tokenizer.Consume('{')
+        expanded_any_end_token = '}'
+      if not self.descriptor_pool:
+        raise ParseError('Descriptor pool required to parse expanded Any field')
+      expanded_any_sub_message = _BuildMessageFromTypeName(packed_type_name,
+                                                           self.descriptor_pool)
+      if not expanded_any_sub_message:
+        raise ParseError('Type %s not found in descriptor pool' %
+                         packed_type_name)
+      while not tokenizer.TryConsume(expanded_any_end_token):
+        if tokenizer.AtEnd():
+          raise tokenizer.ParseErrorPreviousToken('Expected "%s".' %
+                                                  (expanded_any_end_token,))
+        self._MergeField(tokenizer, expanded_any_sub_message)
+      if field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
+        any_message = getattr(message, field.name).add()
+      else:
+        any_message = getattr(message, field.name)
+      any_message.Pack(expanded_any_sub_message)
+    elif field.label == descriptor.FieldDescriptor.LABEL_REPEATED:
       if field.is_extension:
         sub_message = message.Extensions[field].add()
       elif is_map_entry:
@@ -628,17 +791,17 @@
     if field.type in (descriptor.FieldDescriptor.TYPE_INT32,
                       descriptor.FieldDescriptor.TYPE_SINT32,
                       descriptor.FieldDescriptor.TYPE_SFIXED32):
-      value = tokenizer.ConsumeInt32()
+      value = _ConsumeInt32(tokenizer)
     elif field.type in (descriptor.FieldDescriptor.TYPE_INT64,
                         descriptor.FieldDescriptor.TYPE_SINT64,
                         descriptor.FieldDescriptor.TYPE_SFIXED64):
-      value = tokenizer.ConsumeInt64()
+      value = _ConsumeInt64(tokenizer)
     elif field.type in (descriptor.FieldDescriptor.TYPE_UINT32,
                         descriptor.FieldDescriptor.TYPE_FIXED32):
-      value = tokenizer.ConsumeUint32()
+      value = _ConsumeUint32(tokenizer)
     elif field.type in (descriptor.FieldDescriptor.TYPE_UINT64,
                         descriptor.FieldDescriptor.TYPE_FIXED64):
-      value = tokenizer.ConsumeUint64()
+      value = _ConsumeUint64(tokenizer)
     elif field.type in (descriptor.FieldDescriptor.TYPE_FLOAT,
                         descriptor.FieldDescriptor.TYPE_DOUBLE):
       value = tokenizer.ConsumeFloat()
@@ -753,13 +916,12 @@
     return
 
   if (not tokenizer.TryConsumeIdentifier() and
-      not tokenizer.TryConsumeInt64() and
-      not tokenizer.TryConsumeUint64() and
+      not _TryConsumeInt64(tokenizer) and not _TryConsumeUint64(tokenizer) and
       not tokenizer.TryConsumeFloat()):
     raise ParseError('Invalid field value: ' + tokenizer.token)
 
 
-class _Tokenizer(object):
+class Tokenizer(object):
   """Protocol buffer text representation tokenizer.
 
   This class handles the lower level string parsing by splitting it into
@@ -768,17 +930,20 @@
   It was directly ported from the Java protocol buffer API.
   """
 
-  _WHITESPACE = re.compile('(\\s|(#.*$))+', re.MULTILINE)
+  _WHITESPACE = re.compile(r'\s+')
+  _COMMENT = re.compile(r'(\s*#.*$)', re.MULTILINE)
+  _WHITESPACE_OR_COMMENT = re.compile(r'(\s|(#.*$))+', re.MULTILINE)
   _TOKEN = re.compile('|'.join([
-      r'[a-zA-Z_][0-9a-zA-Z_+-]*',             # an identifier
+      r'[a-zA-Z_][0-9a-zA-Z_+-]*',  # an identifier
       r'([0-9+-]|(\.[0-9]))[0-9a-zA-Z_.+-]*',  # a number
-  ] + [                                        # quoted str for each quote mark
+  ] + [  # quoted str for each quote mark
       r'{qt}([^{qt}\n\\]|\\.)*({qt}|\\?$)'.format(qt=mark) for mark in _QUOTES
   ]))
 
-  _IDENTIFIER = re.compile(r'\w+')
+  _IDENTIFIER = re.compile(r'[^\d\W]\w*')
+  _IDENTIFIER_OR_NUMBER = re.compile(r'\w+')
 
-  def __init__(self, lines):
+  def __init__(self, lines, skip_comments=True):
     self._position = 0
     self._line = -1
     self._column = 0
@@ -789,6 +954,9 @@
     self._previous_line = 0
     self._previous_column = 0
     self._more_lines = True
+    self._skip_comments = skip_comments
+    self._whitespace_pattern = (skip_comments and self._WHITESPACE_OR_COMMENT
+                                or self._WHITESPACE)
     self._SkipWhitespace()
     self.NextToken()
 
@@ -818,7 +986,7 @@
   def _SkipWhitespace(self):
     while True:
       self._PopLine()
-      match = self._WHITESPACE.match(self._current_line, self._column)
+      match = self._whitespace_pattern.match(self._current_line, self._column)
       if not match:
         break
       length = len(match.group(0))
@@ -848,7 +1016,14 @@
       ParseError: If the text couldn't be consumed.
     """
     if not self.TryConsume(token):
-      raise self._ParseError('Expected "%s".' % token)
+      raise self.ParseError('Expected "%s".' % token)
+
+  def ConsumeComment(self):
+    result = self.token
+    if not self._COMMENT.match(result):
+      raise self.ParseError('Expected comment.')
+    self.NextToken()
+    return result
 
   def TryConsumeIdentifier(self):
     try:
@@ -868,85 +1043,55 @@
     """
     result = self.token
     if not self._IDENTIFIER.match(result):
-      raise self._ParseError('Expected identifier.')
+      raise self.ParseError('Expected identifier.')
     self.NextToken()
     return result
 
-  def ConsumeInt32(self):
-    """Consumes a signed 32bit integer number.
-
-    Returns:
-      The integer parsed.
-
-    Raises:
-      ParseError: If a signed 32bit integer couldn't be consumed.
-    """
+  def TryConsumeIdentifierOrNumber(self):
     try:
-      result = ParseInteger(self.token, is_signed=True, is_long=False)
-    except ValueError as e:
-      raise self._ParseError(str(e))
-    self.NextToken()
-    return result
-
-  def ConsumeUint32(self):
-    """Consumes an unsigned 32bit integer number.
-
-    Returns:
-      The integer parsed.
-
-    Raises:
-      ParseError: If an unsigned 32bit integer couldn't be consumed.
-    """
-    try:
-      result = ParseInteger(self.token, is_signed=False, is_long=False)
-    except ValueError as e:
-      raise self._ParseError(str(e))
-    self.NextToken()
-    return result
-
-  def TryConsumeInt64(self):
-    try:
-      self.ConsumeInt64()
+      self.ConsumeIdentifierOrNumber()
       return True
     except ParseError:
       return False
 
-  def ConsumeInt64(self):
-    """Consumes a signed 64bit integer number.
+  def ConsumeIdentifierOrNumber(self):
+    """Consumes protocol message field identifier.
 
     Returns:
-      The integer parsed.
+      Identifier string.
 
     Raises:
-      ParseError: If a signed 64bit integer couldn't be consumed.
+      ParseError: If an identifier couldn't be consumed.
     """
-    try:
-      result = ParseInteger(self.token, is_signed=True, is_long=True)
-    except ValueError as e:
-      raise self._ParseError(str(e))
+    result = self.token
+    if not self._IDENTIFIER_OR_NUMBER.match(result):
+      raise self.ParseError('Expected identifier or number.')
     self.NextToken()
     return result
 
-  def TryConsumeUint64(self):
+  def TryConsumeInteger(self):
     try:
-      self.ConsumeUint64()
+      # Note: is_long only affects value type, not whether an error is raised.
+      self.ConsumeInteger()
       return True
     except ParseError:
       return False
 
-  def ConsumeUint64(self):
-    """Consumes an unsigned 64bit integer number.
+  def ConsumeInteger(self, is_long=False):
+    """Consumes an integer number.
 
+    Args:
+      is_long: True if the value should be returned as a long integer.
     Returns:
       The integer parsed.
 
     Raises:
-      ParseError: If an unsigned 64bit integer couldn't be consumed.
+      ParseError: If an integer couldn't be consumed.
     """
     try:
-      result = ParseInteger(self.token, is_signed=False, is_long=True)
+      result = _ParseAbstractInteger(self.token, is_long=is_long)
     except ValueError as e:
-      raise self._ParseError(str(e))
+      raise self.ParseError(str(e))
     self.NextToken()
     return result
 
@@ -969,7 +1114,7 @@
     try:
       result = ParseFloat(self.token)
     except ValueError as e:
-      raise self._ParseError(str(e))
+      raise self.ParseError(str(e))
     self.NextToken()
     return result
 
@@ -985,7 +1130,7 @@
     try:
       result = ParseBool(self.token)
     except ValueError as e:
-      raise self._ParseError(str(e))
+      raise self.ParseError(str(e))
     self.NextToken()
     return result
 
@@ -1039,15 +1184,15 @@
     """
     text = self.token
     if len(text) < 1 or text[0] not in _QUOTES:
-      raise self._ParseError('Expected string but found: %r' % (text,))
+      raise self.ParseError('Expected string but found: %r' % (text,))
 
     if len(text) < 2 or text[-1] != text[0]:
-      raise self._ParseError('String missing ending quote: %r' % (text,))
+      raise self.ParseError('String missing ending quote: %r' % (text,))
 
     try:
       result = text_encoding.CUnescape(text[1:-1])
     except ValueError as e:
-      raise self._ParseError(str(e))
+      raise self.ParseError(str(e))
     self.NextToken()
     return result
 
@@ -1055,7 +1200,7 @@
     try:
       result = ParseEnum(field, self.token)
     except ValueError as e:
-      raise self._ParseError(str(e))
+      raise self.ParseError(str(e))
     self.NextToken()
     return result
 
@@ -1068,16 +1213,15 @@
     Returns:
       A ParseError instance.
     """
-    return ParseError('%d:%d : %s' % (
-        self._previous_line + 1, self._previous_column + 1, message))
+    return ParseError(message, self._previous_line + 1,
+                      self._previous_column + 1)
 
-  def _ParseError(self, message):
+  def ParseError(self, message):
     """Creates and *returns* a ParseError for the current token."""
-    return ParseError('%d:%d : %s' % (
-        self._line + 1, self._column + 1, message))
+    return ParseError(message, self._line + 1, self._column + 1)
 
   def _StringParseError(self, e):
-    return self._ParseError('Couldn\'t parse string: ' + str(e))
+    return self.ParseError('Couldn\'t parse string: ' + str(e))
 
   def NextToken(self):
     """Reads the next meaningful token."""
@@ -1092,12 +1236,124 @@
       return
 
     match = self._TOKEN.match(self._current_line, self._column)
+    if not match and not self._skip_comments:
+      match = self._COMMENT.match(self._current_line, self._column)
     if match:
       token = match.group(0)
       self.token = token
     else:
       self.token = self._current_line[self._column]
 
+# Aliased so it can still be accessed by current visibility violators.
+# TODO(dbarnett): Migrate violators to textformat_tokenizer.
+_Tokenizer = Tokenizer  # pylint: disable=invalid-name
+
+
+def _ConsumeInt32(tokenizer):
+  """Consumes a signed 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If a signed 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=True, is_long=False)
+
+
+def _ConsumeUint32(tokenizer):
+  """Consumes an unsigned 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an unsigned 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=False, is_long=False)
+
+
+def _TryConsumeInt64(tokenizer):
+  try:
+    _ConsumeInt64(tokenizer)
+    return True
+  except ParseError:
+    return False
+
+
+def _ConsumeInt64(tokenizer):
+  """Consumes a signed 32bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If a signed 32bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=True, is_long=True)
+
+
+def _TryConsumeUint64(tokenizer):
+  try:
+    _ConsumeUint64(tokenizer)
+    return True
+  except ParseError:
+    return False
+
+
+def _ConsumeUint64(tokenizer):
+  """Consumes an unsigned 64bit integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an unsigned 64bit integer couldn't be consumed.
+  """
+  return _ConsumeInteger(tokenizer, is_signed=False, is_long=True)
+
+
+def _TryConsumeInteger(tokenizer, is_signed=False, is_long=False):
+  try:
+    _ConsumeInteger(tokenizer, is_signed=is_signed, is_long=is_long)
+    return True
+  except ParseError:
+    return False
+
+
+def _ConsumeInteger(tokenizer, is_signed=False, is_long=False):
+  """Consumes an integer number from tokenizer.
+
+  Args:
+    tokenizer: A tokenizer used to parse the number.
+    is_signed: True if a signed integer must be parsed.
+    is_long: True if a long integer must be parsed.
+
+  Returns:
+    The integer parsed.
+
+  Raises:
+    ParseError: If an integer with given characteristics couldn't be consumed.
+  """
+  try:
+    result = ParseInteger(tokenizer.token, is_signed=is_signed, is_long=is_long)
+  except ValueError as e:
+    raise tokenizer.ParseError(str(e))
+  tokenizer.NextToken()
+  return result
+
 
 def ParseInteger(text, is_signed=False, is_long=False):
   """Parses an integer.
@@ -1114,16 +1370,7 @@
     ValueError: Thrown Iff the text is not a valid integer.
   """
   # Do the actual parsing. Exception handling is propagated to caller.
-  try:
-    # We force 32-bit values to int and 64-bit values to long to make
-    # alternate implementations where the distinction is more significant
-    # (e.g. the C++ implementation) simpler.
-    if is_long:
-      result = long(text, 0)
-    else:
-      result = int(text, 0)
-  except ValueError:
-    raise ValueError('Couldn\'t parse integer: %s' % text)
+  result = _ParseAbstractInteger(text, is_long=is_long)
 
   # Check if the integer is sane. Exceptions handled by callers.
   checker = _INTEGER_CHECKERS[2 * int(is_long) + int(is_signed)]
@@ -1131,6 +1378,32 @@
   return result
 
 
+def _ParseAbstractInteger(text, is_long=False):
+  """Parses an integer without checking size/signedness.
+
+  Args:
+    text: The text to parse.
+    is_long: True if the value should be returned as a long integer.
+
+  Returns:
+    The integer value.
+
+  Raises:
+    ValueError: Thrown Iff the text is not a valid integer.
+  """
+  # Do the actual parsing. Exception handling is propagated to caller.
+  try:
+    # We force 32-bit values to int and 64-bit values to long to make
+    # alternate implementations where the distinction is more significant
+    # (e.g. the C++ implementation) simpler.
+    if is_long:
+      return long(text, 0)
+    else:
+      return int(text, 0)
+  except ValueError:
+    raise ValueError('Couldn\'t parse integer: %s' % text)
+
+
 def ParseFloat(text):
   """Parse a floating point number.
 
@@ -1206,14 +1479,12 @@
     # Identifier.
     enum_value = enum_descriptor.values_by_name.get(value, None)
     if enum_value is None:
-      raise ValueError(
-          'Enum type "%s" has no value named %s.' % (
-              enum_descriptor.full_name, value))
+      raise ValueError('Enum type "%s" has no value named %s.' %
+                       (enum_descriptor.full_name, value))
   else:
     # Numeric value.
     enum_value = enum_descriptor.values_by_number.get(number, None)
     if enum_value is None:
-      raise ValueError(
-          'Enum type "%s" has no value with number %d.' % (
-              enum_descriptor.full_name, number))
+      raise ValueError('Enum type "%s" has no value with number %d.' %
+                       (enum_descriptor.full_name, number))
   return enum_value.number
diff --git a/python/setup.py b/python/setup.py
index 76f0cbc..524a312 100755
--- a/python/setup.py
+++ b/python/setup.py
@@ -76,6 +76,7 @@
       sys.exit(-1)
 
 def GenerateUnittestProtos():
+  generate_proto("../src/google/protobuf/any_test.proto", False)
   generate_proto("../src/google/protobuf/map_unittest.proto", False)
   generate_proto("../src/google/protobuf/unittest_arena.proto", False)
   generate_proto("../src/google/protobuf/unittest_no_arena.proto", False)
@@ -94,6 +95,7 @@
   generate_proto("google/protobuf/internal/descriptor_pool_test2.proto", False)
   generate_proto("google/protobuf/internal/factory_test1.proto", False)
   generate_proto("google/protobuf/internal/factory_test2.proto", False)
+  generate_proto("google/protobuf/internal/file_options_test.proto", False)
   generate_proto("google/protobuf/internal/import_test_package/inner.proto", False)
   generate_proto("google/protobuf/internal/import_test_package/outer.proto", False)
   generate_proto("google/protobuf/internal/missing_enum_values.proto", False)
diff --git a/src/google/protobuf/any.pb.cc b/src/google/protobuf/any.pb.cc
index fbde4a6..c91faa0 100644
--- a/src/google/protobuf/any.pb.cc
+++ b/src/google/protobuf/any.pb.cc
@@ -283,8 +283,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Any)
 }
 
-::google::protobuf::uint8* Any::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Any::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Any)
   // optional string type_url = 1;
   if (this->type_url().size() > 0) {
diff --git a/src/google/protobuf/any.pb.h b/src/google/protobuf/any.pb.h
index 100a67f..d8cbee2 100644
--- a/src/google/protobuf/any.pb.h
+++ b/src/google/protobuf/any.pb.h
@@ -42,7 +42,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Any : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Any) */ {
  public:
   Any();
   virtual ~Any();
@@ -86,7 +86,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/any.proto b/src/google/protobuf/any.proto
index 45db6ed..81dcf46 100644
--- a/src/google/protobuf/any.proto
+++ b/src/google/protobuf/any.proto
@@ -65,6 +65,16 @@
 //       foo = any.unpack(Foo.class);
 //     }
 //
+//  Example 3: Pack and unpack a message in Python.
+//
+//     foo = Foo(...)
+//     any = Any()
+//     any.Pack(foo)
+//     ...
+//     if any.Is(Foo.DESCRIPTOR):
+//       any.Unpack(foo)
+//       ...
+//
 // The pack methods provided by protobuf library will by default use
 // 'type.googleapis.com/full.type.name' as the type URL and the unpack
 // methods only use the fully qualified type name after the last '/'
@@ -104,10 +114,10 @@
   // A URL/resource name whose content describes the type of the
   // serialized protocol buffer message.
   //
-  // For URLs which use the schema `http`, `https`, or no schema, the
+  // For URLs which use the scheme `http`, `https`, or no scheme, the
   // following restrictions and interpretations apply:
   //
-  // * If no schema is provided, `https` is assumed.
+  // * If no scheme is provided, `https` is assumed.
   // * The last segment of the URL's path must represent the fully
   //   qualified name of the type (as in `path/google.protobuf.Duration`).
   //   The name should be in a canonical form (e.g., leading "." is
@@ -120,7 +130,7 @@
   //   on changes to types. (Use versioned type names to manage
   //   breaking changes.)
   //
-  // Schemas other than `http`, `https` (or the empty schema) might be
+  // Schemes other than `http`, `https` (or the empty scheme) might be
   // used with implementation specific semantics.
   //
   string type_url = 1;
diff --git a/src/google/protobuf/api.pb.cc b/src/google/protobuf/api.pb.cc
index cbeba30..d5dd892 100644
--- a/src/google/protobuf/api.pb.cc
+++ b/src/google/protobuf/api.pb.cc
@@ -475,8 +475,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Api)
 }
 
-::google::protobuf::uint8* Api::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Api::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Api)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -492,15 +492,15 @@
   // repeated .google.protobuf.Method methods = 2;
   for (unsigned int i = 0, n = this->methods_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->methods(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->methods(i), false, target);
   }
 
   // repeated .google.protobuf.Option options = 3;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        3, this->options(i), false, target);
   }
 
   // optional string version = 4;
@@ -517,15 +517,15 @@
   // optional .google.protobuf.SourceContext source_context = 5;
   if (this->has_source_context()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        5, *this->source_context_, target);
+      InternalWriteMessageNoVirtualToArray(
+        5, *this->source_context_, false, target);
   }
 
   // repeated .google.protobuf.Mixin mixins = 6;
   for (unsigned int i = 0, n = this->mixins_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        6, this->mixins(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        6, this->mixins(i), false, target);
   }
 
   // optional .google.protobuf.Syntax syntax = 7;
@@ -1225,8 +1225,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Method)
 }
 
-::google::protobuf::uint8* Method::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Method::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Method)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -1274,8 +1274,8 @@
   // repeated .google.protobuf.Option options = 6;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        6, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        6, this->options(i), false, target);
   }
 
   // optional .google.protobuf.Syntax syntax = 7;
@@ -1803,8 +1803,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Mixin)
 }
 
-::google::protobuf::uint8* Mixin::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Mixin::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Mixin)
   // optional string name = 1;
   if (this->name().size() > 0) {
diff --git a/src/google/protobuf/api.pb.h b/src/google/protobuf/api.pb.h
index bb35e47..c9ec923 100644
--- a/src/google/protobuf/api.pb.h
+++ b/src/google/protobuf/api.pb.h
@@ -45,7 +45,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Api : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Api) */ {
  public:
   Api();
   virtual ~Api();
@@ -79,7 +79,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -196,7 +200,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Method : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Method) */ {
  public:
   Method();
   virtual ~Method();
@@ -230,7 +234,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -337,7 +345,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Mixin : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Mixin) */ {
  public:
   Mixin();
   virtual ~Mixin();
@@ -371,7 +379,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc
index 613e589..78e2094 100755
--- a/src/google/protobuf/arena.cc
+++ b/src/google/protobuf/arena.cc
@@ -133,12 +133,7 @@
   Block* b = reinterpret_cast<Block*>(options_.block_alloc(size));
   b->pos = kHeaderSize + n;
   b->size = size;
-  if (b->avail() == 0) {
-    // Do not attempt to reuse this block.
-    b->owner = NULL;
-  } else {
-    b->owner = me;
-  }
+  b->owner = me;
 #ifdef ADDRESS_SANITIZER
   // Poison the rest of the block for ASAN. It was unpoisoned by the underlying
   // malloc but it's not yet usable until we return it as part of an allocation.
@@ -223,9 +218,7 @@
   }
   b = NewBlock(me, b, n, options_.start_block_size, options_.max_block_size);
   AddBlock(b);
-  if (b->owner == me) {  // If this block can be reused (see NewBlock()).
-    SetThreadCacheBlock(b);
-  }
+  SetThreadCacheBlock(b);
   return reinterpret_cast<char*>(b) + kHeaderSize;
 }
 
diff --git a/src/google/protobuf/arena.h b/src/google/protobuf/arena.h
index cf07b9f..58b1e12 100644
--- a/src/google/protobuf/arena.h
+++ b/src/google/protobuf/arena.h
@@ -801,7 +801,7 @@
   template <typename T>
   static void CreateInArenaStorageInternal(
       T* ptr, Arena* arena, google::protobuf::internal::false_type) {
-    new (ptr) T;
+    new (ptr) T();
   }
 
   template <typename T>
diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc
index ab25ffe..5f33e93 100644
--- a/src/google/protobuf/arena_unittest.cc
+++ b/src/google/protobuf/arena_unittest.cc
@@ -42,7 +42,6 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/arena_test_util.h>
 #include <google/protobuf/test_util.h>
 #include <google/protobuf/unittest.pb.h>
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index c1a6c15..df6f8af 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -641,18 +641,23 @@
       return;
     }
 
-    // Seek backwards to the beginning of the line, which is where we will
-    // insert the data.  Note that this has the effect of pushing the insertion
-    // point down, so the data is inserted before it.  This is intentional
-    // because it means that multiple insertions at the same point will end
-    // up in the expected order in the final output.
-    pos = target->find_last_of('\n', pos);
-    if (pos == string::npos) {
-      // Insertion point is on the first line.
-      pos = 0;
+    if ((pos > 3) && (target->substr(pos - 3, 2) == "/*")) {
+      // Support for inline "/* @@protoc_insertion_point() */"
+      pos = pos - 3;
     } else {
-      // Advance to character after '\n'.
-      ++pos;
+      // Seek backwards to the beginning of the line, which is where we will
+      // insert the data.  Note that this has the effect of pushing the
+      // insertion point down, so the data is inserted before it.  This is
+      // intentional because it means that multiple insertions at the same point
+      // will end up in the expected order in the final output.
+      pos = target->find_last_of('\n', pos);
+      if (pos == string::npos) {
+        // Insertion point is on the first line.
+        pos = 0;
+      } else {
+        // Advance to character after '\n'.
+        ++pos;
+      }
     }
 
     // Extract indent.
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 10252b3..ffd8152 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -35,8 +35,8 @@
 #include <google/protobuf/compiler/cpp/cpp_enum_field.h>
 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
 #include <google/protobuf/io/printer.h>
-#include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
 
 namespace google {
 namespace protobuf {
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index f585c31..dd9f188 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -182,33 +182,33 @@
 
 void MapFieldGenerator::
 GenerateMergeFromCodedStream(io::Printer* printer) const {
+    const FieldDescriptor* key_field =
+        descriptor_->message_type()->FindFieldByName("key");
   const FieldDescriptor* value_field =
       descriptor_->message_type()->FindFieldByName("value");
-  printer->Print(variables_,
-      "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
-
+  bool using_entry = false;
+  string key;
+  string value;
   if (IsProto3Field(descriptor_) ||
       value_field->type() != FieldDescriptor::TYPE_ENUM) {
     printer->Print(variables_,
+        "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
+                   "    $key_cpp$, $val_cpp$,\n"
+                   "    $key_wire_type$,\n"
+                   "    $val_wire_type$,\n"
+                   "    $default_enum_value$ >,\n"
+                   "  ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
+        " parser(&$name$_);\n"
         "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
-        "    input, entry.get()));\n");
-    switch (value_field->cpp_type()) {
-      case FieldDescriptor::CPPTYPE_MESSAGE:
-        printer->Print(variables_,
-            "(*mutable_$name$())[entry->key()].Swap("
-            "entry->mutable_value());\n");
-        break;
-      case FieldDescriptor::CPPTYPE_ENUM:
-        printer->Print(variables_,
-            "(*mutable_$name$())[entry->key()] =\n"
-            "    static_cast< $val_cpp$ >(*entry->mutable_value());\n");
-        break;
-      default:
-        printer->Print(variables_,
-            "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
-        break;
-    }
+        "    input, &parser));\n");
+    key = "parser.key()";
+    value = "parser.value()";
   } else {
+    using_entry = true;
+    key = "entry->key()";
+    value = "entry->value()";
+    printer->Print(variables_,
+        "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
     printer->Print(variables_,
         "{\n"
         "  ::std::string data;\n"
@@ -229,28 +229,23 @@
           "    unknown_fields_stream.WriteString(data);\n");
     }
 
-
     printer->Print(variables_,
         "  }\n"
         "}\n");
   }
 
-  const FieldDescriptor* key_field =
-      descriptor_->message_type()->FindFieldByName("key");
   if (key_field->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(
-        key_field, options_, true, variables_,
-        "entry->key().data(), entry->key().length(),\n", printer);
+    key_field, options_, true, variables_,
+        StrCat(key, ".data(), ", key, ".length(),\n").data(), printer);
   }
   if (value_field->type() == FieldDescriptor::TYPE_STRING) {
     GenerateUtf8CheckCodeForString(value_field, options_, true, variables_,
-                                   "entry->mutable_value()->data(),\n"
-                                   "entry->mutable_value()->length(),\n",
-                                   printer);
+        StrCat(value, ".data(), ", value, ".length(),\n").data(), printer);
   }
 
   // If entry is allocated by arena, its desctructor should be avoided.
-  if (SupportsArenas(descriptor_)) {
+  if (using_entry && SupportsArenas(descriptor_)) {
     printer->Print(variables_,
         "if (entry->GetArena() != NULL) entry.release();\n");
   }
@@ -333,8 +328,8 @@
   printer->Print(variables_,
       "    entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
       "    target = ::google::protobuf::internal::WireFormatLite::\n"
-      "        Write$declared_type$NoVirtualToArray(\n"
-      "            $number$, *entry, target);\n");
+      "        InternalWrite$declared_type$NoVirtualToArray(\n"
+      "            $number$, *entry, false, target);\n");
 
   printer->Indent();
   printer->Indent();
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index da2a4c9..32f6315 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -838,11 +838,13 @@
 
   map<string, string> vars;
   vars["classname"] = DependentBaseClassTemplateName(descriptor_);
+  vars["full_name"] = descriptor_->full_name();
   vars["superclass"] = SuperClassName(descriptor_, options_);
 
   printer->Print(vars,
     "template <class T>\n"
-    "class $classname$ : public $superclass$ {\n"
+    "class $classname$ : public $superclass$ "
+    "/* @@protoc_insertion_point(dep_base_class_definition:$full_name$) */ {\n"
     " public:\n");
   printer->Indent();
 
@@ -878,6 +880,7 @@
 
   map<string, string> vars;
   vars["classname"] = classname_;
+  vars["full_name"] = descriptor_->full_name();
   vars["field_count"] = SimpleItoa(descriptor_->field_count());
   vars["oneof_decl_count"] = SimpleItoa(descriptor_->oneof_decl_count());
   if (options_.dllexport_decl.empty()) {
@@ -892,7 +895,9 @@
     vars["superclass"] = SuperClassName(descriptor_, options_);
   }
   printer->Print(vars,
-    "class $dllexport$$classname$ : public $superclass$ {\n");
+    "class $dllexport$$classname$ : public $superclass$ "
+    "/* @@protoc_insertion_point(class_definition:$full_name$) */ "
+    "{\n");
   printer->Annotate("classname", descriptor_);
   if (use_dependent_base_) {
     printer->Print(vars, "  friend class $superclass$;\n");
@@ -1076,7 +1081,11 @@
     }
     if (HasFastArraySerialization(descriptor_->file(), options_)) {
       printer->Print(
-        "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;\n");
+        "::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(\n"
+        "    bool deterministic, ::google::protobuf::uint8* output) const;\n"
+        "::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {\n"
+        "  return InternalSerializeWithCachedSizesToArray(false, output);\n"
+        "}\n");
     }
   }
 
@@ -1095,6 +1104,13 @@
       descriptors.push_back(descriptor_->oneof_decl(i)->field(j));
     }
   }
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    const Descriptor* nested_type = descriptor_->nested_type(i);
+    if (IsMapEntryMessage(nested_type)) {
+      descriptors.push_back(nested_type->FindFieldByName("key"));
+      descriptors.push_back(nested_type->FindFieldByName("value"));
+    }
+  }
   uses_string_ = false;
   if (PreserveUnknownFields(descriptor_) &&
       !UseUnknownFieldSet(descriptor_->file(), options_)) {
@@ -3267,8 +3283,8 @@
     "// Extension range [$start$, $end$)\n");
   if (to_array) {
     printer->Print(vars,
-      "target = _extensions_.SerializeWithCachedSizesToArray(\n"
-      "    $start$, $end$, target);\n\n");
+      "target = _extensions_.InternalSerializeWithCachedSizesToArray(\n"
+      "    $start$, $end$, false, target);\n\n");
   } else {
     printer->Print(vars,
       "_extensions_.SerializeWithCachedSizes(\n"
@@ -3320,10 +3336,11 @@
   if (descriptor_->options().message_set_wire_format()) {
     // Special-case MessageSet.
     printer->Print(
-      "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
-      "    ::google::protobuf::uint8* target) const {\n"
-      "  target =\n"
-      "      _extensions_.SerializeMessageSetWithCachedSizesToArray(target);\n",
+      "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n"
+      "    bool deterministic, ::google::protobuf::uint8* target) const {\n"
+      "  target = _extensions_."
+      "InternalSerializeMessageSetWithCachedSizesToArray(\n"
+      "               deterministic, target);\n",
       "classname", classname_);
     GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file(), options_));
     printer->Print(
@@ -3337,8 +3354,8 @@
   }
 
   printer->Print(
-    "::google::protobuf::uint8* $classname$::SerializeWithCachedSizesToArray(\n"
-    "    ::google::protobuf::uint8* target) const {\n",
+    "::google::protobuf::uint8* $classname$::InternalSerializeWithCachedSizesToArray(\n"
+    "    bool deterministic, ::google::protobuf::uint8* target) const {\n",
     "classname", classname_);
   printer->Indent();
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 332c026..d021035 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -520,8 +520,8 @@
 GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
   printer->Print(variables_,
     "target = ::google::protobuf::internal::WireFormatLite::\n"
-    "  Write$declared_type$NoVirtualToArray(\n"
-    "    $number$, *$non_null_ptr_to_name$, target);\n");
+    "  InternalWrite$declared_type$NoVirtualToArray(\n"
+    "    $number$, *$non_null_ptr_to_name$, false, target);\n");
 }
 
 void MessageFieldGenerator::
@@ -1033,8 +1033,8 @@
   printer->Print(variables_,
     "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
     "  target = ::google::protobuf::internal::WireFormatLite::\n"
-    "    Write$declared_type$NoVirtualToArray(\n"
-    "      $number$, this->$name$(i), target);\n"
+    "    InternalWrite$declared_type$NoVirtualToArray(\n"
+    "      $number$, this->$name$(i), false, target);\n"
     "}\n");
 }
 
diff --git a/src/google/protobuf/compiler/cpp/cpp_options.h b/src/google/protobuf/compiler/cpp/cpp_options.h
index ab1d2ed..ee44fb0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_options.h
+++ b/src/google/protobuf/compiler/cpp/cpp_options.h
@@ -46,12 +46,14 @@
   Options()
       : safe_boundary_check(false),
         proto_h(false),
+        allow_import_public(true),
         annotate_headers(false),
         enforce_lite(false) {}
 
   string dllexport_decl;
   bool safe_boundary_check;
   bool proto_h;
+  bool allow_import_public;
   bool annotate_headers;
   bool enforce_lite;
   string annotation_pragma_name;
diff --git a/src/google/protobuf/compiler/java/java_context.cc b/src/google/protobuf/compiler/java/java_context.cc
index 0a11288..6cfa14a 100644
--- a/src/google/protobuf/compiler/java/java_context.cc
+++ b/src/google/protobuf/compiler/java/java_context.cc
@@ -42,8 +42,8 @@
 namespace compiler {
 namespace java {
 
-Context::Context(const FileDescriptor* file)
-    : name_resolver_(new ClassNameResolver), enforce_lite_(false) {
+Context::Context(const FileDescriptor* file, const Options& options)
+    : name_resolver_(new ClassNameResolver), options_(options) {
   InitializeFieldGeneratorInfo(file);
 }
 
@@ -192,8 +192,8 @@
 // Does this message class have generated parsing, serialization, and other
 // standard methods for which reflection-based fallback implementations exist?
 bool Context::HasGeneratedMethods(const Descriptor* descriptor) const {
-  return enforce_lite_ || descriptor->file()->options().optimize_for() !=
-           FileOptions::CODE_SIZE;
+  return options_.enforce_lite ||
+         descriptor->file()->options().optimize_for() != FileOptions::CODE_SIZE;
 }
 
 }  // namespace java
diff --git a/src/google/protobuf/compiler/java/java_context.h b/src/google/protobuf/compiler/java/java_context.h
index a480e45..f92ae87 100644
--- a/src/google/protobuf/compiler/java/java_context.h
+++ b/src/google/protobuf/compiler/java/java_context.h
@@ -39,6 +39,7 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
 
 namespace google {
 namespace protobuf {
@@ -64,7 +65,7 @@
 // generators.
 class Context {
  public:
-  explicit Context(const FileDescriptor* file);
+  Context(const FileDescriptor* file, const Options& options);
   ~Context();
 
   // Get the name resolver associated with this context. The resolver
@@ -79,15 +80,12 @@
   const OneofGeneratorInfo* GetOneofGeneratorInfo(
       const OneofDescriptor* oneof) const;
 
+  const Options& options() const { return options_; }
+
   // Enforces all the files (including transitive dependencies) to use
   // LiteRuntime.
-  void SetEnforceLite(bool enforce_lite) {
-    enforce_lite_ = enforce_lite;
-  }
 
-  bool EnforceLite() const {
-    return enforce_lite_;
-  }
+  bool EnforceLite() const { return options_.enforce_lite; }
 
   // Does this message class have generated parsing, serialization, and other
   // standard methods for which reflection-based fallback implementations exist?
@@ -102,7 +100,7 @@
   google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
   map<const FieldDescriptor*, FieldGeneratorInfo> field_generator_info_map_;
   map<const OneofDescriptor*, OneofGeneratorInfo> oneof_generator_info_map_;
-  bool enforce_lite_;
+  Options options_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Context);
 };
 
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index 947b80e..b46cfe9 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -86,10 +86,12 @@
 
 void EnumGenerator::Generate(io::Printer* printer) {
   WriteEnumDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
   printer->Print(
-    "public enum $classname$\n"
-    "    implements com.google.protobuf.ProtocolMessageEnum {\n",
-    "classname", descriptor_->name());
+      "public enum $classname$\n"
+      "    implements com.google.protobuf.ProtocolMessageEnum {\n",
+      "classname", descriptor_->name());
+  printer->Annotate("classname", descriptor_);
   printer->Indent();
 
   bool ordinal_is_index = true;
diff --git a/src/google/protobuf/compiler/java/java_enum.h b/src/google/protobuf/compiler/java/java_enum.h
index a0d91f5..c33e713 100644
--- a/src/google/protobuf/compiler/java/java_enum.h
+++ b/src/google/protobuf/compiler/java/java_enum.h
@@ -58,9 +58,8 @@
 
 class EnumGenerator {
  public:
-  explicit EnumGenerator(const EnumDescriptor* descriptor,
-                         bool immutable_api,
-                         Context* context);
+  EnumGenerator(const EnumDescriptor* descriptor, bool immutable_api,
+                Context* context);
   ~EnumGenerator();
 
   void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index 3e54be3..2e916c5 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -76,6 +76,11 @@
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
   (*variables)["on_changed"] = "onChanged();";
+  // Use deprecated valueOf() method to be compatible with old generated code
+  // for v2.5.0/v2.6.1.
+  // TODO(xiaofeng): Use "forNumber" when we no longer support compatibility
+  // with v2.5.0/v2.6.1.
+  (*variables)["for_number"] = "valueOf";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -191,7 +196,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  $type$ result = $type$.forNumber($name$_);\n"
+    "  $type$ result = $type$.$for_number$($name$_);\n"
     "  return result == null ? $unknown$ : result;\n"
     "}\n");
 }
@@ -224,7 +229,7 @@
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
-    "  $type$ result = $type$.forNumber($name$_);\n"
+    "  $type$ result = $type$.$for_number$($name$_);\n"
     "  return result == null ? $unknown$ : result;\n"
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
@@ -304,7 +309,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.forNumber(rawValue);\n"
+      "$type$ value = $type$.$for_number$(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -398,7 +403,8 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+    "    $type$ result = $type$.$for_number$(\n"
+    "        (java.lang.Integer) $oneof_name$_);\n"
     "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
@@ -436,7 +442,8 @@
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
     "  if ($has_oneof_case_message$) {\n"
-    "    $type$ result = $type$.forNumber((java.lang.Integer) $oneof_name$_);\n"
+    "    $type$ result = $type$.$for_number$(\n"
+    "        (java.lang.Integer) $oneof_name$_);\n"
     "    return result == null ? $unknown$ : result;\n"
     "  }\n"
     "  return $default$;\n"
@@ -493,7 +500,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.forNumber(rawValue);\n"
+      "$type$ value = $type$.$for_number$(rawValue);\n"
       "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -606,7 +613,7 @@
     "        new com.google.protobuf.Internal.ListAdapter.Converter<\n"
     "            java.lang.Integer, $type$>() {\n"
     "          public $type$ convert(java.lang.Integer from) {\n"
-    "            $type$ result = $type$.forNumber(from);\n"
+    "            $type$ result = $type$.$for_number$(from);\n"
     "            return result == null ? $unknown$ : result;\n"
     "          }\n"
     "        };\n");
@@ -839,7 +846,7 @@
   } else {
     printer->Print(variables_,
       "int rawValue = input.readEnum();\n"
-      "$type$ value = $type$.forNumber(rawValue);\n"
+      "$type$ value = $type$.$for_number$(rawValue);\n"
         "if (value == null) {\n");
     if (PreserveUnknownFields(descriptor_->containing_type())) {
       printer->Print(variables_,
@@ -887,8 +894,8 @@
   if (descriptor_->is_packed()) {
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "  output.writeUInt32NoTag($tag$);\n"
+      "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  output.writeEnumNoTag($name$_.get(i));\n"
@@ -920,7 +927,7 @@
       "if (!get$capitalized_name$List().isEmpty()) {"
       "  size += $tag_size$;\n"
       "  size += com.google.protobuf.CodedOutputStream\n"
-      "    .computeRawVarint32Size(dataSize);\n"
+      "    .computeUInt32SizeNoTag(dataSize);\n"
       "}");
   } else {
     printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_field_lite.cc b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
index 908d6db..aa0eb5e 100644
--- a/src/google/protobuf/compiler/java/java_enum_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field_lite.cc
@@ -258,7 +258,9 @@
 
 void ImmutableEnumFieldLiteGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_ = $default_number$;\n");
+  if (!IsDefaultValueJavaDefault(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $default_number$;\n");
+  }
 }
 
 void ImmutableEnumFieldLiteGenerator::
@@ -885,8 +887,8 @@
   if (descriptor_->options().packed()) {
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "  output.writeUInt32NoTag($tag$);\n"
+      "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  output.writeEnumNoTag($name$_.getInt(i));\n"
@@ -918,7 +920,7 @@
       "if (!get$capitalized_name$List().isEmpty()) {"
       "  size += $tag_size$;\n"
       "  size += com.google.protobuf.CodedOutputStream\n"
-      "    .computeRawVarint32Size(dataSize);\n"
+      "    .computeUInt32SizeNoTag(dataSize);\n"
       "}");
   } else {
     printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.cc b/src/google/protobuf/compiler/java/java_enum_lite.cc
index c22da8d..99f52d4 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.cc
+++ b/src/google/protobuf/compiler/java/java_enum_lite.cc
@@ -61,10 +61,11 @@
 }  // namespace
 
 EnumLiteGenerator::EnumLiteGenerator(const EnumDescriptor* descriptor,
-                             bool immutable_api,
-                             Context* context)
-  : descriptor_(descriptor), immutable_api_(immutable_api),
-    name_resolver_(context->GetNameResolver())  {
+                                     bool immutable_api, Context* context)
+    : descriptor_(descriptor),
+      immutable_api_(immutable_api),
+      context_(context),
+      name_resolver_(context->GetNameResolver()) {
   for (int i = 0; i < descriptor_->value_count(); i++) {
     const EnumValueDescriptor* value = descriptor_->value(i);
     const EnumValueDescriptor* canonical_value =
@@ -85,10 +86,12 @@
 
 void EnumLiteGenerator::Generate(io::Printer* printer) {
   WriteEnumDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_, immutable_api_);
   printer->Print(
-    "public enum $classname$\n"
-    "    implements com.google.protobuf.Internal.EnumLite {\n",
-    "classname", descriptor_->name());
+      "public enum $classname$\n"
+      "    implements com.google.protobuf.Internal.EnumLite {\n",
+      "classname", descriptor_->name());
+  printer->Annotate("classname", descriptor_);
   printer->Indent();
 
   for (int i = 0; i < canonical_values_.size(); i++) {
diff --git a/src/google/protobuf/compiler/java/java_enum_lite.h b/src/google/protobuf/compiler/java/java_enum_lite.h
index ee2f5f7..f27cb76 100644
--- a/src/google/protobuf/compiler/java/java_enum_lite.h
+++ b/src/google/protobuf/compiler/java/java_enum_lite.h
@@ -58,9 +58,8 @@
 
 class EnumLiteGenerator {
  public:
-  explicit EnumLiteGenerator(const EnumDescriptor* descriptor,
-                         bool immutable_api,
-                         Context* context);
+  EnumLiteGenerator(const EnumDescriptor* descriptor, bool immutable_api,
+                    Context* context);
   ~EnumLiteGenerator();
 
   void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc
index c53aae6..a06c5f6 100644
--- a/src/google/protobuf/compiler/java/java_file.cc
+++ b/src/google/protobuf/compiler/java/java_file.cc
@@ -193,19 +193,19 @@
 
 }  // namespace
 
-FileGenerator::FileGenerator(const FileDescriptor* file, bool immutable_api,
-                             bool enforce_lite)
+FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options,
+                             bool immutable_api)
     : file_(file),
       java_package_(FileJavaPackage(file, immutable_api)),
       message_generators_(
           new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
       extension_generators_(
           new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
-      context_(new Context(file)),
+      context_(new Context(file, options)),
       name_resolver_(context_->GetNameResolver()),
+      options_(options),
       immutable_api_(immutable_api) {
   classname_ = name_resolver_->GetFileClassName(file, immutable_api);
-  context_->SetEnforceLite(enforce_lite);
   generator_factory_.reset(
       new ImmutableGeneratorFactory(context_.get()));
   for (int i = 0; i < file_->message_type_count(); ++i) {
@@ -253,10 +253,13 @@
       "\n",
       "package", java_package_);
   }
+  PrintGeneratedAnnotation(
+      printer, '$', options_.annotate_code ? classname_ + ".java.pb.meta" : "");
   printer->Print(
-    "public final class $classname$ {\n"
-    "  private $classname$() {}\n",
-    "classname", classname_);
+      "public final class $classname$ {\n"
+      "  private $ctor$() {}\n",
+      "classname", classname_, "ctor", classname_);
+  printer->Annotate("classname", file_->name());
   printer->Indent();
 
   // -----------------------------------------------------------------
@@ -372,7 +375,7 @@
     "final", "");
   printer->Indent();
 
-  SharedCodeGenerator shared_code_generator(file_);
+  SharedCodeGenerator shared_code_generator(file_, options_);
   shared_code_generator.GenerateDescriptors(printer);
 
   int bytecode_estimate = 0;
@@ -523,20 +526,26 @@
     "}\n");
 }
 
-template<typename GeneratorClass, typename DescriptorClass>
+template <typename GeneratorClass, typename DescriptorClass>
 static void GenerateSibling(const string& package_dir,
                             const string& java_package,
                             const DescriptorClass* descriptor,
                             GeneratorContext* context,
-                            vector<string>* file_list,
+                            vector<string>* file_list, bool annotate_code,
+                            vector<string>* annotation_list,
                             const string& name_suffix,
                             GeneratorClass* generator,
                             void (GeneratorClass::*pfn)(io::Printer* printer)) {
   string filename = package_dir + descriptor->name() + name_suffix + ".java";
   file_list->push_back(filename);
+  string info_full_path = filename + ".pb.meta";
+  GeneratedCodeInfo annotations;
+  io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+      &annotations);
 
   google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
-  io::Printer printer(output.get(), '$');
+  io::Printer printer(output.get(), '$',
+                      annotate_code ? &annotation_collector : NULL);
 
   printer.Print(
     "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
@@ -551,55 +560,57 @@
   }
 
   (generator->*pfn)(&printer);
+
+  if (annotate_code) {
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+        context->Open(info_full_path));
+    annotations.SerializeToZeroCopyStream(info_output.get());
+    annotation_list->push_back(info_full_path);
+  }
 }
 
 void FileGenerator::GenerateSiblings(const string& package_dir,
                                      GeneratorContext* context,
-                                     vector<string>* file_list) {
+                                     vector<string>* file_list,
+                                     vector<string>* annotation_list) {
   if (MultipleJavaFiles(file_, immutable_api_)) {
     for (int i = 0; i < file_->enum_type_count(); i++) {
       if (HasDescriptorMethods(file_, context_->EnforceLite())) {
         EnumGenerator generator(file_->enum_type(i), immutable_api_,
                                 context_.get());
-        GenerateSibling<EnumGenerator>(package_dir, java_package_,
-                                       file_->enum_type(i),
-                                       context, file_list, "",
-                                       &generator,
-                                       &EnumGenerator::Generate);
+        GenerateSibling<EnumGenerator>(
+            package_dir, java_package_, file_->enum_type(i), context, file_list,
+            options_.annotate_code, annotation_list, "", &generator,
+            &EnumGenerator::Generate);
       } else {
         EnumLiteGenerator generator(file_->enum_type(i), immutable_api_,
                                     context_.get());
-        GenerateSibling<EnumLiteGenerator>(package_dir, java_package_,
-                                           file_->enum_type(i),
-                                           context, file_list, "",
-                                           &generator,
-                                           &EnumLiteGenerator::Generate);
+        GenerateSibling<EnumLiteGenerator>(
+            package_dir, java_package_, file_->enum_type(i), context, file_list,
+            options_.annotate_code, annotation_list, "", &generator,
+            &EnumLiteGenerator::Generate);
       }
     }
     for (int i = 0; i < file_->message_type_count(); i++) {
       if (immutable_api_) {
-        GenerateSibling<MessageGenerator>(package_dir, java_package_,
-                                          file_->message_type(i),
-                                          context, file_list,
-                                          "OrBuilder",
-                                          message_generators_[i].get(),
-                                          &MessageGenerator::GenerateInterface);
+        GenerateSibling<MessageGenerator>(
+            package_dir, java_package_, file_->message_type(i), context,
+            file_list, options_.annotate_code, annotation_list, "OrBuilder",
+            message_generators_[i].get(), &MessageGenerator::GenerateInterface);
       }
-      GenerateSibling<MessageGenerator>(package_dir, java_package_,
-                                        file_->message_type(i),
-                                        context, file_list, "",
-                                        message_generators_[i].get(),
-                                        &MessageGenerator::Generate);
+      GenerateSibling<MessageGenerator>(
+          package_dir, java_package_, file_->message_type(i), context,
+          file_list, options_.annotate_code, annotation_list, "",
+          message_generators_[i].get(), &MessageGenerator::Generate);
     }
     if (HasGenericServices(file_, context_->EnforceLite())) {
       for (int i = 0; i < file_->service_count(); i++) {
         google::protobuf::scoped_ptr<ServiceGenerator> generator(
             generator_factory_->NewServiceGenerator(file_->service(i)));
-        GenerateSibling<ServiceGenerator>(package_dir, java_package_,
-                                          file_->service(i),
-                                          context, file_list, "",
-                                          generator.get(),
-                                          &ServiceGenerator::Generate);
+        GenerateSibling<ServiceGenerator>(
+            package_dir, java_package_, file_->service(i), context, file_list,
+            options_.annotate_code, annotation_list, "", generator.get(),
+            &ServiceGenerator::Generate);
       }
     }
   }
diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h
index 7dbeb94..1e643f7 100644
--- a/src/google/protobuf/compiler/java/java_file.h
+++ b/src/google/protobuf/compiler/java/java_file.h
@@ -42,6 +42,7 @@
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
 
 namespace google {
 namespace protobuf {
@@ -67,8 +68,8 @@
 
 class FileGenerator {
  public:
-  FileGenerator(const FileDescriptor* file, bool immutable_api = true,
-                bool enforce_lite = false);
+  FileGenerator(const FileDescriptor* file, const Options& options,
+                bool immutable_api = true);
   ~FileGenerator();
 
   // Checks for problems that would otherwise lead to cryptic compile errors.
@@ -83,12 +84,12 @@
   // service type).
   void GenerateSiblings(const string& package_dir,
                         GeneratorContext* generator_context,
-                        vector<string>* file_list);
+                        vector<string>* file_list,
+                        vector<string>* annotation_list);
 
   const string& java_package() { return java_package_; }
   const string& classname()    { return classname_;    }
 
-
  private:
   void GenerateDescriptorInitializationCodeForImmutable(io::Printer* printer);
   void GenerateDescriptorInitializationCodeForMutable(io::Printer* printer);
@@ -105,9 +106,9 @@
   google::protobuf::scoped_ptr<GeneratorFactory> generator_factory_;
   google::protobuf::scoped_ptr<Context> context_;
   ClassNameResolver* name_resolver_;
+  const Options options_;
   bool immutable_api_;
 
-
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc
index a46c7fc..3c545e1 100644
--- a/src/google/protobuf/compiler/java/java_generator.cc
+++ b/src/google/protobuf/compiler/java/java_generator.cc
@@ -42,6 +42,7 @@
 #include <google/protobuf/compiler/java/java_file.h>
 #include <google/protobuf/compiler/java/java_generator_factory.h>
 #include <google/protobuf/compiler/java/java_helpers.h>
+#include <google/protobuf/compiler/java/java_options.h>
 #include <google/protobuf/compiler/java/java_shared_code_generator.h>
 #include <google/protobuf/io/printer.h>
 #include <google/protobuf/io/zero_copy_stream.h>
@@ -64,63 +65,60 @@
   // -----------------------------------------------------------------
   // parse generator options
 
-  // Name a file where we will write a list of generated file names, one
-  // per line.
-  string output_list_file;
-
 
   vector<pair<string, string> > options;
   ParseGeneratorParameter(parameter, &options);
+  Options file_options;
 
-  bool generate_immutable_code = false;
-  bool generate_mutable_code = false;
-  bool generate_shared_code = false;
-  bool enforce_lite = false;
   for (int i = 0; i < options.size(); i++) {
     if (options[i].first == "output_list_file") {
-      output_list_file = options[i].second;
+      file_options.output_list_file = options[i].second;
     } else if (options[i].first == "immutable") {
-      generate_immutable_code = true;
+      file_options.generate_immutable_code = true;
     } else if (options[i].first == "mutable") {
-      generate_mutable_code = true;
+      file_options.generate_mutable_code = true;
     } else if (options[i].first == "shared") {
-      generate_shared_code = true;
+      file_options.generate_shared_code = true;
     } else if (options[i].first == "lite") {
-      // When set, the protoc will generate the current files and all the
-      // transitive dependencies as lite runtime.
-      enforce_lite = true;
+      file_options.enforce_lite = true;
+    } else if (options[i].first == "annotate_code") {
+      file_options.annotate_code = true;
+    } else if (options[i].first == "annotation_list_file") {
+      file_options.annotation_list_file = options[i].second;
     } else {
       *error = "Unknown generator option: " + options[i].first;
       return false;
     }
   }
 
-  if (enforce_lite && generate_mutable_code) {
+  if (file_options.enforce_lite && file_options.generate_mutable_code) {
     *error = "lite runtime generator option cannot be used with mutable API.";
     return false;
   }
 
   // By default we generate immutable code and shared code for immutable API.
-  if (!generate_immutable_code && !generate_mutable_code &&
-      !generate_shared_code) {
-    generate_immutable_code = true;
-    generate_shared_code = true;
+  if (!file_options.generate_immutable_code &&
+      !file_options.generate_mutable_code &&
+      !file_options.generate_shared_code) {
+    file_options.generate_immutable_code = true;
+    file_options.generate_shared_code = true;
   }
 
   // -----------------------------------------------------------------
 
 
   vector<string> all_files;
+  vector<string> all_annotations;
 
 
   vector<FileGenerator*> file_generators;
-  if (generate_immutable_code) {
-    file_generators.push_back(
-        new FileGenerator(file, /* immutable = */ true, enforce_lite));
+  if (file_options.generate_immutable_code) {
+    file_generators.push_back(new FileGenerator(file, file_options,
+                                                /* immutable = */ true));
   }
-  if (generate_mutable_code) {
-    file_generators.push_back(
-        new FileGenerator(file, /* mutable = */ false, enforce_lite));
+  if (file_options.generate_mutable_code) {
+    file_generators.push_back(new FileGenerator(file, file_options,
+                                                /* mutable = */ false));
   }
   for (int i = 0; i < file_generators.size(); ++i) {
     if (!file_generators[i]->Validate(error)) {
@@ -140,15 +138,32 @@
     java_filename += file_generator->classname();
     java_filename += ".java";
     all_files.push_back(java_filename);
+    string info_full_path = java_filename + ".pb.meta";
+    if (file_options.annotate_code) {
+      all_annotations.push_back(info_full_path);
+    }
 
     // Generate main java file.
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
         context->Open(java_filename));
-    io::Printer printer(output.get(), '$');
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    io::Printer printer(output.get(), '$', file_options.annotate_code
+                                               ? &annotation_collector
+                                               : NULL);
+
     file_generator->Generate(&printer);
 
     // Generate sibling files.
-    file_generator->GenerateSiblings(package_dir, context, &all_files);
+    file_generator->GenerateSiblings(package_dir, context, &all_files,
+                                     &all_annotations);
+
+    if (file_options.annotate_code) {
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          context->Open(info_full_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+    }
   }
 
   for (int i = 0; i < file_generators.size(); ++i) {
@@ -157,17 +172,29 @@
   file_generators.clear();
 
   // Generate output list if requested.
-  if (!output_list_file.empty()) {
+  if (!file_options.output_list_file.empty()) {
     // Generate output list.  This is just a simple text file placed in a
     // deterministic location which lists the .java files being generated.
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
-        context->Open(output_list_file));
+        context->Open(file_options.output_list_file));
     io::Printer srclist_printer(srclist_raw_output.get(), '$');
     for (int i = 0; i < all_files.size(); i++) {
       srclist_printer.Print("$filename$\n", "filename", all_files[i]);
     }
   }
 
+  if (!file_options.annotation_list_file.empty()) {
+    // Generate output list.  This is just a simple text file placed in a
+    // deterministic location which lists the .java files being generated.
+    google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> annotation_list_raw_output(
+        context->Open(file_options.annotation_list_file));
+    io::Printer annotation_list_printer(annotation_list_raw_output.get(), '$');
+    for (int i = 0; i < all_annotations.size(); i++) {
+      annotation_list_printer.Print("$filename$\n", "filename",
+                                    all_annotations[i]);
+    }
+  }
+
   return true;
 }
 
diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc
index e24894b..c31df26 100644
--- a/src/google/protobuf/compiler/java/java_helpers.cc
+++ b/src/google/protobuf/compiler/java/java_helpers.cc
@@ -101,6 +101,20 @@
 
 }  // namespace
 
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter,
+                              const string& annotation_file) {
+  if (annotation_file.empty()) {
+    return;
+  }
+  string ptemplate =
+      "@javax.annotation.Generated(value=\"protoc\", comments=\"annotations:";
+  ptemplate.push_back(delimiter);
+  ptemplate.append("annotation_file");
+  ptemplate.push_back(delimiter);
+  ptemplate.append("\")\n");
+  printer->Print(ptemplate.c_str(), "annotation_file", annotation_file);
+}
+
 string UnderscoresToCamelCase(const string& input, bool cap_next_letter) {
   string result;
   // Note:  I distrust ctype.h due to locales.
@@ -481,9 +495,9 @@
       return field->default_value_float() == 0.0;
     case FieldDescriptor::CPPTYPE_BOOL:
       return field->default_value_bool() == false;
-
-    case FieldDescriptor::CPPTYPE_STRING:
     case FieldDescriptor::CPPTYPE_ENUM:
+      return field->default_value_enum()->number() == 0;
+    case FieldDescriptor::CPPTYPE_STRING:
     case FieldDescriptor::CPPTYPE_MESSAGE:
       return false;
 
@@ -495,6 +509,11 @@
   return false;
 }
 
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field) {
+  return GetJavaType(field) == JAVATYPE_BYTES &&
+         field->default_value_string() != "";
+}
+
 const char* bit_masks[] = {
   "0x00000001",
   "0x00000002",
diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h
index c850423..5316d2f 100644
--- a/src/google/protobuf/compiler/java/java_helpers.h
+++ b/src/google/protobuf/compiler/java/java_helpers.h
@@ -36,6 +36,8 @@
 #define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
 
 #include <string>
+#include <google/protobuf/compiler/java/java_context.h>
+#include <google/protobuf/io/printer.h>
 #include <google/protobuf/descriptor.pb.h>
 #include <google/protobuf/descriptor.h>
 
@@ -49,6 +51,17 @@
 extern const char kThickSeparator[];
 extern const char kThinSeparator[];
 
+// If annotation_file is non-empty, prints a javax.annotation.Generated
+// annotation to the given Printer. annotation_file will be referenced in the
+// annotation's comments field. delimiter should be the Printer's delimiter
+// character. annotation_file will be included verbatim into a Java literal
+// string, so it should not contain quotes or invalid Java escape sequences;
+// however, these are unlikely to appear in practice, as the value of
+// annotation_file should be generated from the filename of the source file
+// being annotated (which in turn must be a Java identifier plus ".java").
+void PrintGeneratedAnnotation(io::Printer* printer, char delimiter = '$',
+                              const string& annotation_file = "");
+
 // Converts a name to camel-case. If cap_first_letter is true, capitalize the
 // first letter.
 string UnderscoresToCamelCase(const string& name, bool cap_first_letter);
@@ -126,6 +139,38 @@
   return descriptor->options().java_multiple_files();
 }
 
+// Returns true if `descriptor` will be written to its own .java file.
+// `immutable` should be set to true if we're generating for the immutable API.
+template <typename Descriptor>
+bool IsOwnFile(const Descriptor* descriptor, bool immutable) {
+  return descriptor->containing_type() == NULL &&
+         MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+template <>
+inline bool IsOwnFile(const ServiceDescriptor* descriptor, bool immutable) {
+  return MultipleJavaFiles(descriptor->file(), immutable);
+}
+
+// If `descriptor` describes an object with its own .java file,
+// returns the name (relative to that .java file) of the file that stores
+// annotation data for that descriptor. `suffix` is usually empty, but may
+// (e.g.) be "OrBuilder" for some generated interfaces.
+template <typename Descriptor>
+string AnnotationFileName(const Descriptor* descriptor, const string& suffix) {
+  return descriptor->name() + suffix + ".java.pb.meta";
+}
+
+template <typename Descriptor>
+void MaybePrintGeneratedAnnotation(Context* context, io::Printer* printer,
+                                   Descriptor* descriptor, bool immutable,
+                                   const string& suffix = "") {
+  if (context->options().annotate_code && IsOwnFile(descriptor, immutable)) {
+    PrintGeneratedAnnotation(printer, '$',
+                             AnnotationFileName(descriptor, suffix));
+  }
+}
+
 // Get the unqualified name that should be used for a field's field
 // number constant.
 string FieldConstantName(const FieldDescriptor *field);
@@ -169,11 +214,7 @@
   return DefaultValue(field, true, name_resolver);
 }
 bool IsDefaultValueJavaDefault(const FieldDescriptor* field);
-
-// Does this message have specialized equals() and hashCode() methods?
-inline bool HasEqualsAndHashCode(const Descriptor* descriptor) {
-  return descriptor->file()->options().java_generate_equals_and_hash();
-}
+bool IsByteStringWithCustomDefaultValue(const FieldDescriptor* field);
 
 // Does this message class have descriptor and reflection methods?
 inline bool HasDescriptorMethods(const Descriptor* descriptor,
@@ -344,6 +385,9 @@
       descriptor->file()->options().java_string_check_utf8();
 }
 
+inline string GeneratedCodeVersionSuffix() {
+  return "V3";
+}
 }  // namespace java
 }  // namespace compiler
 }  // namespace protobuf
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field.cc b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
index 0de8cbe..abf8e55 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field.cc
@@ -93,7 +93,7 @@
   printer->Print(variables_,
     // If this builder is non-null, it is used and the other fields are
     // ignored.
-    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
     "\n");
 
@@ -193,11 +193,11 @@
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
-    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> \n"
     "    get$capitalized_name$FieldBuilder() {\n"
     "  if ($name$Builder_ == null) {\n"
-    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "        $type$, $type$.Builder, $type$OrBuilder>(\n"
     "            $name$_,\n"
     "            getParentForChildren(),\n"
@@ -535,7 +535,7 @@
   printer->Print(variables_,
     // If this builder is non-null, it is used and the other fields are
     // ignored.
-    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
     "\n");
 
@@ -763,11 +763,11 @@
     "     get$capitalized_name$BuilderList() {\n"
     "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
     "}\n"
-    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> \n"
     "    get$capitalized_name$FieldBuilder() {\n"
     "  if ($name$Builder_ == null) {\n"
-    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "        $type$, $type$.Builder, $type$OrBuilder>(\n"
     "            $name$_,\n"
     "            $get_mutable_bit_builder$,\n"
diff --git a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
index 62f3930..dac1b51 100644
--- a/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc
@@ -59,19 +59,28 @@
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateMembers(io::Printer* printer) const {
   printer->Print(variables_,
-    "private com.google.protobuf.LazyFieldLite $name$_ =\n"
-    "    new com.google.protobuf.LazyFieldLite();\n");
+    "private com.google.protobuf.LazyFieldLite $name$_;");
 
   PrintExtraFieldInfo(variables_, printer);
   WriteFieldDocComment(printer, descriptor_);
-  printer->Print(variables_,
-    "$deprecation$public boolean has$capitalized_name$() {\n"
-    "  return $get_has_field_bit_message$;\n"
-    "}\n");
+  if (SupportFieldPresence(descriptor_->file())) {
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $get_has_field_bit_message$;\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "$deprecation$public boolean has$capitalized_name$() {\n"
+      "  return $name$_ != null;\n"
+      "}\n");
+  }
 
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "$deprecation$public $type$ get$capitalized_name$() {\n"
+    "  if ($name$_ == null) {\n"
+    "    return $type$.getDefaultInstance();\n"
+    "  }\n"
     "  return ($type$) $name$_.getValue($type$.getDefaultInstance());\n"
    "}\n");
 
@@ -82,8 +91,11 @@
     "  if (value == null) {\n"
     "    throw new NullPointerException();\n"
     "  }\n"
+    "  if ($name$_ == null) {\n"
+    "    $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+    "  }\n"
     "  $name$_.setValue(value);\n"
-    "  $set_has_field_bit_message$;\n"
+    "  $set_has_field_bit_message$\n"
     "}\n");
 
   // Field.Builder setField(Field.Builder builderForValue)
@@ -91,30 +103,36 @@
   printer->Print(variables_,
     "private void set$capitalized_name$(\n"
     "    $type$.Builder builderForValue) {\n"
+    "  if ($name$_ == null) {\n"
+    "    $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+    "  }\n"
     "  $name$_.setValue(builderForValue.build());\n"
-    "  $set_has_field_bit_message$;\n"
+    "  $set_has_field_bit_message$\n"
     "}\n");
 
   // Field.Builder mergeField(Field value)
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "private void merge$capitalized_name$($type$ value) {\n"
-    "  if ($get_has_field_bit_message$ &&\n"
+    "  if (has$capitalized_name$() &&\n"
     "      !$name$_.containsDefaultInstance()) {\n"
     "    $name$_.setValue(\n"
     "      $type$.newBuilder(\n"
     "          get$capitalized_name$()).mergeFrom(value).buildPartial());\n"
     "  } else {\n"
+    "    if ($name$_ == null) {\n"
+    "      $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+    "    }\n"
     "    $name$_.setValue(value);\n"
+    "    $set_has_field_bit_message$\n"
     "  }\n"
-    "  $set_has_field_bit_message$;\n"
     "}\n");
 
   // Field.Builder clearField()
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
     "private void clear$capitalized_name$() {\n"
-    "  $name$_.clear();\n"
+    "  $name$_ = null;\n"
     "  $clear_has_field_bit_message$;\n"
     "}\n");
 }
@@ -177,31 +195,30 @@
 
 
 void ImmutableLazyMessageFieldLiteGenerator::
-GenerateInitializationCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_.clear();\n");
-}
+GenerateInitializationCode(io::Printer* printer) const {}
 
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateVisitCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "$name$_ = visitor.visitLazyMessage(\n"
-    "    has$capitalized_name$(), $name$_,\n"
-    "    other.has$capitalized_name$(), other.$name$_);\n");
+    "$name$_ = visitor.visitLazyMessage($name$_, other.$name$_);\n");
 }
 
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateParsingCode(io::Printer* printer) const {
   printer->Print(variables_,
+    "if ($name$_ == null) {\n"
+    "  $name$_ = new com.google.protobuf.LazyFieldLite();\n"
+    "}\n"
     "$name$_.mergeFrom(input, extensionRegistry);\n");
   printer->Print(variables_,
-    "$set_has_field_bit_message$;\n");
+    "$set_has_field_bit_message$\n");
 }
 
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateSerializationCode(io::Printer* printer) const {
   // Do not de-serialize lazy fields.
   printer->Print(variables_,
-    "if ($get_has_field_bit_message$) {\n"
+    "if (has$capitalized_name$()) {\n"
     "  output.writeBytes($number$, $name$_.toByteString());\n"
     "}\n");
 }
@@ -209,7 +226,7 @@
 void ImmutableLazyMessageFieldLiteGenerator::
 GenerateSerializedSizeCode(io::Printer* printer) const {
   printer->Print(variables_,
-    "if ($get_has_field_bit_message$) {\n"
+    "if (has$capitalized_name$()) {\n"
     "  size += com.google.protobuf.CodedOutputStream\n"
     "    .computeLazyFieldSize($number$, $name$_);\n"
     "}\n");
diff --git a/src/google/protobuf/compiler/java/java_map_field.cc b/src/google/protobuf/compiler/java/java_map_field.cc
index 2a551ca..16c5bec 100644
--- a/src/google/protobuf/compiler/java/java_map_field.cc
+++ b/src/google/protobuf/compiler/java/java_map_field.cc
@@ -88,11 +88,18 @@
       name_resolver->GetImmutableClassName(descriptor->message_type());
   const FieldDescriptor* key = KeyField(descriptor);
   const FieldDescriptor* value = ValueField(descriptor);
+  const JavaType keyJavaType = GetJavaType(key);
+  const JavaType valueJavaType = GetJavaType(value);
+
   (*variables)["key_type"] = TypeName(key, name_resolver, false);
   (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
   (*variables)["key_wire_type"] = WireType(key);
   (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
-  if (GetJavaType(value) == JAVATYPE_ENUM) {
+  (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ?
+      "if (key == null) { throw new java.lang.NullPointerException(); }" : "";
+  (*variables)["value_null_check"] = IsReferenceType(valueJavaType) ?
+      "if (value == null) { throw new java.lang.NullPointerException(); }" : "";
+  if (valueJavaType == JAVATYPE_ENUM) {
     // We store enums as Integers internally.
     (*variables)["value_type"] = "int";
     (*variables)["boxed_value_type"] = "java.lang.Integer";
@@ -135,7 +142,6 @@
 
   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
       "DefaultEntryHolder.defaultEntry";
-  (*variables)["lite"] = "";
   (*variables)["map_field_parameter"] = (*variables)["default_entry"];
   (*variables)["descriptor"] =
       name_resolver->GetImmutableClassName(descriptor->file()) +
@@ -169,25 +175,95 @@
 
 void ImmutableMapFieldGenerator::
 GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$boolean contains$capitalized_name$(\n"
+      "    $key_type$ key);\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$();\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "get$capitalized_name$();\n");
+        "get$capitalized_name$Map();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue);\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key);\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "java.util.Map<$type_parameters$>\n"
+          "get$capitalized_name$Value();\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
           "$deprecation$java.util.Map<$type_parameters$>\n"
-          "get$capitalized_name$Value();\n");
+          "get$capitalized_name$ValueMap();\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "$value_type$ get$capitalized_name$ValueOrDefault(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue);\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "$value_type$ get$capitalized_name$ValueOrThrow(\n"
+          "    $key_type$ key);\n");
     }
   } else {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "java.util.Map<$type_parameters$>\n"
+        "get$capitalized_name$();\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$java.util.Map<$type_parameters$>\n"
-        "get$capitalized_name$();\n");
+        "get$capitalized_name$Map();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "$value_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue);\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "$value_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key);\n");
   }
 }
 
@@ -196,9 +272,9 @@
   printer->Print(
       variables_,
       "private static final class $capitalized_name$DefaultEntryHolder {\n"
-      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "  static final com.google.protobuf.MapEntry<\n"
       "      $type_parameters$> defaultEntry =\n"
-      "          com.google.protobuf.MapEntry$lite$\n"
+      "          com.google.protobuf.MapEntry\n"
       "          .<$type_parameters$>newDefaultInstance(\n"
       "              $descriptor$\n"
       "              $key_wire_type$,\n"
@@ -208,12 +284,12 @@
       "}\n");
   printer->Print(
       variables_,
-      "private com.google.protobuf.MapField$lite$<\n"
+      "private com.google.protobuf.MapField<\n"
       "    $type_parameters$> $name$_;\n"
-      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "private com.google.protobuf.MapField<$type_parameters$>\n"
       "internalGet$capitalized_name$() {\n"
       "  if ($name$_ == null) {\n"
-      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "    return com.google.protobuf.MapField.emptyMapField(\n"
       "        $map_field_parameter$);\n"
       "  }\n"
       "  return $name$_;\n"
@@ -227,57 +303,29 @@
         "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
         "            $value_enum_type$.internalGetValueMap(),\n"
         "            $unrecognized_value$);\n");
-    if (SupportUnknownEnumValue(descriptor_->file())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(
-          variables_,
-          "$deprecation$\n"
-          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "get$capitalized_name$Value() {\n"
-          "  return internalGet$capitalized_name$().getMap();\n"
-          "}\n");
-    }
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
-        "$deprecation$\n"
-        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "get$capitalized_name$() {\n"
-        "  return new com.google.protobuf.Internal.MapAdapter<\n"
-        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          internalGet$capitalized_name$().getMap(),\n"
-        "          $name$ValueConverter);\n"
-        "}\n");
-  } else {
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
-        "$deprecation$\n"
-        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return internalGet$capitalized_name$().getMap();\n"
-        "}\n");
   }
+  GenerateMapGetters(printer);
 }
 
 void ImmutableMapFieldGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
   printer->Print(
       variables_,
-      "private com.google.protobuf.MapField$lite$<\n"
+      "private com.google.protobuf.MapField<\n"
       "    $type_parameters$> $name$_;\n"
-      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "private com.google.protobuf.MapField<$type_parameters$>\n"
       "internalGet$capitalized_name$() {\n"
       "  if ($name$_ == null) {\n"
-      "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
+      "    return com.google.protobuf.MapField.emptyMapField(\n"
       "        $map_field_parameter$);\n"
       "  }\n"
       "  return $name$_;\n"
       "}\n"
-      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "private com.google.protobuf.MapField<$type_parameters$>\n"
       "internalGetMutable$capitalized_name$() {\n"
       "  $on_changed$;\n"
       "  if ($name$_ == null) {\n"
-      "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+      "    $name$_ = com.google.protobuf.MapField.newMapField(\n"
       "        $map_field_parameter$);\n"
       "  }\n"
       "  if (!$name$_.isMutable()) {\n"
@@ -285,22 +333,31 @@
       "  }\n"
       "  return $name$_;\n"
       "}\n");
+  GenerateMapGetters(printer);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public Builder clear$capitalized_name$() {\n"
+      "  getMutable$capitalized_name$().clear();\n"
+      "  return this;\n"
+      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public Builder remove$capitalized_name$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  getMutable$capitalized_name$().remove(key);\n"
+      "  return this;\n"
+      "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
-    WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
-        "$deprecation$\n"
-        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "get$capitalized_name$() {\n"
-        "  return new com.google.protobuf.Internal.MapAdapter<\n"
-        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          internalGet$capitalized_name$().getMap(),\n"
-        "          $name$ValueConverter);\n"
-        "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
-        "$deprecation$\n"
+        "/**\n"
+        " * Use alternate mutation accessors instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
         "getMutable$capitalized_name$() {\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
@@ -311,27 +368,47 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
+        "$deprecation$public Builder put$capitalized_name$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
+        "  getMutable$capitalized_name$().put(key, value);\n"
+        "  return this;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        // TODO(arielb): null check map keys/values here and everywhere else
+        // related to putAll
         "$deprecation$public Builder putAll$capitalized_name$(\n"
         "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
         "  getMutable$capitalized_name$().putAll(values);\n"
         "  return this;\n"
         "}\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
-      WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
-          "$deprecation$\n"
+          "/**\n"
+          " * Use alternate mutation accessors instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "get$capitalized_name$Value() {\n"
-          "  return internalGet$capitalized_name$().getMap();\n"
+          "getMutable$capitalized_name$Value() {\n"
+          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
           "}\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
-          "$deprecation$\n"
-          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "getMutable$capitalized_name$Value() {\n"
-          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "$deprecation$public Builder put$capitalized_name$Value(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ value) {\n"
+          "  $key_null_check$\n"
+          "  if ($value_enum_type$.forNumber(value) == null) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  getMutable$capitalized_name$Value().put(key, value);\n"
+          "  return this;\n"
           "}\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
@@ -343,15 +420,12 @@
           "}\n");
     }
   } else {
-    WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
-        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return internalGet$capitalized_name$().getMap();\n"
-        "}\n");
-    WriteFieldDocComment(printer, descriptor_);
-    printer->Print(
-        variables_,
+        "/**\n"
+        " * Use alternate mutation accessors instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
         "public java.util.Map<$type_parameters$>\n"
         "getMutable$capitalized_name$() {\n"
         "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
@@ -359,7 +433,20 @@
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
-        "$deprecation$public Builder putAll$capitalized_name$(\n"
+        "$deprecation$"
+        "public Builder put$capitalized_name$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
+        "  getMutable$capitalized_name$().put(key, value);\n"
+        "  return this;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public Builder putAll$capitalized_name$(\n"
         "    java.util.Map<$type_parameters$> values) {\n"
         "  getMutable$capitalized_name$().putAll(values);\n"
         "  return this;\n"
@@ -368,6 +455,165 @@
 }
 
 void ImmutableMapFieldGenerator::
+GenerateMapGetters(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public int get$capitalized_name$Count() {\n"
+      "  return internalGet$capitalized_name$().getMap().size();\n"
+      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public boolean contains$capitalized_name$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  return internalGet$capitalized_name$().getMap().containsKey(key);\n"
+      "}\n");
+  if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return get$capitalized_name$Map();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$Map() {\n"
+        "  return new com.google.protobuf.Internal.MapAdapter<\n"
+        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "          internalGet$capitalized_name$().getMap(),\n"
+        "          $name$ValueConverter);\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  return map.containsKey(key)\n"
+        "         ? $name$ValueConverter.doForward(map.get(key))\n"
+        "         : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return $name$ValueConverter.doForward(map.get(key));\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return get$capitalized_name$ValueMap();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$ValueMap() {\n"
+          "  return internalGet$capitalized_name$().getMap();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$().getMap();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$().getMap();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+    }
+  } else {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
+        "  return get$capitalized_name$Map();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+        "  return internalGet$capitalized_name$().getMap();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$().getMap();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return map.get(key);\n"
+        "}\n");
+  }
+}
+
+void ImmutableMapFieldGenerator::
 GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
   // Nothing to initialize.
 }
@@ -405,7 +651,7 @@
   printer->Print(
       variables_,
       "if (!$get_mutable_bit_parser$) {\n"
-      "  $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
+      "  $name$_ = com.google.protobuf.MapField.newMapField(\n"
       "      $map_field_parameter$);\n"
       "  $set_mutable_bit_parser$;\n"
       "}\n");
@@ -414,7 +660,7 @@
     printer->Print(
         variables_,
         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
-        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "com.google.protobuf.MapEntry<$type_parameters$>\n"
         "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
     printer->Print(
         variables_,
@@ -426,7 +672,7 @@
   } else {
     printer->Print(
         variables_,
-        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+        "com.google.protobuf.MapEntry<$type_parameters$>\n"
         "$name$ = input.readMessage(\n"
         "    $default_entry$.getParserForType(), extensionRegistry);\n"
         "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
@@ -444,7 +690,7 @@
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
-      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  com.google.protobuf.MapEntry<$type_parameters$>\n"
       "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
@@ -459,7 +705,7 @@
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
-      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
+      "  com.google.protobuf.MapEntry<$type_parameters$>\n"
       "  $name$ = $default_entry$.newBuilderForType()\n"
       "      .setKey(entry.getKey())\n"
       "      .setValue(entry.getValue())\n"
diff --git a/src/google/protobuf/compiler/java/java_map_field.h b/src/google/protobuf/compiler/java/java_map_field.h
index f2768f3..ae7ce7c 100644
--- a/src/google/protobuf/compiler/java/java_map_field.h
+++ b/src/google/protobuf/compiler/java/java_map_field.h
@@ -69,6 +69,7 @@
   const FieldDescriptor* descriptor_;
   map<string, string> variables_;
   ClassNameResolver* name_resolver_;
+  void GenerateMapGetters(io::Printer* printer) const;
 };
 
 }  // namespace java
diff --git a/src/google/protobuf/compiler/java/java_map_field_lite.cc b/src/google/protobuf/compiler/java/java_map_field_lite.cc
index b80d413..0d3bea1 100644
--- a/src/google/protobuf/compiler/java/java_map_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_map_field_lite.cc
@@ -88,10 +88,18 @@
       name_resolver->GetImmutableClassName(descriptor->message_type());
   const FieldDescriptor* key = KeyField(descriptor);
   const FieldDescriptor* value = ValueField(descriptor);
+  const JavaType keyJavaType = GetJavaType(key);
+  const JavaType valueJavaType = GetJavaType(value);
+
   (*variables)["key_type"] = TypeName(key, name_resolver, false);
   (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
   (*variables)["key_wire_type"] = WireType(key);
   (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
+  (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ?
+      "if (key == null) { throw new java.lang.NullPointerException(); }" : "";
+  (*variables)["value_null_check"] = IsReferenceType(valueJavaType) ?
+      "if (value == null) { throw new java.lang.NullPointerException(); }" : "";
+
   if (GetJavaType(value) == JAVATYPE_ENUM) {
     // We store enums as Integers internally.
     (*variables)["value_type"] = "int";
@@ -127,8 +135,6 @@
 
   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
       "DefaultEntryHolder.defaultEntry";
-  (*variables)["lite"] = "Lite";
-  (*variables)["descriptor"] = "";
 }
 
 }  // namespace
@@ -157,25 +163,95 @@
 
 void ImmutableMapFieldLiteGenerator::
 GenerateInterfaceMembers(io::Printer* printer) const {
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$int get$capitalized_name$Count();\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$boolean contains$capitalized_name$(\n"
+      "    $key_type$ key);\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$();\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "get$capitalized_name$();\n");
+        "get$capitalized_name$Map();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue);\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$$value_enum_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key);\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "java.util.Map<$type_parameters$>\n"
+          "get$capitalized_name$Value();\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
           "$deprecation$java.util.Map<$type_parameters$>\n"
-          "get$capitalized_name$Value();\n");
+          "get$capitalized_name$ValueMap();\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "$value_type$ get$capitalized_name$ValueOrDefault(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue);\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "$value_type$ get$capitalized_name$ValueOrThrow(\n"
+          "    $key_type$ key);\n");
     }
   } else {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "java.util.Map<$type_parameters$>\n"
+        "get$capitalized_name$();\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$java.util.Map<$type_parameters$>\n"
-        "get$capitalized_name$();\n");
+        "get$capitalized_name$Map();\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "$value_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue);\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "$value_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key);\n");
   }
 }
 
@@ -184,11 +260,10 @@
   printer->Print(
       variables_,
       "private static final class $capitalized_name$DefaultEntryHolder {\n"
-      "  static final com.google.protobuf.MapEntry$lite$<\n"
+      "  static final com.google.protobuf.MapEntryLite<\n"
       "      $type_parameters$> defaultEntry =\n"
-      "          com.google.protobuf.MapEntry$lite$\n"
+      "          com.google.protobuf.MapEntryLite\n"
       "          .<$type_parameters$>newDefaultInstance(\n"
-      "              $descriptor$\n"
       "              $key_wire_type$,\n"
       "              $key_default_value$,\n"
       "              $value_wire_type$,\n"
@@ -196,20 +271,35 @@
       "}\n");
   printer->Print(
       variables_,
-      "private com.google.protobuf.MapField$lite$<\n"
+      "private com.google.protobuf.MapFieldLite<\n"
       "    $type_parameters$> $name$_ =\n"
-      "        com.google.protobuf.MapField$lite$.emptyMapField();\n"
-      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "        com.google.protobuf.MapFieldLite.emptyMapField();\n"
+      "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
       "internalGet$capitalized_name$() {\n"
       "  return $name$_;\n"
       "}\n"
-      "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
+      "private com.google.protobuf.MapFieldLite<$type_parameters$>\n"
       "internalGetMutable$capitalized_name$() {\n"
       "  if (!$name$_.isMutable()) {\n"
-      "    $name$_ = $name$_.copy();\n"
+      "    $name$_ = $name$_.mutableCopy();\n"
       "  }\n"
       "  return $name$_;\n"
       "}\n");
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public int get$capitalized_name$Count() {\n"
+      "  return internalGet$capitalized_name$().size();\n"
+      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public boolean contains$capitalized_name$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  return internalGet$capitalized_name$().containsKey(key);\n"
+      "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
     printer->Print(
         variables_,
@@ -219,34 +309,146 @@
         "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
         "            $value_enum_type$.internalGetValueMap(),\n"
         "            $unrecognized_value$);\n");
-    if (SupportUnknownEnumValue(descriptor_->file())) {
-      WriteFieldDocComment(printer, descriptor_);
-      printer->Print(
-          variables_,
-          "$deprecation$\n"
-          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "get$capitalized_name$Value() {\n"
-          "  return internalGet$capitalized_name$().getMap();\n"
-          "}\n");
-    }
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
+        "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
+        "get$capitalized_name$() {\n"
+        "  return get$capitalized_name$Map();\n"
+        "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "get$capitalized_name$() {\n"
-        "  return new com.google.protobuf.Internal.MapAdapter<\n"
-        "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          internalGet$capitalized_name$().getMap(),\n"
-        "          $name$ValueConverter);\n"
+        "get$capitalized_name$Map() {\n"
+        "  return java.util.Collections.unmodifiableMap(\n"
+        "      new com.google.protobuf.Internal.MapAdapter<\n"
+        "        $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
+        "            internalGet$capitalized_name$(),\n"
+        "            $name$ValueConverter));\n"
         "}\n");
-  } else {
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  return map.containsKey(key)\n"
+        "         ? $name$ValueConverter.doForward(map.get(key))\n"
+        "         : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return $name$ValueConverter.doForward(map.get(key));\n"
+        "}\n");
+    if (SupportUnknownEnumValue(descriptor_->file())) {
+      printer->Print(
+          variables_,
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$Value() {\n"
+          "  return get$capitalized_name$ValueMap();\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
+          "get$capitalized_name$ValueMap() {\n"
+          "  return java.util.Collections.unmodifiableMap(\n"
+          "      internalGet$capitalized_name$());\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      internalGet$capitalized_name$();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+    }
+  } else {
+    printer->Print(
+        variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return internalGet$capitalized_name$().getMap();\n"
+        "  return get$capitalized_name$Map();\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+        "  return java.util.Collections.unmodifiableMap(\n"
+        "      internalGet$capitalized_name$());\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      internalGet$capitalized_name$();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return map.get(key);\n"
         "}\n");
   }
 
@@ -256,10 +458,10 @@
     printer->Print(
         variables_,
         "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "getMutable$capitalized_name$() {\n"
+        "getMutable$capitalized_name$Map() {\n"
         "  return new com.google.protobuf.Internal.MapAdapter<\n"
         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
-        "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
+        "          internalGetMutable$capitalized_name$(),\n"
         "          $name$ValueConverter);\n"
         "}\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
@@ -267,8 +469,8 @@
       printer->Print(
           variables_,
           "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "getMutable$capitalized_name$Value() {\n"
-          "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+          "getMutable$capitalized_name$ValueMap() {\n"
+          "  return internalGetMutable$capitalized_name$();\n"
           "}\n");
     }
   } else {
@@ -276,88 +478,252 @@
     printer->Print(
         variables_,
         "private java.util.Map<$type_parameters$>\n"
-        "getMutable$capitalized_name$() {\n"
-        "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
+        "getMutable$capitalized_name$Map() {\n"
+        "  return internalGetMutable$capitalized_name$();\n"
         "}\n");
   }
 }
 
 void ImmutableMapFieldLiteGenerator::
 GenerateBuilderMembers(io::Printer* printer) const {
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public int get$capitalized_name$Count() {\n"
+      "  return instance.get$capitalized_name$Map().size();\n"
+      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public boolean contains$capitalized_name$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  return instance.get$capitalized_name$Map().containsKey(key);\n"
+      "}\n");
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public Builder clear$capitalized_name$() {\n"
+      "  copyOnWrite();\n"
+      "  instance.getMutable$capitalized_name$Map().clear();\n"
+      "  return this;\n"
+      "}\n");
+  WriteFieldDocComment(printer, descriptor_);
+  printer->Print(
+      variables_,
+      "$deprecation$\n"
+      "public Builder remove$capitalized_name$(\n"
+      "    $key_type$ key) {\n"
+      "  $key_null_check$\n"
+      "  copyOnWrite();\n"
+      "  instance.getMutable$capitalized_name$Map().remove(key);\n"
+      "  return this;\n"
+      "}\n");
   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
-    WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
-        "$deprecation$\n"
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
         "get$capitalized_name$() {\n"
-        "  return instance.get$capitalized_name$();\n"
+        "  return get$capitalized_name$Map();\n"
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$\n"
         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
-        "getMutable$capitalized_name$() {\n"
+        "get$capitalized_name$Map() {\n"
+        "  return java.util.Collections.unmodifiableMap(\n"
+        "      instance.get$capitalized_name$Map());\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  return map.containsKey(key)\n"
+        "         ? map.get(key)\n"
+        "         : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$boxed_key_type$, $value_enum_type$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return map.get(key);\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$public Builder put$capitalized_name$(\n"
+        "    $key_type$ key,\n"
+        "    $value_enum_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
         "  copyOnWrite();\n"
-        "  return instance.getMutable$capitalized_name$();\n"
+        "  instance.getMutable$capitalized_name$Map().put(key, value);\n"
+        "  return this;\n"
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
         "$deprecation$public Builder putAll$capitalized_name$(\n"
         "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
-        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().putAll(values);\n"
         "  return this;\n"
         "}\n");
     if (SupportUnknownEnumValue(descriptor_->file())) {
-      WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
-          "$deprecation$\n"
+          "/**\n"
+          " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
+          " */\n"
+          "@java.lang.Deprecated\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
           "get$capitalized_name$Value() {\n"
-          "  return instance.get$capitalized_name$Value();\n"
+          "  return get$capitalized_name$ValueMap();\n"
           "}\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
           "$deprecation$\n"
           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
-          "getMutable$capitalized_name$Value() {\n"
+          "get$capitalized_name$ValueMap() {\n"
+          "  return java.util.Collections.unmodifiableMap(\n"
+          "      instance.get$capitalized_name$ValueMap());\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ defaultValue) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      instance.get$capitalized_name$ValueMap();\n"
+          "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$\n"
+          "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
+          "    $key_type$ key) {\n"
+          "  $key_null_check$\n"
+          "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
+          "      instance.get$capitalized_name$ValueMap();\n"
+          "  if (!map.containsKey(key)) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
+          "  return map.get(key);\n"
+          "}\n");
+      WriteFieldDocComment(printer, descriptor_);
+      printer->Print(
+          variables_,
+          "$deprecation$public Builder put$capitalized_name$Value(\n"
+          "    $key_type$ key,\n"
+          "    $value_type$ value) {\n"
+          "  $key_null_check$\n"
+          "  if ($value_enum_type$.forNumber(value) == null) {\n"
+          "    throw new java.lang.IllegalArgumentException();\n"
+          "  }\n"
           "  copyOnWrite();\n"
-          "  return instance.getMutable$capitalized_name$Value();\n"
+          "  instance.getMutable$capitalized_name$ValueMap().put(key, value);\n"
+          "  return this;\n"
           "}\n");
       WriteFieldDocComment(printer, descriptor_);
       printer->Print(
           variables_,
           "$deprecation$public Builder putAll$capitalized_name$Value(\n"
           "    java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
-          "  getMutable$capitalized_name$Value().putAll(values);\n"
+          "  copyOnWrite();\n"
+          "  instance.getMutable$capitalized_name$ValueMap().putAll(values);\n"
           "  return this;\n"
           "}\n");
     }
   } else {
-    WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
+        "/**\n"
+        " * Use {@link #get$capitalized_name$Map()} instead.\n"
+        " */\n"
+        "@java.lang.Deprecated\n"
         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
-        "  return instance.get$capitalized_name$();\n"
+        "  return get$capitalized_name$Map();\n"
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
-        "public java.util.Map<$type_parameters$>\n"
-        "getMutable$capitalized_name$() {\n"
+        "$deprecation$"
+        "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
+        "  return java.util.Collections.unmodifiableMap(\n"
+        "      instance.get$capitalized_name$Map());\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrDefault(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ defaultValue) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$\n"
+        "public $value_type$ get$capitalized_name$OrThrow(\n"
+        "    $key_type$ key) {\n"
+        "  $key_null_check$\n"
+        "  java.util.Map<$type_parameters$> map =\n"
+        "      instance.get$capitalized_name$Map();\n"
+        "  if (!map.containsKey(key)) {\n"
+        "    throw new java.lang.IllegalArgumentException();\n"
+        "  }\n"
+        "  return map.get(key);\n"
+        "}\n");
+    WriteFieldDocComment(printer, descriptor_);
+    printer->Print(
+        variables_,
+        "$deprecation$"
+        "public Builder put$capitalized_name$(\n"
+        "    $key_type$ key,\n"
+        "    $value_type$ value) {\n"
+        "  $key_null_check$\n"
+        "  $value_null_check$\n"
         "  copyOnWrite();\n"
-        "  return instance.getMutable$capitalized_name$();\n"
+        "  instance.getMutable$capitalized_name$Map().put(key, value);\n"
+        "  return this;\n"
         "}\n");
     WriteFieldDocComment(printer, descriptor_);
     printer->Print(
         variables_,
+        "$deprecation$"
         "public Builder putAll$capitalized_name$(\n"
         "    java.util.Map<$type_parameters$> values) {\n"
-        "  getMutable$capitalized_name$().putAll(values);\n"
+        "  copyOnWrite();\n"
+        "  instance.getMutable$capitalized_name$Map().putAll(values);\n"
         "  return this;\n"
         "}\n");
   }
@@ -377,8 +743,8 @@
 GenerateVisitCode(io::Printer* printer) const {
   printer->Print(
       variables_,
-      "$name$_ = visitor.visitMap(internalGetMutable$capitalized_name$(),\n"
-      "    other.internalGet$capitalized_name$());\n");
+      "$name$_ = visitor.visitMap(\n"
+      "    $name$_, other.internalGet$capitalized_name$());\n");
 }
 
 void ImmutableMapFieldLiteGenerator::
@@ -392,29 +758,26 @@
   printer->Print(
       variables_,
       "if (!$name$_.isMutable()) {\n"
-      "  $name$_ = $name$_.copy();\n"
+      "  $name$_ = $name$_.mutableCopy();\n"
       "}\n");
   if (!SupportUnknownEnumValue(descriptor_->file()) &&
       GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
     printer->Print(
         variables_,
         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
-        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-        "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
+        "java.util.Map.Entry<$type_parameters$> $name$ =\n"
+        "    $default_entry$.parseEntry(bytes, extensionRegistry);\n");
     printer->Print(
         variables_,
         "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
         "  super.mergeLengthDelimitedField($number$, bytes);\n"
         "} else {\n"
-        "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
+        "  $name$_.put($name$);\n"
         "}\n");
   } else {
     printer->Print(
         variables_,
-        "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-        "$name$ = input.readMessage(\n"
-        "    $default_entry$.getParserForType(), extensionRegistry);\n"
-        "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
+        "$default_entry$.parseInto($name$_, input, extensionRegistry);");
   }
 }
 
@@ -428,13 +791,9 @@
   printer->Print(
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
-      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
-      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $default_entry$.newBuilderForType()\n"
-      "      .setKey(entry.getKey())\n"
-      "      .setValue(entry.getValue())\n"
-      "      .build();\n"
-      "  output.writeMessage($number$, $name$);\n"
+      "     : internalGet$capitalized_name$().entrySet()) {\n"
+      "  $default_entry$.serializeTo(\n"
+      "      output, $number$, entry.getKey(), entry.getValue());\n"
       "}\n");
 }
 
@@ -443,14 +802,9 @@
   printer->Print(
       variables_,
       "for (java.util.Map.Entry<$type_parameters$> entry\n"
-      "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
-      "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
-      "  $name$ = $default_entry$.newBuilderForType()\n"
-      "      .setKey(entry.getKey())\n"
-      "      .setValue(entry.getValue())\n"
-      "      .build();\n"
-      "  size += com.google.protobuf.CodedOutputStream\n"
-      "      .computeMessageSize($number$, $name$);\n"
+      "     : internalGet$capitalized_name$().entrySet()) {\n"
+      "  size += $default_entry$.computeMessageSize(\n"
+      "    $number$, entry.getKey(), entry.getValue());\n"
       "}\n");
 }
 
@@ -466,7 +820,7 @@
 GenerateHashCode(io::Printer* printer) const {
   printer->Print(
       variables_,
-      "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
+      "if (!internalGet$capitalized_name$().isEmpty()) {\n"
       "  hash = (37 * hash) + $constant_name$;\n"
       "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
       "}\n");
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 4c474a4..d55a984 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -248,22 +248,27 @@
 // ===================================================================
 
 void ImmutableMessageGenerator::GenerateInterface(io::Printer* printer) {
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true, "OrBuilder");
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
-      "public interface $classname$OrBuilder extends\n"
-      "    $extra_interfaces$\n"
-      "    com.google.protobuf.GeneratedMessage.\n"
-      "        ExtendableMessageOrBuilder<$classname$> {\n",
-      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-      "classname", descriptor_->name());
+        "public interface $classname$OrBuilder$idend$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.GeneratedMessage.\n"
+        "        ExtendableMessageOrBuilder<$classname$> {\n",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(),
+        "idend", "");
   } else {
     printer->Print(
-      "public interface $classname$OrBuilder extends\n"
-      "    $extra_interfaces$\n"
-      "    com.google.protobuf.MessageOrBuilder {\n",
-      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-      "classname", descriptor_->name());
+        "public interface $classname$OrBuilder$idend$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.MessageOrBuilder {\n",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(),
+        "idend", "");
   }
+  printer->Annotate("classname", "idend", descriptor_);
 
   printer->Indent();
     for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -291,9 +296,7 @@
 // ===================================================================
 
 void ImmutableMessageGenerator::Generate(io::Printer* printer) {
-  bool is_own_file =
-    descriptor_->containing_type() == NULL &&
-    MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
 
   map<string, string> variables;
   variables["static"] = is_own_file ? " " : " static ";
@@ -301,22 +304,29 @@
   variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
 
   WriteMessageDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
 
   // The builder_type stores the super type name of the nested Builder class.
   string builder_type;
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(variables,
-      "public $static$final class $classname$ extends\n"
-      "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
-      "      $classname$> implements\n"
-      "    $extra_interfaces$\n"
-      "    $classname$OrBuilder {\n");
+                   "public $static$final class $classname$ extends\n");
+    printer->Annotate("classname", descriptor_);
+    printer->Print(
+        variables,
+        "    com.google.protobuf.GeneratedMessage.ExtendableMessage<\n"
+        "      $classname$> implements\n"
+        "    $extra_interfaces$\n"
+        "    $classname$OrBuilder {\n");
     builder_type = strings::Substitute(
              "com.google.protobuf.GeneratedMessage.ExtendableBuilder<$0, ?>",
              name_resolver_->GetImmutableClassName(descriptor_));
   } else {
     printer->Print(variables,
-      "public $static$final class $classname$ extends\n"
+                   "public $static$final class $classname$ extends\n");
+    printer->Annotate("classname", descriptor_);
+    printer->Print(variables,
       "    com.google.protobuf.GeneratedMessage implements\n"
       "    $extra_interfaces$\n"
       "    $classname$OrBuilder {\n");
@@ -485,9 +495,6 @@
   if (context_->HasGeneratedMethods(descriptor_)) {
     GenerateIsInitialized(printer);
     GenerateMessageSerializationMethods(printer);
-  }
-
-  if (HasEqualsAndHashCode(descriptor_)) {
     GenerateEqualsAndHashCode(printer);
   }
 
@@ -1225,8 +1232,7 @@
       "default: {\n"
       "  if (!input.skipField(tag)) {\n"
       "    done = true;\n"  // it's an endgroup tag
-      "  }\n");
-    printer->Print(
+      "  }\n"
       "  break;\n"
       "}\n");
   }
diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h
index e9fc57c..da1447c 100644
--- a/src/google/protobuf/compiler/java/java_message.h
+++ b/src/google/protobuf/compiler/java/java_message.h
@@ -92,8 +92,7 @@
 
 class ImmutableMessageGenerator : public MessageGenerator {
  public:
-  explicit ImmutableMessageGenerator(const Descriptor* descriptor,
-                                     Context* context);
+  ImmutableMessageGenerator(const Descriptor* descriptor, Context* context);
   virtual ~ImmutableMessageGenerator();
 
   virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index 455516f..cc627b5 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -71,6 +71,10 @@
   (*variables)["deprecation"] = descriptor->options().deprecated()
       ? "@java.lang.Deprecated " : "";
   (*variables)["on_changed"] = "onChanged();";
+  (*variables)["ver"] = GeneratedCodeVersionSuffix();
+  (*variables)["get_parser"] =
+      ExposePublicParser(descriptor->message_type()->file())
+          ? "PARSER" : "parser()";
 
   if (SupportFieldPresence(descriptor->file())) {
     // For singular messages and builders, one bit is used for the hasField bit.
@@ -252,7 +256,7 @@
   printer->Print(variables_,
       // If this builder is non-null, it is used and the other fields are
       // ignored.
-      "private com.google.protobuf.SingleFieldBuilder<\n"
+      "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
       "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
       "\n");
 
@@ -374,11 +378,11 @@
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
-    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> \n"
     "    get$capitalized_name$FieldBuilder() {\n"
     "  if ($name$Builder_ == null) {\n"
-    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "        $type$, $type$.Builder, $type$OrBuilder>(\n"
     "            get$capitalized_name$(),\n"
     "            getParentForChildren(),\n"
@@ -451,11 +455,11 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$name$_ = input.readGroup($number$, $type$.parser(),\n"
+      "$name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
       "    extensionRegistry);\n");
   } else {
     printer->Print(variables_,
-      "$name$_ = input.readMessage($type$.parser(), extensionRegistry);\n");
+      "$name$_ = input.readMessage($type$.$get_parser$, extensionRegistry);\n");
   }
 
   printer->Print(variables_,
@@ -560,7 +564,7 @@
   printer->Print(variables_,
     // If this builder is non-null, it is used and the other fields are
     // ignored.
-    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;"
     "\n");
 
@@ -683,14 +687,14 @@
     "}\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
-    "private com.google.protobuf.SingleFieldBuilder<\n"
+    "private com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> \n"
     "    get$capitalized_name$FieldBuilder() {\n"
     "  if ($name$Builder_ == null) {\n"
     "    if (!($has_oneof_case_message$)) {\n"
     "      $oneof_name$_ = $type$.getDefaultInstance();\n"
     "    }\n"
-    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder<\n"
+    "    $name$Builder_ = new com.google.protobuf.SingleFieldBuilder$ver$<\n"
     "        $type$, $type$.Builder, $type$OrBuilder>(\n"
     "            ($type$) $oneof_name$_,\n"
     "            getParentForChildren(),\n"
@@ -735,12 +739,12 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$oneof_name$_ = input.readGroup($number$, $type$.parser(),\n"
+      "$oneof_name$_ = input.readGroup($number$, $type$.$get_parser$,\n"
       "    extensionRegistry);\n");
   } else {
     printer->Print(variables_,
       "$oneof_name$_ =\n"
-      "    input.readMessage($type$.parser(), extensionRegistry);\n");
+      "    input.readMessage($type$.$get_parser$, extensionRegistry);\n");
   }
 
   printer->Print(variables_,
@@ -920,7 +924,7 @@
   printer->Print(variables_,
     // If this builder is non-null, it is used and the other fields are
     // ignored.
-    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> $name$Builder_;\n"
     "\n");
 
@@ -1137,11 +1141,11 @@
     "     get$capitalized_name$BuilderList() {\n"
     "  return get$capitalized_name$FieldBuilder().getBuilderList();\n"
     "}\n"
-    "private com.google.protobuf.RepeatedFieldBuilder<\n"
+    "private com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "    $type$, $type$.Builder, $type$OrBuilder> \n"
     "    get$capitalized_name$FieldBuilder() {\n"
     "  if ($name$Builder_ == null) {\n"
-    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder<\n"
+    "    $name$Builder_ = new com.google.protobuf.RepeatedFieldBuilder$ver$<\n"
     "        $type$, $type$.Builder, $type$OrBuilder>(\n"
     "            $name$_,\n"
     "            $get_mutable_bit_builder$,\n"
@@ -1232,11 +1236,12 @@
 
   if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) {
     printer->Print(variables_,
-      "$name$_.add(input.readGroup($number$, $type$.parser(),\n"
+      "$name$_.add(input.readGroup($number$, $type$.$get_parser$,\n"
       "    extensionRegistry));\n");
   } else {
     printer->Print(variables_,
-      "$name$_.add(input.readMessage($type$.parser(), extensionRegistry));\n");
+      "$name$_.add(\n"
+      "    input.readMessage($type$.$get_parser$, extensionRegistry));\n");
   }
 }
 
diff --git a/src/google/protobuf/compiler/java/java_message_lite.cc b/src/google/protobuf/compiler/java/java_message_lite.cc
index d4d2593..7c8c4a0 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.cc
+++ b/src/google/protobuf/compiler/java/java_message_lite.cc
@@ -120,23 +120,28 @@
 // ===================================================================
 
 void ImmutableMessageLiteGenerator::GenerateInterface(io::Printer* printer) {
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true, "OrBuilder");
   if (descriptor_->extension_range_count() > 0) {
     printer->Print(
-      "public interface $classname$OrBuilder extends \n"
-      "    $extra_interfaces$\n"
-      "     com.google.protobuf.GeneratedMessageLite.\n"
-      "          ExtendableMessageOrBuilder<\n"
-      "              $classname$, $classname$.Builder> {\n",
-      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-      "classname", descriptor_->name());
+        "public interface $classname$OrBuilder$idend$ extends \n"
+        "    $extra_interfaces$\n"
+        "     com.google.protobuf.GeneratedMessageLite.\n"
+        "          ExtendableMessageOrBuilder<\n"
+        "              $classname$, $classname$.Builder> {\n",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(),
+        "idend", "");
   } else {
     printer->Print(
-      "public interface $classname$OrBuilder extends\n"
-      "    $extra_interfaces$\n"
-      "    com.google.protobuf.MessageLiteOrBuilder {\n",
-      "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
-      "classname", descriptor_->name());
+        "public interface $classname$OrBuilder$idend$ extends\n"
+        "    $extra_interfaces$\n"
+        "    com.google.protobuf.MessageLiteOrBuilder {\n",
+        "extra_interfaces", ExtraMessageOrBuilderInterfaces(descriptor_),
+        "classname", descriptor_->name(),
+        "idend", "");
   }
+  printer->Annotate("classname", "idend", descriptor_);
 
   printer->Indent();
     for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -163,9 +168,7 @@
 // ===================================================================
 
 void ImmutableMessageLiteGenerator::Generate(io::Printer* printer) {
-  bool is_own_file =
-    descriptor_->containing_type() == NULL &&
-    MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
 
   map<string, string> variables;
   variables["static"] = is_own_file ? " " : " static ";
@@ -173,6 +176,8 @@
   variables["extra_interfaces"] = ExtraMessageInterfaces(descriptor_);
 
   WriteMessageDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
 
   // The builder_type stores the super type name of the nested Builder class.
   string builder_type;
diff --git a/src/google/protobuf/compiler/java/java_message_lite.h b/src/google/protobuf/compiler/java/java_message_lite.h
index 292c1c5..1e319c6 100644
--- a/src/google/protobuf/compiler/java/java_message_lite.h
+++ b/src/google/protobuf/compiler/java/java_message_lite.h
@@ -47,8 +47,7 @@
 
 class ImmutableMessageLiteGenerator : public MessageGenerator {
  public:
-  explicit ImmutableMessageLiteGenerator(const Descriptor* descriptor,
-                                     Context* context);
+  ImmutableMessageLiteGenerator(const Descriptor* descriptor, Context* context);
   virtual ~ImmutableMessageLiteGenerator();
 
   virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_options.h b/src/google/protobuf/compiler/java/java_options.h
new file mode 100644
index 0000000..7bce144
--- /dev/null
+++ b/src/google/protobuf/compiler/java/java_options.h
@@ -0,0 +1,73 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// 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.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
+
+#include <string>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace java {
+
+// Generator options
+struct Options {
+  Options()
+      : generate_immutable_code(false),
+        generate_mutable_code(false),
+        generate_shared_code(false),
+        enforce_lite(false),
+        annotate_code(false) {
+  }
+
+  bool generate_immutable_code;
+  bool generate_mutable_code;
+  bool generate_shared_code;
+  // When set, the protoc will generate the current files and all the transitive
+  // dependencies as lite runtime.
+  bool enforce_lite;
+  // If true, we should build .meta files and emit @Generated annotations into
+  // generated code.
+  bool annotate_code;
+  // Name of a file where we will write a list of generated .meta file names,
+  // one per line.
+  string annotation_list_file;
+  // Name of a file where we will write a list of generated file names, one
+  // per line.
+  string output_list_file;
+};
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_OPTIONS_H__
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index e42ec28..877baf0 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -777,8 +777,8 @@
     // That makes it safe to rely on the memoized size here.
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "  output.writeUInt32NoTag($tag$);\n"
+      "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  output.write$capitalized_type$NoTag($name$_.get(i));\n"
diff --git a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
index 690dad1..ad2db30 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field_lite.cc
@@ -63,22 +63,20 @@
                            ClassNameResolver* name_resolver,
                            map<string, string>* variables) {
   SetCommonFieldVariables(descriptor, info, variables);
-
-  (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
-  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  JavaType javaType = GetJavaType(descriptor);
+  (*variables)["type"] = PrimitiveTypeName(javaType);
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(javaType);
   (*variables)["field_type"] = (*variables)["type"];
   (*variables)["default"] = ImmutableDefaultValue(descriptor, name_resolver);
-  (*variables)["default_init"] = IsDefaultValueJavaDefault(descriptor) ?
-      "" : ("= " + ImmutableDefaultValue(descriptor, name_resolver));
   (*variables)["capitalized_type"] =
       GetCapitalizedType(descriptor, /* immutable = */ true);
   (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
   (*variables)["tag_size"] = SimpleItoa(
       WireFormat::TagSize(descriptor->number(), GetType(descriptor)));
 
-  string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(
-        GetJavaType(descriptor)), true /* cap_next_letter */);
-  switch (GetJavaType(descriptor)) {
+  string capitalized_type = UnderscoresToCamelCase(PrimitiveTypeName(javaType),
+                                                   true /* cap_next_letter */);
+  switch (javaType) {
     case JAVATYPE_INT:
     case JAVATYPE_LONG:
     case JAVATYPE_FLOAT:
@@ -112,7 +110,12 @@
       (*variables)["visit_type_list"] = "visitList";
   }
 
-  if (IsReferenceType(GetJavaType(descriptor))) {
+  if (javaType == JAVATYPE_BYTES) {
+    (*variables)["bytes_default"] =
+        ToUpper((*variables)["name"]) + "_DEFAULT_VALUE";
+  }
+
+  if (IsReferenceType(javaType)) {
     (*variables)["null_check"] =
         "  if (value == null) {\n"
         "    throw new NullPointerException();\n"
@@ -204,6 +207,13 @@
 
 void ImmutablePrimitiveFieldLiteGenerator::
 GenerateMembers(io::Printer* printer) const {
+  if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+    // allocate this once statically since we know ByteStrings are immutable
+    // values that can be reused.
+    printer->Print(
+        variables_,
+        "private static final $field_type$ $bytes_default$ = $default$;\n");
+  }
   printer->Print(variables_,
     "private $field_type$ $name$_;\n");
   PrintExtraFieldInfo(variables_, printer);
@@ -287,7 +297,11 @@
 
 void ImmutablePrimitiveFieldLiteGenerator::
 GenerateInitializationCode(io::Printer* printer) const {
-  printer->Print(variables_, "$name$_ = $default$;\n");
+  if (IsByteStringWithCustomDefaultValue(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $bytes_default$;\n");
+  } else if (!IsDefaultValueJavaDefault(descriptor_)) {
+    printer->Print(variables_, "$name$_ = $default$;\n");
+  }
 }
 
 void ImmutablePrimitiveFieldLiteGenerator::
@@ -817,8 +831,8 @@
     // That makes it safe to rely on the memoized size here.
     printer->Print(variables_,
       "if (get$capitalized_name$List().size() > 0) {\n"
-      "  output.writeRawVarint32($tag$);\n"
-      "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+      "  output.writeUInt32NoTag($tag$);\n"
+      "  output.writeUInt32NoTag($name$MemoizedSerializedSize);\n"
       "}\n"
       "for (int i = 0; i < $name$_.size(); i++) {\n"
       "  output.write$capitalized_type$NoTag($repeated_get$(i));\n"
diff --git a/src/google/protobuf/compiler/java/java_service.cc b/src/google/protobuf/compiler/java/java_service.cc
index 11bfc12..9f34f01 100644
--- a/src/google/protobuf/compiler/java/java_service.cc
+++ b/src/google/protobuf/compiler/java/java_service.cc
@@ -60,9 +60,10 @@
 ImmutableServiceGenerator::~ImmutableServiceGenerator() {}
 
 void ImmutableServiceGenerator::Generate(io::Printer* printer) {
-  bool is_own_file =
-    MultipleJavaFiles(descriptor_->file(), /* immutable = */ true);
+  bool is_own_file = IsOwnFile(descriptor_, /* immutable = */ true);
   WriteServiceDocComment(printer, descriptor_);
+  MaybePrintGeneratedAnnotation(context_, printer, descriptor_,
+                                /* immutable = */ true);
   printer->Print(
     "public $static$ abstract class $classname$\n"
     "    implements com.google.protobuf.Service {\n",
diff --git a/src/google/protobuf/compiler/java/java_service.h b/src/google/protobuf/compiler/java/java_service.h
index 6707e82..5fc9e2f 100644
--- a/src/google/protobuf/compiler/java/java_service.h
+++ b/src/google/protobuf/compiler/java/java_service.h
@@ -74,8 +74,8 @@
 
 class ImmutableServiceGenerator : public ServiceGenerator {
  public:
-  explicit ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
-                                     Context* context);
+  ImmutableServiceGenerator(const ServiceDescriptor* descriptor,
+                            Context* context);
   virtual ~ImmutableServiceGenerator();
 
   virtual void Generate(io::Printer* printer);
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.cc b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
index 74253c3..5289372 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.cc
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.cc
@@ -51,44 +51,53 @@
 namespace compiler {
 namespace java {
 
-SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file)
-    : name_resolver_(new ClassNameResolver),
-      enforce_lite_(false),
-      file_(file) {}
+SharedCodeGenerator::SharedCodeGenerator(const FileDescriptor* file,
+                                         const Options& options)
+    : name_resolver_(new ClassNameResolver), file_(file), options_(options) {}
 
 SharedCodeGenerator::~SharedCodeGenerator() {
 }
 
 void SharedCodeGenerator::Generate(GeneratorContext* context,
-                                   vector<string>* file_list) {
+                                   vector<string>* file_list,
+                                   vector<string>* annotation_file_list) {
   string java_package = FileJavaPackage(file_);
   string package_dir = JavaPackageToDir(java_package);
 
-  if (HasDescriptorMethods(file_, enforce_lite_)) {
+  if (HasDescriptorMethods(file_, options_.enforce_lite)) {
     // Generate descriptors.
     string classname = name_resolver_->GetDescriptorClassName(file_);
     string filename = package_dir + classname + ".java";
     file_list->push_back(filename);
     google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(context->Open(filename));
-    google::protobuf::scoped_ptr<io::Printer> printer(new io::Printer(output.get(), '$'));
-
+    GeneratedCodeInfo annotations;
+    io::AnnotationProtoCollector<GeneratedCodeInfo> annotation_collector(
+        &annotations);
+    google::protobuf::scoped_ptr<io::Printer> printer(
+        new io::Printer(output.get(), '$',
+                        options_.annotate_code ? &annotation_collector : NULL));
+    string info_relative_path = classname + ".java.pb.meta";
+    string info_full_path = filename + ".pb.meta";
     printer->Print(
-      "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
-      "// source: $filename$\n"
-      "\n",
-      "filename", file_->name());
+        "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+        "// source: $filename$\n"
+        "\n",
+        "filename", file_->name());
     if (!java_package.empty()) {
       printer->Print(
         "package $package$;\n"
         "\n",
         "package", java_package);
     }
+    PrintGeneratedAnnotation(printer.get(), '$',
+                             options_.annotate_code ? info_relative_path : "");
     printer->Print(
-      "public final class $classname$ {\n"
-      "  public static com.google.protobuf.Descriptors.FileDescriptor\n"
-      "      descriptor;\n"
-      "  static {\n",
-      "classname", classname);
+        "public final class $classname$ {\n"
+        "  public static com.google.protobuf.Descriptors.FileDescriptor\n"
+        "      descriptor;\n"
+        "  static {\n",
+        "classname", classname);
+    printer->Annotate("classname", file_->name());
     printer->Indent();
     printer->Indent();
     GenerateDescriptors(printer.get());
@@ -98,6 +107,13 @@
       "  }\n"
       "}\n");
 
+    if (options_.annotate_code) {
+      google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> info_output(
+          context->Open(info_full_path));
+      annotations.SerializeToZeroCopyStream(info_output.get());
+      annotation_file_list->push_back(info_full_path);
+    }
+
     printer.reset();
     output.reset();
   }
diff --git a/src/google/protobuf/compiler/java/java_shared_code_generator.h b/src/google/protobuf/compiler/java/java_shared_code_generator.h
index 3b573c0..7e1e1f1 100644
--- a/src/google/protobuf/compiler/java/java_shared_code_generator.h
+++ b/src/google/protobuf/compiler/java/java_shared_code_generator.h
@@ -43,6 +43,7 @@
 #include <vector>
 
 #include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/java/java_options.h>
 
 namespace google {
 namespace protobuf {
@@ -66,15 +67,11 @@
 // and mutable API. Currently only descriptors are shared.
 class SharedCodeGenerator {
  public:
-  explicit SharedCodeGenerator(const FileDescriptor* file);
+  SharedCodeGenerator(const FileDescriptor* file, const Options& options);
   ~SharedCodeGenerator();
 
-  void Generate(GeneratorContext* generator_context,
-                vector<string>* file_list);
-
-  void SetEnforceLite(bool value) {
-    enforce_lite_ = value;
-  }
+  void Generate(GeneratorContext* generator_context, vector<string>* file_list,
+                vector<string>* annotation_file_list);
 
   void GenerateDescriptors(io::Printer* printer);
 
@@ -85,8 +82,8 @@
   bool ShouldIncludeDependency(const FileDescriptor* descriptor);
 
   google::protobuf::scoped_ptr<ClassNameResolver> name_resolver_;
-  bool enforce_lite_;
   const FileDescriptor* file_;
+  const Options options_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(SharedCodeGenerator);
 };
 
diff --git a/src/google/protobuf/compiler/java/java_string_field.cc b/src/google/protobuf/compiler/java/java_string_field.cc
index b67eeb5..b74c744 100644
--- a/src/google/protobuf/compiler/java/java_string_field.cc
+++ b/src/google/protobuf/compiler/java/java_string_field.cc
@@ -712,7 +712,13 @@
 GenerateInterfaceMembers(io::Printer* printer) const {
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
-    "$deprecation$com.google.protobuf.ProtocolStringList\n"
+    // NOTE: the same method in the implementation class actually returns
+    // com.google.protobuf.ProtocolStringList (a subclass of List). It's
+    // changed between protobuf 2.5.0 release and protobuf 2.6.1 release.
+    // To retain binary compatibilty with both 2.5.0 and 2.6.1 generated
+    // code, we make this interface method return List so both methods
+    // with different return types exist in the compiled byte code.
+    "$deprecation$java.util.List<java.lang.String>\n"
     "    get$capitalized_name$List();\n");
   WriteFieldDocComment(printer, descriptor_);
   printer->Print(variables_,
diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc
index 8fb24be..f5185ab 100755
--- a/src/google/protobuf/compiler/js/js_generator.cc
+++ b/src/google/protobuf/compiler/js/js_generator.cc
@@ -28,7 +28,7 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#include <google/protobuf/compiler/js/js_generator.h>
+#include "google/protobuf/compiler/js/js_generator.h"
 
 #include <assert.h>
 #include <algorithm>
@@ -444,6 +444,11 @@
 }
 
 
+// Do we ignore this message type?
+bool IgnoreMessage(const GeneratorOptions& options, const Descriptor* d) {
+  return d->options().map_entry();
+}
+
 // Does JSPB ignore this entire oneof? True only if all fields are ignored.
 bool IgnoreOneof(const OneofDescriptor* oneof) {
   for (int i = 0; i < oneof->field_count(); i++) {
@@ -454,7 +459,8 @@
   return true;
 }
 
-string JSIdent(const FieldDescriptor* field,
+string JSIdent(const GeneratorOptions& options,
+               const FieldDescriptor* field,
                bool is_upper_camel,
                bool is_map) {
   string result;
@@ -467,16 +473,20 @@
         ToUpperCamel(ParseLowerUnderscore(field->name())) :
         ToLowerCamel(ParseLowerUnderscore(field->name()));
   }
-  if (is_map) {
+  if (is_map || (field->is_map())) {
+    // JSPB-style or proto3-style map.
     result += "Map";
   } else if (field->is_repeated()) {
+    // Repeated field.
     result += "List";
   }
   return result;
 }
 
-string JSObjectFieldName(const FieldDescriptor* field) {
+string JSObjectFieldName(const GeneratorOptions& options,
+                         const FieldDescriptor* field) {
   string name = JSIdent(
+      options,
       field,
       /* is_upper_camel = */ false,
       /* is_map = */ false);
@@ -502,9 +512,10 @@
 
 // Returns the field name as a capitalized portion of a getter/setter method
 // name, e.g. MyField for .getMyField().
-string JSGetterName(const FieldDescriptor* field,
+string JSGetterName(const GeneratorOptions& options,
+                    const FieldDescriptor* field,
                     BytesMode bytes_mode = BYTES_DEFAULT) {
-  string name = JSIdent(field,
+  string name = JSIdent(options, field,
                         /* is_upper_camel = */ true,
                         /* is_map = */ false);
   if (field->type() == FieldDescriptor::TYPE_BYTES) {
@@ -520,8 +531,9 @@
   return name;
 }
 
-string JSMapGetterName(const FieldDescriptor* field) {
-  return JSIdent(field,
+string JSMapGetterName(const GeneratorOptions& options,
+                       const FieldDescriptor* field) {
+  return JSIdent(options, field,
                  /* is_upper_camel = */ true,
                  /* is_map = */ true);
 }
@@ -967,12 +979,24 @@
   return name;
 }
 
-string JSBinaryReaderMethodName(const FieldDescriptor* field) {
-  return "read" + JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+string JSBinaryReaderMethodName(const GeneratorOptions& options,
+                                const FieldDescriptor* field) {
+  if (options.binary) {
+    return "jspb.BinaryReader.prototype.read" +
+           JSBinaryReadWriteMethodName(field, /* is_writer = */ false);
+  } else {
+    return "null";
+  }
 }
 
-string JSBinaryWriterMethodName(const FieldDescriptor* field) {
-  return "write" + JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+string JSBinaryWriterMethodName(const GeneratorOptions& options,
+                                const FieldDescriptor* field) {
+  if (options.binary) {
+    return "jspb.BinaryWriter.prototype.write" +
+           JSBinaryReadWriteMethodName(field, /* is_writer = */ true);
+  } else {
+    return "null";
+  }
 }
 
 string JSReturnClause(const FieldDescriptor* desc) {
@@ -986,7 +1010,7 @@
 
 bool HasRepeatedFields(const Descriptor* desc) {
   for (int i = 0; i < desc->field_count(); i++) {
-    if (desc->field(i)->is_repeated()) {
+    if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
       return true;
     }
   }
@@ -1021,7 +1045,7 @@
 string RepeatedFieldNumberList(const Descriptor* desc) {
   std::vector<string> numbers;
   for (int i = 0; i < desc->field_count(); i++) {
-    if (desc->field(i)->is_repeated()) {
+    if (desc->field(i)->is_repeated() && !desc->field(i)->is_map()) {
       numbers.push_back(JSFieldIndex(desc->field(i)));
     }
   }
@@ -1092,27 +1116,58 @@
   }
 }
 
+static const int kMapKeyField = 1;
+static const int kMapValueField = 2;
+
+const FieldDescriptor* MapFieldKey(const FieldDescriptor* field) {
+  assert(field->is_map());
+  return field->message_type()->FindFieldByNumber(kMapKeyField);
+}
+
+const FieldDescriptor* MapFieldValue(const FieldDescriptor* field) {
+  assert(field->is_map());
+  return field->message_type()->FindFieldByNumber(kMapValueField);
+}
+
 string FieldDefinition(const GeneratorOptions& options,
                        const FieldDescriptor* field) {
-  string qualifier = field->is_repeated() ? "repeated" :
-      (field->is_optional() ? "optional" : "required");
-  string type, name;
-  if (field->type() == FieldDescriptor::TYPE_ENUM ||
-      field->type() == FieldDescriptor::TYPE_MESSAGE) {
-    type = RelativeTypeName(field);
-    name = field->name();
-  } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
-    type = "group";
-    name = field->message_type()->name();
+  if (field->is_map()) {
+    const FieldDescriptor* key_field = MapFieldKey(field);
+    const FieldDescriptor* value_field = MapFieldValue(field);
+    string key_type = ProtoTypeName(options, key_field);
+    string value_type;
+    if (value_field->type() == FieldDescriptor::TYPE_ENUM ||
+        value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      value_type = RelativeTypeName(value_field);
+    } else {
+      value_type = ProtoTypeName(options, value_field);
+    }
+    return StringPrintf("map<%s, %s> %s = %d;",
+                        key_type.c_str(),
+                        value_type.c_str(),
+                        field->name().c_str(),
+                        field->number());
   } else {
-    type = ProtoTypeName(options, field);
-    name = field->name();
+    string qualifier = field->is_repeated() ? "repeated" :
+        (field->is_optional() ? "optional" : "required");
+    string type, name;
+    if (field->type() == FieldDescriptor::TYPE_ENUM ||
+        field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      type = RelativeTypeName(field);
+      name = field->name();
+    } else if (field->type() == FieldDescriptor::TYPE_GROUP) {
+      type = "group";
+      name = field->message_type()->name();
+    } else {
+      type = ProtoTypeName(options, field);
+      name = field->name();
+    }
+    return StringPrintf("%s %s %s = %d;",
+                        qualifier.c_str(),
+                        type.c_str(),
+                        name.c_str(),
+                        field->number());
   }
-  return StringPrintf("%s %s %s = %d;",
-                      qualifier.c_str(),
-                      type.c_str(),
-                      name.c_str(),
-                      field->number());
 }
 
 string FieldComments(const FieldDescriptor* field, BytesMode bytes_mode) {
@@ -1417,6 +1472,10 @@
     io::Printer* printer,
     const Descriptor* desc,
     std::set<string>* provided) const {
+  if (IgnoreMessage(options, desc)) {
+    return;
+  }
+
   string name = GetPath(options, desc);
   provided->insert(name);
 
@@ -1451,7 +1510,8 @@
     }
 
     string name =
-        GetPath(options, field->file()) + "." + JSObjectFieldName(field);
+        GetPath(options, field->file()) + "." +
+        JSObjectFieldName(options, field);
     provided->insert(name);
   }
 }
@@ -1494,10 +1554,13 @@
 
   for (int i = 0; i < files.size(); i++) {
     for (int j = 0; j < files[i]->message_type_count(); j++) {
-      FindRequiresForMessage(options,
-                             files[i]->message_type(j),
-                             &required, &forwards, &have_message);
+      const Descriptor* desc = files[i]->message_type(j);
+      if (!IgnoreMessage(options, desc)) {
+        FindRequiresForMessage(options, desc, &required, &forwards,
+                               &have_message);
+      }
     }
+
     if (!have_extensions && HasExtensions(files[i])) {
       have_extensions = true;
     }
@@ -1632,7 +1695,9 @@
         forwards->insert(GetPath(options, field->enum_type()));
       }
     } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
-      required->insert(GetPath(options, field->message_type()));
+      if (!IgnoreMessage(options, field->message_type())) {
+        required->insert(GetPath(options, field->message_type()));
+      }
     }
 }
 
@@ -1668,6 +1733,10 @@
 void Generator::GenerateClass(const GeneratorOptions& options,
                               io::Printer* printer,
                               const Descriptor* desc) const {
+  if (IgnoreMessage(options, desc)) {
+    return;
+  }
+
   if (!NamespaceOnly(desc)) {
     printer->Print("\n");
     GenerateClassConstructor(options, printer, desc);
@@ -1932,21 +2001,24 @@
                                            io::Printer* printer,
                                            const FieldDescriptor* field) const {
   printer->Print("$fieldname$: ",
-                 "fieldname", JSObjectFieldName(field));
+                 "fieldname", JSObjectFieldName(options, field));
 
-  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+  if (field->is_map()) {
+    printer->Print("(f = msg.get$name$(true)) ? f.toArray() : []",
+                   "name", JSGetterName(options, field));
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     // Message field.
     if (field->is_repeated()) {
       {
         printer->Print("jspb.Message.toObjectList(msg.get$getter$(),\n"
                        "    $type$.toObject, includeInstance)",
-                       "getter", JSGetterName(field),
+                       "getter", JSGetterName(options, field),
                        "type", SubmessageTypeRef(options, field));
       }
     } else {
       printer->Print("(f = msg.get$getter$()) && "
                      "$type$.toObject(includeInstance, f)",
-                     "getter", JSGetterName(field),
+                     "getter", JSGetterName(options, field),
                      "type", SubmessageTypeRef(options, field));
     }
   } else {
@@ -1956,7 +2028,7 @@
       // Delegate to the generated get<field>() method in order not to duplicate
       // the proto3-field-default-value or byte-coercion logic here.
       printer->Print("msg.get$getter$()",
-                     "getter", JSGetterName(field, BYTES_B64));
+                     "getter", JSGetterName(options, field, BYTES_B64));
     } else {
       if (field->has_default_value()) {
         printer->Print("jspb.Message.getField(msg, $index$) == null ? "
@@ -2017,7 +2089,17 @@
     const GeneratorOptions& options,
     io::Printer* printer,
     const FieldDescriptor* field) const {
-  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+
+  if (field->is_map()) {
+    // `msg` is a newly-constructed message object that has not yet built any
+    // map containers wrapping underlying arrays, so we can simply directly set
+    // the array here without fear of a stale wrapper.
+    printer->Print(
+        "  goog.isDef(obj.$name$) && "
+        "jspb.Message.setField(msg, $index$, obj.$name$);\n",
+        "name", JSObjectFieldName(options, field),
+        "index", JSFieldIndex(field));
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
     // Message field (singular or repeated)
     if (field->is_repeated()) {
       {
@@ -2027,7 +2109,7 @@
             "      msg, $index$, goog.array.map(obj.$name$, function(i) {\n"
             "        return $fieldclass$.fromObject(i);\n"
             "      }));\n",
-            "name", JSObjectFieldName(field),
+            "name", JSObjectFieldName(options, field),
             "index", JSFieldIndex(field),
             "fieldclass", SubmessageTypeRef(options, field));
       }
@@ -2035,7 +2117,7 @@
       printer->Print(
           "  goog.isDef(obj.$name$) && jspb.Message.setWrapperField(\n"
           "      msg, $index$, $fieldclass$.fromObject(obj.$name$));\n",
-          "name", JSObjectFieldName(field),
+          "name", JSObjectFieldName(options, field),
           "index", JSFieldIndex(field),
           "fieldclass", SubmessageTypeRef(options, field));
     }
@@ -2044,7 +2126,7 @@
     printer->Print(
         "  goog.isDef(obj.$name$) && jspb.Message.setField(msg, $index$, "
         "obj.$name$);\n",
-        "name", JSObjectFieldName(field),
+        "name", JSObjectFieldName(options, field),
         "index", JSFieldIndex(field));
   }
 }
@@ -2114,17 +2196,93 @@
       "comment", FieldComments(field, bytes_mode),
       "type", type,
       "class", GetPath(options, field->containing_type()),
-      "name", JSGetterName(field, bytes_mode),
+      "name", JSGetterName(options, field, bytes_mode),
       "list", field->is_repeated() ? "List" : "",
       "suffix", JSByteGetterSuffix(bytes_mode),
-      "defname", JSGetterName(field, BYTES_DEFAULT));
+      "defname", JSGetterName(options, field, BYTES_DEFAULT));
 }
 
 
 void Generator::GenerateClassField(const GeneratorOptions& options,
                                    io::Printer* printer,
                                    const FieldDescriptor* field) const {
-  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+  if (field->is_map()) {
+    const FieldDescriptor* key_field = MapFieldKey(field);
+    const FieldDescriptor* value_field = MapFieldValue(field);
+    // Map field: special handling to instantiate the map object on demand.
+    string key_type =
+        JSFieldTypeAnnotation(
+            options, key_field,
+            /* force_optional = */ false,
+            /* force_present = */ true,
+            /* singular_if_not_packed = */ false);
+    string value_type =
+        JSFieldTypeAnnotation(
+            options, value_field,
+            /* force_optional = */ false,
+            /* force_present = */ true,
+            /* singular_if_not_packed = */ false);
+
+    printer->Print(
+        "/**\n"
+        " * $fielddef$\n"
+        " * @param {boolean=} opt_noLazyCreate Do not create the map if\n"
+        " * empty, instead returning `undefined`\n"
+        " * @return {!jspb.Map<$keytype$,$valuetype$>}\n"
+        " */\n",
+        "fielddef", FieldDefinition(options, field),
+        "keytype", key_type,
+        "valuetype", value_type);
+    printer->Print(
+        "$class$.prototype.get$name$ = function(opt_noLazyCreate) {\n"
+        "  return /** @type {!jspb.Map<$keytype$,$valuetype$>} */ (\n",
+        "class", GetPath(options, field->containing_type()),
+        "name", JSGetterName(options, field),
+        "keytype", key_type,
+        "valuetype", value_type);
+    printer->Print(
+        "      jspb.Message.getMapField(this, $index$, opt_noLazyCreate",
+        "index", JSFieldIndex(field));
+
+    if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+      printer->Print(",\n"
+          "      $messageType$",
+            "messageType", GetPath(options, value_field->message_type()));
+    } else if (options.binary) {
+      printer->Print(",\n"
+          "      null");
+    }
+
+    if (options.binary) {
+      printer->Print(",\n"
+          "      $keyWriterFn$,\n"
+          "      $keyReaderFn$,\n"
+          "      $valueWriterFn$,\n"
+          "      $valueReaderFn$",
+          "keyWriterFn", JSBinaryWriterMethodName(options, key_field),
+          "keyReaderFn", JSBinaryReaderMethodName(options, key_field),
+          "valueWriterFn", JSBinaryWriterMethodName(options, value_field),
+          "valueReaderFn", JSBinaryReaderMethodName(options, value_field));
+
+      if (value_field->type() == FieldDescriptor::TYPE_MESSAGE) {
+        printer->Print(",\n"
+            "      $messageType$.serializeBinaryToWriter,\n"
+            "      $messageType$.deserializeBinaryFromReader",
+            "messageType", GetPath(options, value_field->message_type()));
+      }
+    }
+
+    printer->Print(
+        "));\n");
+
+    printer->Print(
+        "};\n"
+        "\n"
+        "\n");
+  } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+    // Message field: special handling in order to wrap the underlying data
+    // array with a message object.
+
     printer->Print(
         "/**\n"
         " * $fielddef$\n"
@@ -2146,7 +2304,7 @@
         "\n"
         "\n",
         "class", GetPath(options, field->containing_type()),
-        "name", JSGetterName(field),
+        "name", JSGetterName(options, field),
         "type", JSFieldTypeAnnotation(options, field,
                                       /* force_optional = */ false,
                                       /* force_present = */ false,
@@ -2167,7 +2325,7 @@
                               /* singular_if_not_packed = */ false),
         "returndoc", JSReturnDoc(options, field),
         "class", GetPath(options, field->containing_type()),
-        "name", JSGetterName(field),
+        "name", JSGetterName(options, field),
         "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
         "repeatedtag", (field->is_repeated() ? "Repeated" : ""));
 
@@ -2188,7 +2346,7 @@
         "\n"
         "\n",
         "class", GetPath(options, field->containing_type()),
-        "name", JSGetterName(field),
+        "name", JSGetterName(options, field),
         "clearedvalue", (field->is_repeated() ? "[]" : "undefined"),
         "returnvalue", JSReturnClause(field));
 
@@ -2230,7 +2388,7 @@
     printer->Print(
         "$class$.prototype.get$name$ = function() {\n",
         "class", GetPath(options, field->containing_type()),
-        "name", JSGetterName(field));
+        "name", JSGetterName(options, field));
 
     if (untyped) {
       printer->Print(
@@ -2315,7 +2473,7 @@
         "$class$.prototype.set$name$ = function(value) {\n"
         "  jspb.Message.set$oneoftag$Field(this, $index$",
         "class", GetPath(options, field->containing_type()),
-        "name", JSGetterName(field),
+        "name", JSGetterName(options, field),
         "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
         "index", JSFieldIndex(field));
     printer->Print(
@@ -2345,7 +2503,7 @@
           "$class$.prototype.clear$name$ = function() {\n"
           "  jspb.Message.set$oneoftag$Field(this, $index$$oneofgroup$, ",
           "class", GetPath(options, field->containing_type()),
-          "name", JSGetterName(field),
+          "name", JSGetterName(options, field),
           "oneoftag", (field->containing_oneof() ? "Oneof" : ""),
           "oneofgroup", (field->containing_oneof() ?
                          (", " + JSOneofArray(options, field)) : ""),
@@ -2461,40 +2619,49 @@
   printer->Print("    case $num$:\n",
                  "num", SimpleItoa(field->number()));
 
-  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+  if (field->is_map()) {
     printer->Print(
-        "      var value = new $fieldclass$;\n"
-        "      reader.read$msgOrGroup$($grpfield$value,"
-        "$fieldclass$.deserializeBinaryFromReader);\n",
+        "      var value = msg.get$name$();\n"
+        "      reader.readMessage(value, jspb.Map.deserializeBinary);\n",
+        "name", JSGetterName(options, field));
+  } else {
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      printer->Print(
+          "      var value = new $fieldclass$;\n"
+          "      reader.read$msgOrGroup$($grpfield$value,"
+          "$fieldclass$.deserializeBinaryFromReader);\n",
         "fieldclass", SubmessageTypeRef(options, field),
-        "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
-                      "Group" : "Message",
-        "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
-                    (SimpleItoa(field->number()) + ", ") : "");
-  } else {
-    printer->Print(
-        "      var value = /** @type {$fieldtype$} */ (reader.$reader$());\n",
-        "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
-                                           /* singular_if_not_packed = */ true,
-                                           BYTES_U8),
-        "reader", JSBinaryReaderMethodName(field));
-  }
+          "msgOrGroup", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                        "Group" : "Message",
+          "grpfield", (field->type() == FieldDescriptor::TYPE_GROUP) ?
+                      (SimpleItoa(field->number()) + ", ") : "");
+    } else {
+      printer->Print(
+          "      var value = /** @type {$fieldtype$} */ "
+          "(reader.read$reader$());\n",
+          "fieldtype", JSFieldTypeAnnotation(options, field, false, true,
+                                             /* singular_if_not_packed */ true,
+                                             BYTES_U8),
+          "reader",
+          JSBinaryReadWriteMethodName(field, /* is_writer = */ false));
+    }
 
-  if (field->is_repeated() && !field->is_packed()) {
-    // Repeated fields receive a |value| one at at a time; append to array
-    // returned by get$name$(). Annoyingly, we have to call 'set' after
-    // changing the array.
-    printer->Print("      msg.get$name$().push(value);\n", "name",
-                   JSGetterName(field));
-    printer->Print("      msg.set$name$(msg.get$name$());\n", "name",
-                   JSGetterName(field));
-  } else {
-    // Singular fields, and packed repeated fields, receive a |value| either as
-    // the field's value or as the array of all the field's values; set this as
-    // the field's value directly.
-    printer->Print(
-        "      msg.set$name$(value);\n",
-        "name", JSGetterName(field));
+    if (field->is_repeated() && !field->is_packed()) {
+      // Repeated fields receive a |value| one at at a time; append to array
+      // returned by get$name$(). Annoyingly, we have to call 'set' after
+      // changing the array.
+      printer->Print("      msg.get$name$().push(value);\n", "name",
+                     JSGetterName(options, field));
+      printer->Print("      msg.set$name$(msg.get$name$());\n", "name",
+                     JSGetterName(options, field));
+    } else {
+      // Singular fields, and packed repeated fields, receive a |value| either
+      // as the field's value or as the array of all the field's values; set
+      // this as the field's value directly.
+      printer->Print(
+          "      msg.set$name$(value);\n",
+          "name", JSGetterName(options, field));
+    }
   }
 
   printer->Print("      break;\n");
@@ -2559,10 +2726,18 @@
     io::Printer* printer,
     const FieldDescriptor* field) const {
   printer->Print(
-      "  f = this.get$name$();\n",
-      "name", JSGetterName(field, BYTES_U8));
+      "  f = this.get$name$($nolazy$);\n",
+      "name", JSGetterName(options, field, BYTES_U8),
+      // No lazy creation for maps containers -- fastpath the empty case.
+      "nolazy", (field->is_map()) ? "true" : "");
 
-  if (field->is_repeated()) {
+
+  // Print an `if (condition)` statement that evaluates to true if the field
+  // goes on the wire.
+  if (field->is_map()) {
+    printer->Print(
+        "  if (f && f.getLength() > 0) {\n");
+  } else if (field->is_repeated()) {
     printer->Print(
         "  if (f.length > 0) {\n");
   } else {
@@ -2605,23 +2780,35 @@
     }
   }
 
-  printer->Print(
-      "    writer.$writer$(\n"
-      "      $index$,\n"
-      "      f",
-      "writer", JSBinaryWriterMethodName(field),
-      "index", SimpleItoa(field->number()));
-
-  if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+  // Write the field on the wire.
+  if (field->is_map()) {
     printer->Print(
-        ",\n"
-        "      $submsg$.serializeBinaryToWriter\n",
-        "submsg", SubmessageTypeRef(options, field));
+        "    f.serializeBinary($index$, writer);\n",
+        "index", SimpleItoa(field->number()));
   } else {
-    printer->Print("\n");
+    printer->Print(
+        "    writer.write$method$(\n"
+        "      $index$,\n"
+        "      f",
+        "method", JSBinaryReadWriteMethodName(field, /* is_writer = */ true),
+        "index", SimpleItoa(field->number()));
+
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        !(field->is_map())) {
+      printer->Print(
+          ",\n"
+          "      $submsg$.serializeBinaryToWriter\n",
+        "submsg", SubmessageTypeRef(options, field));
+    } else {
+      printer->Print("\n");
+    }
+
+    printer->Print(
+        "    );\n");
   }
+
+  // Close the `if`.
   printer->Print(
-      "    );\n"
       "  }\n");
 }
 
@@ -2665,7 +2852,7 @@
       " * @type {!jspb.ExtensionFieldInfo.<$extensionType$>}\n"
       " */\n"
       "$class$.$name$ = new jspb.ExtensionFieldInfo(\n",
-      "name", JSObjectFieldName(field),
+      "name", JSObjectFieldName(options, field),
       "class", extension_scope,
       "extensionType", JSFieldTypeAnnotation(
           options, field,
@@ -2681,7 +2868,7 @@
       "         $toObject$),\n"
       "    $repeated$",
       "index", SimpleItoa(field->number()),
-      "name", JSObjectFieldName(field),
+      "name", JSObjectFieldName(options, field),
       "ctor", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
                SubmessageTypeRef(options, field) : string("null")),
       "toObject", (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ?
@@ -2692,13 +2879,13 @@
   if (options.binary) {
     printer->Print(
         ",\n"
-        "    jspb.BinaryReader.prototype.$binaryReaderFn$,\n"
-        "    jspb.BinaryWriter.prototype.$binaryWriterFn$,\n"
+        "    $binaryReaderFn$,\n"
+        "    $binaryWriterFn$,\n"
         "    $binaryMessageSerializeFn$,\n"
         "    $binaryMessageDeserializeFn$,\n"
         "    $isPacked$);\n",
-        "binaryReaderFn", JSBinaryReaderMethodName(field),
-        "binaryWriterFn", JSBinaryWriterMethodName(field),
+        "binaryReaderFn", JSBinaryReaderMethodName(options, field),
+        "binaryWriterFn", JSBinaryWriterMethodName(options, field),
         "binaryMessageSerializeFn",
         (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) ?
         (SubmessageTypeRef(options, field) +
@@ -2721,7 +2908,7 @@
                                            field->containing_type()),
       "index", SimpleItoa(field->number()),
       "class", extension_scope,
-      "name", JSObjectFieldName(field));
+      "name", JSObjectFieldName(options, field));
 }
 
 bool GeneratorOptions::ParseFromOptions(
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index 66ad13b..2f3c5b8 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -35,6 +35,8 @@
 #include <google/protobuf/compiler/python/python_generator.h>
 #include <google/protobuf/compiler/java/java_generator.h>
 #include <google/protobuf/compiler/javanano/javanano_generator.h>
+// TODO(teboring): Add it back when php implementation is ready
+// #include <google/protobuf/compiler/php/php_generator.h>
 #include <google/protobuf/compiler/ruby/ruby_generator.h>
 #include <google/protobuf/compiler/csharp/csharp_generator.h>
 #include <google/protobuf/compiler/objectivec/objectivec_generator.h>
@@ -66,6 +68,12 @@
   cli.RegisterGenerator("--javanano_out", &javanano_generator,
                         "Generate Java Nano source file.");
 
+  // TODO(teboring): Add it back when php implementation is ready
+  // PHP
+  // google::protobuf::compiler::php::Generator php_generator;
+  // cli.RegisterGenerator("--php_out", &php_generator,
+  //                      "Generate PHP source file.");
+
   // Ruby
   google::protobuf::compiler::ruby::Generator rb_generator;
   cli.RegisterGenerator("--ruby_out", &rb_generator,
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 90ded4d..214d7c9 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -1630,6 +1630,16 @@
       return false;
     }
 
+    if (LookingAt("option")) {
+      LocationRecorder option_location(
+          oneof_location, OneofDescriptorProto::kOptionsFieldNumber);
+      if (!ParseOption(oneof_decl->mutable_options(), option_location,
+                       containing_file, OPTION_STATEMENT)) {
+        return false;
+      }
+      continue;
+    }
+
     // Print a nice error if the user accidentally tries to place a label
     // on an individual member of a oneof.
     if (LookingAt("required") ||
diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc
index e9d50a1..c4d48fc 100644
--- a/src/google/protobuf/compiler/plugin.pb.cc
+++ b/src/google/protobuf/compiler/plugin.pb.cc
@@ -373,8 +373,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorRequest)
 }
 
-::google::protobuf::uint8* CodeGeneratorRequest::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorRequest::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorRequest)
   // repeated string file_to_generate = 1;
   for (int i = 0; i < this->file_to_generate_size(); i++) {
@@ -400,8 +400,8 @@
   // repeated .google.protobuf.FileDescriptorProto proto_file = 15;
   for (unsigned int i = 0, n = this->proto_file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        15, this->proto_file(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        15, this->proto_file(i), false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -878,8 +878,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse.File)
 }
 
-::google::protobuf::uint8* CodeGeneratorResponse_File::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorResponse_File::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse.File)
   // optional string name = 1;
   if (has_name()) {
@@ -1208,8 +1208,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.compiler.CodeGeneratorResponse)
 }
 
-::google::protobuf::uint8* CodeGeneratorResponse::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* CodeGeneratorResponse::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.compiler.CodeGeneratorResponse)
   // optional string error = 1;
   if (has_error()) {
@@ -1225,8 +1225,8 @@
   // repeated .google.protobuf.compiler.CodeGeneratorResponse.File file = 15;
   for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        15, this->file(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        15, this->file(i), false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h
index 510202f..13eeb69 100644
--- a/src/google/protobuf/compiler/plugin.pb.h
+++ b/src/google/protobuf/compiler/plugin.pb.h
@@ -45,7 +45,7 @@
 
 // ===================================================================
 
-class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorRequest : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorRequest) */ {
  public:
   CodeGeneratorRequest();
   virtual ~CodeGeneratorRequest();
@@ -87,7 +87,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -169,7 +173,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorResponse_File : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse.File) */ {
  public:
   CodeGeneratorResponse_File();
   virtual ~CodeGeneratorResponse_File();
@@ -211,7 +215,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -293,7 +301,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message {
+class LIBPROTOC_EXPORT CodeGeneratorResponse : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.compiler.CodeGeneratorResponse) */ {
  public:
   CodeGeneratorResponse();
   virtual ~CodeGeneratorResponse();
@@ -335,7 +343,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 0553dd0..cc54a8a 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -707,11 +707,18 @@
     m["name"] = desc->name();
     m["full_name"] = desc->full_name();
     m["index"] = SimpleItoa(desc->index());
+    string options_string =
+        OptionsValue("OneofOptions", desc->options().SerializeAsString());
+    if (options_string == "None") {
+      m["options"] = "";
+    } else {
+      m["options"] = ", options=" + options_string;
+    }
     printer_->Print(
         m,
         "_descriptor.OneofDescriptor(\n"
         "  name='$name$', full_name='$full_name$',\n"
-        "  index=$index$, containing_type=None, fields=[]),\n");
+        "  index=$index$, containing_type=None, fields=[]$options$),\n");
   }
   printer_->Outdent();
   printer_->Print("],\n");
@@ -1235,6 +1242,18 @@
   }
 }
 
+void Generator::FixOptionsForOneof(const OneofDescriptor& oneof) const {
+  string oneof_options = OptionsValue(
+      "OneofOptions", oneof.options().SerializeAsString());
+  if (oneof_options != "None") {
+    string oneof_name = strings::Substitute(
+        "$0.$1['$2']",
+        ModuleLevelDescriptorName(*oneof.containing_type()),
+        "oneofs_by_name", oneof.name());
+    PrintDescriptorOptionsFixingCode(oneof_name, oneof_options, printer_);
+  }
+}
+
 // Prints expressions that set the options for an enum descriptor and its
 // value descriptors.
 void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const {
@@ -1288,6 +1307,10 @@
   for (int i = 0; i < descriptor.nested_type_count(); ++i) {
     FixOptionsForMessage(*descriptor.nested_type(i));
   }
+  // Oneofs.
+  for (int i = 0; i < descriptor.oneof_decl_count(); ++i) {
+    FixOptionsForOneof(*descriptor.oneof_decl(i));
+  }
   // Enums.
   for (int i = 0; i < descriptor.enum_type_count(); ++i) {
     FixOptionsForEnum(*descriptor.enum_type(i));
diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h
index aa0f5fc..7583aa6 100644
--- a/src/google/protobuf/compiler/python/python_generator.h
+++ b/src/google/protobuf/compiler/python/python_generator.h
@@ -48,6 +48,7 @@
 class EnumDescriptor;
 class EnumValueDescriptor;
 class FieldDescriptor;
+class OneofDescriptor;
 class ServiceDescriptor;
 
 namespace io { class Printer; }
@@ -148,6 +149,7 @@
 
   void FixAllDescriptorOptions() const;
   void FixOptionsForField(const FieldDescriptor& field) const;
+  void FixOptionsForOneof(const OneofDescriptor& oneof) const;
   void FixOptionsForEnum(const EnumDescriptor& descriptor) const;
   void FixOptionsForMessage(const Descriptor& descriptor) const;
 
diff --git a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
index 1b04cb3..c0acb40 100644
--- a/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
+++ b/src/google/protobuf/compiler/ruby/ruby_generator_unittest.cc
@@ -45,22 +45,8 @@
 namespace ruby {
 namespace {
 
-string FindRubyTestDir(const string& file) {
-  // Inspired by TestSourceDir() in src/google/protobuf/testing/googletest.cc.
-#ifndef GOOGLE_THIRD_PARTY_PROTOBUF
-  string prefix = ".";
-  while (!File::Exists(prefix + "/src/google/protobuf/compiler/ruby" + file)) {
-    if (!File::Exists(prefix)) {
-      GOOGLE_LOG(FATAL)
-          << "Could not find Ruby test directory. Please run tests from "
-             "somewhere within the protobuf source package.";
-    }
-    prefix += "/..";
-  }
-  return prefix + "/src/google/protobuf/compiler/ruby";
-#else
-  return "third_party/protobuf/src/google/protobuf/compiler/ruby";
-#endif  // GOOGLE_THIRD_PARTY_PROTOBUF
+string FindRubyTestDir() {
+  return TestSourceDir() + "/google/protobuf/compiler/ruby";
 }
 
 // This test is a simple golden-file test over the output of the Ruby code
@@ -71,7 +57,7 @@
 // extensions to the point where we can do this test in a more automated way.
 
 TEST(RubyGeneratorTest, GeneratorTest) {
-  string ruby_tests = FindRubyTestDir("/ruby_generated_code.proto");
+  string ruby_tests = FindRubyTestDir();
 
   google::protobuf::compiler::CommandLineInterface cli;
   cli.SetInputsAreProtoPathRelative(true);
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 56e11fa..9b20946 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -1896,6 +1896,9 @@
 
 void OneofDescriptor::CopyTo(OneofDescriptorProto* proto) const {
   proto->set_name(name());
+  if (&options() != &OneofOptions::default_instance()) {
+    proto->mutable_options()->CopyFrom(options());
+  }
 }
 
 void EnumDescriptor::CopyTo(EnumDescriptorProto* proto) const {
@@ -2435,6 +2438,9 @@
   comment_printer.AddPreComment(contents);
   strings::SubstituteAndAppend(
       contents, "$0 oneof $1 {", prefix, name());
+
+  FormatLineOptions(depth, options(), contents);
+
   if (debug_string_options.elide_oneof_body) {
     contents->append(" ... }\n");
   } else {
@@ -4523,6 +4529,13 @@
   result->field_count_ = 0;
   result->fields_ = NULL;
 
+  // Copy options.
+  if (!proto.has_options()) {
+    result->options_ = NULL;  // Will set to default_instance later.
+  } else {
+    AllocateOptions(proto.options(), result);
+  }
+
   AddSymbol(result->full_name(), parent, result->name(),
             proto, Symbol(result));
 }
@@ -4783,6 +4796,10 @@
     oneof_decl->fields_ =
       tables_->AllocateArray<const FieldDescriptor*>(oneof_decl->field_count_);
     oneof_decl->field_count_ = 0;
+
+    if (oneof_decl->options_ == NULL) {
+      oneof_decl->options_ = &OneofOptions::default_instance();
+    }
   }
 
   // Then fill them in.
@@ -5181,7 +5198,7 @@
     if (name_to_field.find(lowercase_name) != name_to_field.end()) {
       AddError(message->full_name(), proto,
                DescriptorPool::ErrorCollector::OTHER,
-               "The JSON camcel-case name of field \"" +
+               "The JSON camel-case name of field \"" +
                message->field(i)->name() + "\" conflicts with field \"" +
                name_to_field[lowercase_name]->name() + "\". This is not " +
                "allowed in proto3.");
@@ -5237,6 +5254,7 @@
   }
 }
 
+
 void DescriptorBuilder::ValidateMessageOptions(Descriptor* message,
                                                const DescriptorProto& proto) {
   VALIDATE_OPTIONS_FROM_ARRAY(message, field, Field);
@@ -5257,6 +5275,7 @@
                               max_extension_range));
     }
   }
+
 }
 
 void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 3ecc0a9..b040b62 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -62,7 +62,6 @@
 #include <string>
 #include <vector>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 
 // TYPE_BOOL is defined in the MacOS's ConditionalMacros.h.
 #ifdef TYPE_BOOL
@@ -95,6 +94,7 @@
 class FileDescriptorProto;
 class MessageOptions;
 class FieldOptions;
+class OneofOptions;
 class EnumOptions;
 class EnumValueOptions;
 class ServiceOptions;
@@ -750,6 +750,8 @@
   // .proto file.  Does not include extensions.
   const FieldDescriptor* field(int index) const;
 
+  const OneofOptions& options() const;
+
   // See Descriptor::CopyTo().
   void CopyTo(OneofDescriptorProto* proto) const;
 
@@ -767,6 +769,8 @@
   bool GetSourceLocation(SourceLocation* out_location) const;
 
  private:
+  typedef OneofOptions OptionsType;
+
   // Allows access to GetLocationPath for annotations.
   friend class ::google::protobuf::io::Printer;
 
@@ -784,6 +788,8 @@
   bool is_extendable_;
   int field_count_;
   const FieldDescriptor** fields_;
+  const OneofOptions* options_;
+
   // IMPORTANT:  If you add a new field, make sure to search for all instances
   // of Allocate<OneofDescriptor>() and AllocateArray<OneofDescriptor>()
   // in descriptor.cc and update them to initialize the field.
@@ -1708,6 +1714,7 @@
 PROTOBUF_DEFINE_STRING_ACCESSOR(OneofDescriptor, full_name)
 PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, containing_type, const Descriptor*)
 PROTOBUF_DEFINE_ACCESSOR(OneofDescriptor, field_count, int)
+PROTOBUF_DEFINE_OPTIONS_ACCESSOR(OneofDescriptor, OneofOptions)
 
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, name)
 PROTOBUF_DEFINE_STRING_ACCESSOR(EnumDescriptor, full_name)
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index 4d5c4d9..4e2c9dc 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -69,6 +69,9 @@
   FieldOptions_reflection_ = NULL;
 const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor_ = NULL;
 const ::google::protobuf::EnumDescriptor* FieldOptions_JSType_descriptor_ = NULL;
+const ::google::protobuf::Descriptor* OneofOptions_descriptor_ = NULL;
+const ::google::protobuf::internal::GeneratedMessageReflection*
+  OneofOptions_reflection_ = NULL;
 const ::google::protobuf::Descriptor* EnumOptions_descriptor_ = NULL;
 const ::google::protobuf::internal::GeneratedMessageReflection*
   EnumOptions_reflection_ = NULL;
@@ -233,8 +236,9 @@
   FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0);
   FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1);
   OneofDescriptorProto_descriptor_ = file->message_type(4);
-  static const int OneofDescriptorProto_offsets_[1] = {
+  static const int OneofDescriptorProto_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, name_),
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, options_),
   };
   OneofDescriptorProto_reflection_ =
     ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
@@ -390,7 +394,22 @@
       -1);
   FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0);
   FieldOptions_JSType_descriptor_ = FieldOptions_descriptor_->enum_type(1);
-  EnumOptions_descriptor_ = file->message_type(12);
+  OneofOptions_descriptor_ = file->message_type(12);
+  static const int OneofOptions_offsets_[1] = {
+    GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, uninterpreted_option_),
+  };
+  OneofOptions_reflection_ =
+    ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection(
+      OneofOptions_descriptor_,
+      OneofOptions::default_instance_,
+      OneofOptions_offsets_,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _has_bits_[0]),
+      -1,
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _extensions_),
+      sizeof(OneofOptions),
+      GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofOptions, _internal_metadata_),
+      -1);
+  EnumOptions_descriptor_ = file->message_type(13);
   static const int EnumOptions_offsets_[3] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, allow_alias_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, deprecated_),
@@ -407,7 +426,7 @@
       sizeof(EnumOptions),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_),
       -1);
-  EnumValueOptions_descriptor_ = file->message_type(13);
+  EnumValueOptions_descriptor_ = file->message_type(14);
   static const int EnumValueOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, uninterpreted_option_),
@@ -423,7 +442,7 @@
       sizeof(EnumValueOptions),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_),
       -1);
-  ServiceOptions_descriptor_ = file->message_type(14);
+  ServiceOptions_descriptor_ = file->message_type(15);
   static const int ServiceOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, uninterpreted_option_),
@@ -439,7 +458,7 @@
       sizeof(ServiceOptions),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_),
       -1);
-  MethodOptions_descriptor_ = file->message_type(15);
+  MethodOptions_descriptor_ = file->message_type(16);
   static const int MethodOptions_offsets_[2] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, uninterpreted_option_),
@@ -455,7 +474,7 @@
       sizeof(MethodOptions),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_),
       -1);
-  UninterpretedOption_descriptor_ = file->message_type(16);
+  UninterpretedOption_descriptor_ = file->message_type(17);
   static const int UninterpretedOption_offsets_[7] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_),
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, identifier_value_),
@@ -492,7 +511,7 @@
       sizeof(UninterpretedOption_NamePart),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_),
       -1);
-  SourceCodeInfo_descriptor_ = file->message_type(17);
+  SourceCodeInfo_descriptor_ = file->message_type(18);
   static const int SourceCodeInfo_offsets_[1] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_),
   };
@@ -526,7 +545,7 @@
       sizeof(SourceCodeInfo_Location),
       GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_),
       -1);
-  GeneratedCodeInfo_descriptor_ = file->message_type(18);
+  GeneratedCodeInfo_descriptor_ = file->message_type(19);
   static const int GeneratedCodeInfo_offsets_[1] = {
     GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(GeneratedCodeInfo, annotation_),
   };
@@ -600,6 +619,8 @@
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       FieldOptions_descriptor_, &FieldOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
+      OneofOptions_descriptor_, &OneofOptions::default_instance());
+  ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       EnumOptions_descriptor_, &EnumOptions::default_instance());
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(
       EnumValueOptions_descriptor_, &EnumValueOptions::default_instance());
@@ -652,6 +673,8 @@
   delete MessageOptions_reflection_;
   delete FieldOptions::default_instance_;
   delete FieldOptions_reflection_;
+  delete OneofOptions::default_instance_;
+  delete OneofOptions_reflection_;
   delete EnumOptions::default_instance_;
   delete EnumOptions_reflection_;
   delete EnumValueOptions::default_instance_;
@@ -729,87 +752,91 @@
     "SFIXED32\020\017\022\021\n\rTYPE_SFIXED64\020\020\022\017\n\013TYPE_SI"
     "NT32\020\021\022\017\n\013TYPE_SINT64\020\022\"C\n\005Label\022\022\n\016LABE"
     "L_OPTIONAL\020\001\022\022\n\016LABEL_REQUIRED\020\002\022\022\n\016LABE"
-    "L_REPEATED\020\003\"$\n\024OneofDescriptorProto\022\014\n\004"
-    "name\030\001 \001(\t\"\214\001\n\023EnumDescriptorProto\022\014\n\004na"
-    "me\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google.protobu"
-    "f.EnumValueDescriptorProto\022-\n\007options\030\003 "
-    "\001(\0132\034.google.protobuf.EnumOptions\"l\n\030Enu"
-    "mValueDescriptorProto\022\014\n\004name\030\001 \001(\t\022\016\n\006n"
-    "umber\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.google.pr"
-    "otobuf.EnumValueOptions\"\220\001\n\026ServiceDescr"
-    "iptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(\013"
-    "2&.google.protobuf.MethodDescriptorProto"
-    "\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Serv"
-    "iceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n\004"
-    "name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output"
-    "_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.pr"
-    "otobuf.MethodOptions\022\037\n\020client_streaming"
-    "\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010:"
-    "\005false\"\207\005\n\013FileOptions\022\024\n\014java_package\030\001"
-    " \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023ja"
-    "va_multiple_files\030\n \001(\010:\005false\022,\n\035java_g"
-    "enerate_equals_and_hash\030\024 \001(\010:\005false\022%\n\026"
-    "java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014o"
-    "ptimize_for\030\t \001(\0162).google.protobuf.File"
-    "Options.OptimizeMode:\005SPEED\022\022\n\ngo_packag"
-    "e\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005fa"
-    "lse\022$\n\025java_generic_services\030\021 \001(\010:\005fals"
-    "e\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031\n"
-    "\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_ar"
-    "enas\030\037 \001(\010:\005false\022\031\n\021objc_class_prefix\030$"
-    " \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C\n\024uninte"
-    "rpreted_option\030\347\007 \003(\0132$.google.protobuf."
-    "UninterpretedOption\":\n\014OptimizeMode\022\t\n\005S"
-    "PEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*"
-    "\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOptions\022&\n\027m"
-    "essage_set_wire_format\030\001 \001(\010:\005false\022.\n\037n"
-    "o_standard_descriptor_accessor\030\002 \001(\010:\005fa"
-    "lse\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_en"
-    "try\030\007 \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\013"
-    "2$.google.protobuf.UninterpretedOption*\t"
-    "\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ctype\030\001 \001("
-    "\0162#.google.protobuf.FieldOptions.CType:\006"
-    "STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype\030\006 \001(\0162$"
-    ".google.protobuf.FieldOptions.JSType:\tJS"
-    "_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecat"
-    "ed\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024"
-    "uninterpreted_option\030\347\007 \003(\0132$.google.pro"
-    "tobuf.UninterpretedOption\"/\n\005CType\022\n\n\006ST"
-    "RING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002\"5\n\006JS"
-    "Type\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING\020\001\022\r\n\tJS"
-    "_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013"
-    "allow_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005f"
+    "L_REPEATED\020\003\"T\n\024OneofDescriptorProto\022\014\n\004"
+    "name\030\001 \001(\t\022.\n\007options\030\002 \001(\0132\035.google.pro"
+    "tobuf.OneofOptions\"\214\001\n\023EnumDescriptorPro"
+    "to\022\014\n\004name\030\001 \001(\t\0228\n\005value\030\002 \003(\0132).google"
+    ".protobuf.EnumValueDescriptorProto\022-\n\007op"
+    "tions\030\003 \001(\0132\034.google.protobuf.EnumOption"
+    "s\"l\n\030EnumValueDescriptorProto\022\014\n\004name\030\001 "
+    "\001(\t\022\016\n\006number\030\002 \001(\005\0222\n\007options\030\003 \001(\0132!.g"
+    "oogle.protobuf.EnumValueOptions\"\220\001\n\026Serv"
+    "iceDescriptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006meth"
+    "od\030\002 \003(\0132&.google.protobuf.MethodDescrip"
+    "torProto\0220\n\007options\030\003 \001(\0132\037.google.proto"
+    "buf.ServiceOptions\"\301\001\n\025MethodDescriptorP"
+    "roto\022\014\n\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023"
+    "\n\013output_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.g"
+    "oogle.protobuf.MethodOptions\022\037\n\020client_s"
+    "treaming\030\005 \001(\010:\005false\022\037\n\020server_streamin"
+    "g\030\006 \001(\010:\005false\"\207\005\n\013FileOptions\022\024\n\014java_p"
+    "ackage\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001"
+    "(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022,"
+    "\n\035java_generate_equals_and_hash\030\024 \001(\010:\005f"
+    "alse\022%\n\026java_string_check_utf8\030\033 \001(\010:\005fa"
+    "lse\022F\n\014optimize_for\030\t \001(\0162).google.proto"
+    "buf.FileOptions.OptimizeMode:\005SPEED\022\022\n\ng"
+    "o_package\030\013 \001(\t\022\"\n\023cc_generic_services\030\020"
+    " \001(\010:\005false\022$\n\025java_generic_services\030\021 \001"
+    "(\010:\005false\022\"\n\023py_generic_services\030\022 \001(\010:\005"
+    "false\022\031\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_e"
+    "nable_arenas\030\037 \001(\010:\005false\022\031\n\021objc_class_"
+    "prefix\030$ \001(\t\022\030\n\020csharp_namespace\030% \001(\t\022C"
+    "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p"
+    "rotobuf.UninterpretedOption\":\n\014OptimizeM"
+    "ode\022\t\n\005SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RU"
+    "NTIME\020\003*\t\010\350\007\020\200\200\200\200\002J\004\010&\020\'\"\346\001\n\016MessageOpti"
+    "ons\022&\n\027message_set_wire_format\030\001 \001(\010:\005fa"
+    "lse\022.\n\037no_standard_descriptor_accessor\030\002"
+    " \001(\010:\005false\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\021"
+    "\n\tmap_entry\030\007 \001(\010\022C\n\024uninterpreted_optio"
+    "n\030\347\007 \003(\0132$.google.protobuf.Uninterpreted"
+    "Option*\t\010\350\007\020\200\200\200\200\002\"\230\003\n\014FieldOptions\022:\n\005ct"
+    "ype\030\001 \001(\0162#.google.protobuf.FieldOptions"
+    ".CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\?\n\006jstype"
+    "\030\006 \001(\0162$.google.protobuf.FieldOptions.JS"
+    "Type:\tJS_NORMAL\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\n"
+    "deprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005f"
+    "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+    "ogle.protobuf.UninterpretedOption\"/\n\005CTy"
+    "pe\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE"
+    "\020\002\"5\n\006JSType\022\r\n\tJS_NORMAL\020\000\022\r\n\tJS_STRING"
+    "\020\001\022\r\n\tJS_NUMBER\020\002*\t\010\350\007\020\200\200\200\200\002\"^\n\014OneofOpt"
+    "ions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
+    "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
+    "\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow_alias\030\002 \001("
+    "\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uninterp"
+    "reted_option\030\347\007 \003(\0132$.google.protobuf.Un"
+    "interpretedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValu"
+    "eOptions\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024u"
+    "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
+    "obuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016S"
+    "erviceOptions\022\031\n\ndeprecated\030! \001(\010:\005false"
+    "\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.google"
+    ".protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002"
+    "\"z\n\rMethodOptions\022\031\n\ndeprecated\030! \001(\010:\005f"
     "alse\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go"
     "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200"
-    "\200\200\200\002\"}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001"
-    " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003"
-    "(\0132$.google.protobuf.UninterpretedOption"
-    "*\t\010\350\007\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndepreca"
-    "ted\030! \001(\010:\005false\022C\n\024uninterpreted_option"
-    "\030\347\007 \003(\0132$.google.protobuf.UninterpretedO"
-    "ption*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndep"
-    "recated\030! \001(\010:\005false\022C\n\024uninterpreted_op"
-    "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre"
-    "tedOption*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOp"
-    "tion\022;\n\004name\030\002 \003(\0132-.google.protobuf.Uni"
-    "nterpretedOption.NamePart\022\030\n\020identifier_"
-    "value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022"
-    "\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_va"
-    "lue\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggre"
-    "gate_value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_par"
-    "t\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010\"\325\001\n\016Source"
-    "CodeInfo\022:\n\010location\030\001 \003(\0132(.google.prot"
-    "obuf.SourceCodeInfo.Location\032\206\001\n\010Locatio"
-    "n\022\020\n\004path\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n"
-    "\020leading_comments\030\003 \001(\t\022\031\n\021trailing_comm"
-    "ents\030\004 \001(\t\022!\n\031leading_detached_comments\030"
-    "\006 \003(\t\"\247\001\n\021GeneratedCodeInfo\022A\n\nannotatio"
-    "n\030\001 \003(\0132-.google.protobuf.GeneratedCodeI"
-    "nfo.Annotation\032O\n\nAnnotation\022\020\n\004path\030\001 \003"
-    "(\005B\002\020\001\022\023\n\013source_file\030\002 \001(\t\022\r\n\005begin\030\003 \001"
-    "(\005\022\013\n\003end\030\004 \001(\005BX\n\023com.google.protobufB\020"
-    "DescriptorProtosH\001Z\ndescriptor\242\002\003GPB\252\002\032G"
-    "oogle.Protobuf.Reflection", 5145);
+    "\200\200\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003"
+    "(\0132-.google.protobuf.UninterpretedOption"
+    ".NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022p"
+    "ositive_int_value\030\004 \001(\004\022\032\n\022negative_int_"
+    "value\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014str"
+    "ing_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t"
+    "\0323\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_ex"
+    "tension\030\002 \002(\010\"\325\001\n\016SourceCodeInfo\022:\n\010loca"
+    "tion\030\001 \003(\0132(.google.protobuf.SourceCodeI"
+    "nfo.Location\032\206\001\n\010Location\022\020\n\004path\030\001 \003(\005B"
+    "\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020leading_comment"
+    "s\030\003 \001(\t\022\031\n\021trailing_comments\030\004 \001(\t\022!\n\031le"
+    "ading_detached_comments\030\006 \003(\t\"\247\001\n\021Genera"
+    "tedCodeInfo\022A\n\nannotation\030\001 \003(\0132-.google"
+    ".protobuf.GeneratedCodeInfo.Annotation\032O"
+    "\n\nAnnotation\022\020\n\004path\030\001 \003(\005B\002\020\001\022\023\n\013source"
+    "_file\030\002 \001(\t\022\r\n\005begin\030\003 \001(\005\022\013\n\003end\030\004 \001(\005B"
+    "X\n\023com.google.protobufB\020DescriptorProtos"
+    "H\001Z\ndescriptor\242\002\003GPB\252\002\032Google.Protobuf.R"
+    "eflection", 5289);
   ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile(
     "google/protobuf/descriptor.proto", &protobuf_RegisterTypes);
   FileDescriptorSet::default_instance_ = new FileDescriptorSet();
@@ -826,6 +853,7 @@
   FileOptions::default_instance_ = new FileOptions();
   MessageOptions::default_instance_ = new MessageOptions();
   FieldOptions::default_instance_ = new FieldOptions();
+  OneofOptions::default_instance_ = new OneofOptions();
   EnumOptions::default_instance_ = new EnumOptions();
   EnumValueOptions::default_instance_ = new EnumValueOptions();
   ServiceOptions::default_instance_ = new ServiceOptions();
@@ -850,6 +878,7 @@
   FileOptions::default_instance_->InitAsDefaultInstance();
   MessageOptions::default_instance_->InitAsDefaultInstance();
   FieldOptions::default_instance_->InitAsDefaultInstance();
+  OneofOptions::default_instance_->InitAsDefaultInstance();
   EnumOptions::default_instance_->InitAsDefaultInstance();
   EnumValueOptions::default_instance_->InitAsDefaultInstance();
   ServiceOptions::default_instance_->InitAsDefaultInstance();
@@ -1016,14 +1045,14 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorSet)
 }
 
-::google::protobuf::uint8* FileDescriptorSet::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileDescriptorSet::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorSet)
   // repeated .google.protobuf.FileDescriptorProto file = 1;
   for (unsigned int i = 0, n = this->file_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        1, this->file(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        1, this->file(i), false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -1604,8 +1633,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FileDescriptorProto)
 }
 
-::google::protobuf::uint8* FileDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -1642,43 +1671,43 @@
   // repeated .google.protobuf.DescriptorProto message_type = 4;
   for (unsigned int i = 0, n = this->message_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        4, this->message_type(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        4, this->message_type(i), false, target);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
   for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        5, this->enum_type(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        5, this->enum_type(i), false, target);
   }
 
   // repeated .google.protobuf.ServiceDescriptorProto service = 6;
   for (unsigned int i = 0, n = this->service_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        6, this->service(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        6, this->service(i), false, target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 7;
   for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        7, this->extension(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        7, this->extension(i), false, target);
   }
 
   // optional .google.protobuf.FileOptions options = 8;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        8, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        8, *this->options_, false, target);
   }
 
   // optional .google.protobuf.SourceCodeInfo source_code_info = 9;
   if (has_source_code_info()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        9, *this->source_code_info_, target);
+      InternalWriteMessageNoVirtualToArray(
+        9, *this->source_code_info_, false, target);
   }
 
   // repeated int32 public_dependency = 10;
@@ -2599,8 +2628,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ExtensionRange)
 }
 
-::google::protobuf::uint8* DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto_ExtensionRange::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ExtensionRange)
   // optional int32 start = 1;
   if (has_start()) {
@@ -2898,8 +2927,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto.ReservedRange)
 }
 
-::google::protobuf::uint8* DescriptorProto_ReservedRange::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto_ReservedRange::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto.ReservedRange)
   // optional int32 start = 1;
   if (has_start()) {
@@ -3395,8 +3424,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.DescriptorProto)
 }
 
-::google::protobuf::uint8* DescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -3412,57 +3441,57 @@
   // repeated .google.protobuf.FieldDescriptorProto field = 2;
   for (unsigned int i = 0, n = this->field_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->field(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->field(i), false, target);
   }
 
   // repeated .google.protobuf.DescriptorProto nested_type = 3;
   for (unsigned int i = 0, n = this->nested_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, this->nested_type(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        3, this->nested_type(i), false, target);
   }
 
   // repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
   for (unsigned int i = 0, n = this->enum_type_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        4, this->enum_type(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        4, this->enum_type(i), false, target);
   }
 
   // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
   for (unsigned int i = 0, n = this->extension_range_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        5, this->extension_range(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        5, this->extension_range(i), false, target);
   }
 
   // repeated .google.protobuf.FieldDescriptorProto extension = 6;
   for (unsigned int i = 0, n = this->extension_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        6, this->extension(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        6, this->extension(i), false, target);
   }
 
   // optional .google.protobuf.MessageOptions options = 7;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        7, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        7, *this->options_, false, target);
   }
 
   // repeated .google.protobuf.OneofDescriptorProto oneof_decl = 8;
   for (unsigned int i = 0, n = this->oneof_decl_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        8, this->oneof_decl(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        8, this->oneof_decl(i), false, target);
   }
 
   // repeated .google.protobuf.DescriptorProto.ReservedRange reserved_range = 9;
   for (unsigned int i = 0, n = this->reserved_range_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        9, this->reserved_range(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        9, this->reserved_range(i), false, target);
   }
 
   // repeated string reserved_name = 10;
@@ -3637,6 +3666,7 @@
   if (!::google::protobuf::internal::AllAreInitialized(this->extension())) return false;
   if (!::google::protobuf::internal::AllAreInitialized(this->nested_type())) return false;
   if (!::google::protobuf::internal::AllAreInitialized(this->enum_type())) return false;
+  if (!::google::protobuf::internal::AllAreInitialized(this->oneof_decl())) return false;
   if (has_options()) {
     if (!this->options_->IsInitialized()) return false;
   }
@@ -4630,8 +4660,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FieldDescriptorProto)
 }
 
-::google::protobuf::uint8* FieldDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -4697,8 +4727,8 @@
   // optional .google.protobuf.FieldOptions options = 8;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        8, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        8, *this->options_, false, target);
   }
 
   // optional int32 oneof_index = 9;
@@ -5345,6 +5375,7 @@
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int OneofDescriptorProto::kNameFieldNumber;
+const int OneofDescriptorProto::kOptionsFieldNumber;
 #endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
 
 OneofDescriptorProto::OneofDescriptorProto()
@@ -5354,6 +5385,7 @@
 }
 
 void OneofDescriptorProto::InitAsDefaultInstance() {
+  options_ = const_cast< ::google::protobuf::OneofOptions*>(&::google::protobuf::OneofOptions::default_instance());
 }
 
 OneofDescriptorProto::OneofDescriptorProto(const OneofDescriptorProto& from)
@@ -5368,6 +5400,7 @@
   ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
   name_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  options_ = NULL;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -5379,6 +5412,7 @@
 void OneofDescriptorProto::SharedDtor() {
   name_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
   if (this != default_instance_) {
+    delete options_;
   }
 }
 
@@ -5409,8 +5443,13 @@
 
 void OneofDescriptorProto::Clear() {
 // @@protoc_insertion_point(message_clear_start:google.protobuf.OneofDescriptorProto)
-  if (has_name()) {
-    name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+  if (_has_bits_[0 / 32] & 3u) {
+    if (has_name()) {
+      name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());
+    }
+    if (has_options()) {
+      if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+    }
   }
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
   if (_internal_metadata_.have_unknown_fields()) {
@@ -5440,6 +5479,19 @@
         } else {
           goto handle_unusual;
         }
+        if (input->ExpectTag(18)) goto parse_options;
+        break;
+      }
+
+      // optional .google.protobuf.OneofOptions options = 2;
+      case 2: {
+        if (tag == 18) {
+         parse_options:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
+               input, mutable_options()));
+        } else {
+          goto handle_unusual;
+        }
         if (input->ExpectAtEnd()) goto success;
         break;
       }
@@ -5479,6 +5531,12 @@
       1, this->name(), output);
   }
 
+  // optional .google.protobuf.OneofOptions options = 2;
+  if (has_options()) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      2, *this->options_, output);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
         unknown_fields(), output);
@@ -5486,8 +5544,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.OneofDescriptorProto)
 }
 
-::google::protobuf::uint8* OneofDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* OneofDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -5500,6 +5558,13 @@
         1, this->name(), target);
   }
 
+  // optional .google.protobuf.OneofOptions options = 2;
+  if (has_options()) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        2, *this->options_, false, target);
+  }
+
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
         unknown_fields(), target);
@@ -5512,13 +5577,22 @@
 // @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofDescriptorProto)
   int total_size = 0;
 
-  // optional string name = 1;
-  if (has_name()) {
-    total_size += 1 +
-      ::google::protobuf::internal::WireFormatLite::StringSize(
-        this->name());
-  }
+  if (_has_bits_[0 / 32] & 3u) {
+    // optional string name = 1;
+    if (has_name()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::StringSize(
+          this->name());
+    }
 
+    // optional .google.protobuf.OneofOptions options = 2;
+    if (has_options()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+          *this->options_);
+    }
+
+  }
   if (_internal_metadata_.have_unknown_fields()) {
     total_size +=
       ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
@@ -5553,6 +5627,9 @@
       set_has_name();
       name_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.name_);
     }
+    if (from.has_options()) {
+      mutable_options()->::google::protobuf::OneofOptions::MergeFrom(from.options());
+    }
   }
   if (from._internal_metadata_.have_unknown_fields()) {
     mutable_unknown_fields()->MergeFrom(from.unknown_fields());
@@ -5575,6 +5652,9 @@
 
 bool OneofDescriptorProto::IsInitialized() const {
 
+  if (has_options()) {
+    if (!this->options_->IsInitialized()) return false;
+  }
   return true;
 }
 
@@ -5584,6 +5664,7 @@
 }
 void OneofDescriptorProto::InternalSwap(OneofDescriptorProto* other) {
   name_.Swap(&other->name_);
+  std::swap(options_, other->options_);
   std::swap(_has_bits_[0], other->_has_bits_[0]);
   _internal_metadata_.Swap(&other->_internal_metadata_);
   std::swap(_cached_size_, other->_cached_size_);
@@ -5654,6 +5735,50 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
 }
 
+// optional .google.protobuf.OneofOptions options = 2;
+bool OneofDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+void OneofDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000002u;
+}
+void OneofDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+void OneofDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+  clear_has_options();
+}
+const ::google::protobuf::OneofOptions& OneofDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+::google::protobuf::OneofOptions* OneofDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::OneofOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+  return options_;
+}
+::google::protobuf::OneofOptions* OneofDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::OneofOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+void OneofDescriptorProto::set_allocated_options(::google::protobuf::OneofOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
 #endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
 
 // ===================================================================
@@ -5854,8 +5979,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.EnumDescriptorProto)
 }
 
-::google::protobuf::uint8* EnumDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -5871,15 +5996,15 @@
   // repeated .google.protobuf.EnumValueDescriptorProto value = 2;
   for (unsigned int i = 0, n = this->value_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->value(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->value(i), false, target);
   }
 
   // optional .google.protobuf.EnumOptions options = 3;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        3, *this->options_, false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -6335,8 +6460,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueDescriptorProto)
 }
 
-::google::protobuf::uint8* EnumValueDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValueDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -6357,8 +6482,8 @@
   // optional .google.protobuf.EnumValueOptions options = 3;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        3, *this->options_, false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -6810,8 +6935,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceDescriptorProto)
 }
 
-::google::protobuf::uint8* ServiceDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ServiceDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -6827,15 +6952,15 @@
   // repeated .google.protobuf.MethodDescriptorProto method = 2;
   for (unsigned int i = 0, n = this->method_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->method(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->method(i), false, target);
   }
 
   // optional .google.protobuf.ServiceOptions options = 3;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        3, *this->options_, false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -7399,8 +7524,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.MethodDescriptorProto)
 }
 
-::google::protobuf::uint8* MethodDescriptorProto::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MethodDescriptorProto::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodDescriptorProto)
   // optional string name = 1;
   if (has_name()) {
@@ -7438,8 +7563,8 @@
   // optional .google.protobuf.MethodOptions options = 4;
   if (has_options()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        4, *this->options_, target);
+      InternalWriteMessageNoVirtualToArray(
+        4, *this->options_, false, target);
   }
 
   // optional bool client_streaming = 5 [default = false];
@@ -8432,8 +8557,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FileOptions)
 }
 
-::google::protobuf::uint8* FileOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FileOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FileOptions)
   // optional string java_package = 1;
   if (has_java_package()) {
@@ -8539,13 +8664,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -9573,8 +9698,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.MessageOptions)
 }
 
-::google::protobuf::uint8* MessageOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MessageOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MessageOptions)
   // optional bool message_set_wire_format = 1 [default = false];
   if (has_message_set_wire_format()) {
@@ -9599,13 +9724,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -10237,8 +10362,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FieldOptions)
 }
 
-::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldOptions)
   // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING];
   if (has_ctype()) {
@@ -10275,13 +10400,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -10626,6 +10751,300 @@
 // ===================================================================
 
 #if !defined(_MSC_VER) || _MSC_VER >= 1900
+const int OneofOptions::kUninterpretedOptionFieldNumber;
+#endif  // !defined(_MSC_VER) || _MSC_VER >= 1900
+
+OneofOptions::OneofOptions()
+  : ::google::protobuf::Message(), _internal_metadata_(NULL) {
+  SharedCtor();
+  // @@protoc_insertion_point(constructor:google.protobuf.OneofOptions)
+}
+
+void OneofOptions::InitAsDefaultInstance() {
+}
+
+OneofOptions::OneofOptions(const OneofOptions& from)
+  : ::google::protobuf::Message(),
+    _internal_metadata_(NULL) {
+  SharedCtor();
+  MergeFrom(from);
+  // @@protoc_insertion_point(copy_constructor:google.protobuf.OneofOptions)
+}
+
+void OneofOptions::SharedCtor() {
+  _cached_size_ = 0;
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+}
+
+OneofOptions::~OneofOptions() {
+  // @@protoc_insertion_point(destructor:google.protobuf.OneofOptions)
+  SharedDtor();
+}
+
+void OneofOptions::SharedDtor() {
+  if (this != default_instance_) {
+  }
+}
+
+void OneofOptions::SetCachedSize(int size) const {
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+}
+const ::google::protobuf::Descriptor* OneofOptions::descriptor() {
+  protobuf_AssignDescriptorsOnce();
+  return OneofOptions_descriptor_;
+}
+
+const OneofOptions& OneofOptions::default_instance() {
+  if (default_instance_ == NULL) protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  return *default_instance_;
+}
+
+OneofOptions* OneofOptions::default_instance_ = NULL;
+
+OneofOptions* OneofOptions::New(::google::protobuf::Arena* arena) const {
+  OneofOptions* n = new OneofOptions;
+  if (arena != NULL) {
+    arena->Own(n);
+  }
+  return n;
+}
+
+void OneofOptions::Clear() {
+// @@protoc_insertion_point(message_clear_start:google.protobuf.OneofOptions)
+  _extensions_.Clear();
+  uninterpreted_option_.Clear();
+  ::memset(_has_bits_, 0, sizeof(_has_bits_));
+  if (_internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->Clear();
+  }
+}
+
+bool OneofOptions::MergePartialFromCodedStream(
+    ::google::protobuf::io::CodedInputStream* input) {
+#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure
+  ::google::protobuf::uint32 tag;
+  // @@protoc_insertion_point(parse_start:google.protobuf.OneofOptions)
+  for (;;) {
+    ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(16383);
+    tag = p.first;
+    if (!p.second) goto handle_unusual;
+    switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) {
+      // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+      case 999: {
+        if (tag == 7994) {
+          DO_(input->IncrementRecursionDepth());
+         parse_loop_uninterpreted_option:
+          DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth(
+                input, add_uninterpreted_option()));
+        } else {
+          goto handle_unusual;
+        }
+        if (input->ExpectTag(7994)) goto parse_loop_uninterpreted_option;
+        input->UnsafeDecrementRecursionDepth();
+        if (input->ExpectAtEnd()) goto success;
+        break;
+      }
+
+      default: {
+      handle_unusual:
+        if (tag == 0 ||
+            ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) {
+          goto success;
+        }
+        if ((8000u <= tag)) {
+          DO_(_extensions_.ParseField(tag, input, default_instance_,
+                                      mutable_unknown_fields()));
+          continue;
+        }
+        DO_(::google::protobuf::internal::WireFormat::SkipField(
+              input, tag, mutable_unknown_fields()));
+        break;
+      }
+    }
+  }
+success:
+  // @@protoc_insertion_point(parse_success:google.protobuf.OneofOptions)
+  return true;
+failure:
+  // @@protoc_insertion_point(parse_failure:google.protobuf.OneofOptions)
+  return false;
+#undef DO_
+}
+
+void OneofOptions::SerializeWithCachedSizes(
+    ::google::protobuf::io::CodedOutputStream* output) const {
+  // @@protoc_insertion_point(serialize_start:google.protobuf.OneofOptions)
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
+    ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray(
+      999, this->uninterpreted_option(i), output);
+  }
+
+  // Extension range [1000, 536870912)
+  _extensions_.SerializeWithCachedSizes(
+      1000, 536870912, output);
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    ::google::protobuf::internal::WireFormat::SerializeUnknownFields(
+        unknown_fields(), output);
+  }
+  // @@protoc_insertion_point(serialize_end:google.protobuf.OneofOptions)
+}
+
+::google::protobuf::uint8* OneofOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
+  // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.OneofOptions)
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
+    target = ::google::protobuf::internal::WireFormatLite::
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
+  }
+
+  // Extension range [1000, 536870912)
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
+        unknown_fields(), target);
+  }
+  // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.OneofOptions)
+  return target;
+}
+
+int OneofOptions::ByteSize() const {
+// @@protoc_insertion_point(message_byte_size_start:google.protobuf.OneofOptions)
+  int total_size = 0;
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  total_size += 2 * this->uninterpreted_option_size();
+  for (int i = 0; i < this->uninterpreted_option_size(); i++) {
+    total_size +=
+      ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual(
+        this->uninterpreted_option(i));
+  }
+
+  total_size += _extensions_.ByteSize();
+
+  if (_internal_metadata_.have_unknown_fields()) {
+    total_size +=
+      ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(
+        unknown_fields());
+  }
+  GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();
+  _cached_size_ = total_size;
+  GOOGLE_SAFE_CONCURRENT_WRITES_END();
+  return total_size;
+}
+
+void OneofOptions::MergeFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_merge_from_start:google.protobuf.OneofOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  const OneofOptions* source = 
+      ::google::protobuf::internal::DynamicCastToGenerated<const OneofOptions>(
+          &from);
+  if (source == NULL) {
+  // @@protoc_insertion_point(generalized_merge_from_cast_fail:google.protobuf.OneofOptions)
+    ::google::protobuf::internal::ReflectionOps::Merge(from, this);
+  } else {
+  // @@protoc_insertion_point(generalized_merge_from_cast_success:google.protobuf.OneofOptions)
+    MergeFrom(*source);
+  }
+}
+
+void OneofOptions::MergeFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_merge_from_start:google.protobuf.OneofOptions)
+  if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);
+  uninterpreted_option_.MergeFrom(from.uninterpreted_option_);
+  _extensions_.MergeFrom(from._extensions_);
+  if (from._internal_metadata_.have_unknown_fields()) {
+    mutable_unknown_fields()->MergeFrom(from.unknown_fields());
+  }
+}
+
+void OneofOptions::CopyFrom(const ::google::protobuf::Message& from) {
+// @@protoc_insertion_point(generalized_copy_from_start:google.protobuf.OneofOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+void OneofOptions::CopyFrom(const OneofOptions& from) {
+// @@protoc_insertion_point(class_specific_copy_from_start:google.protobuf.OneofOptions)
+  if (&from == this) return;
+  Clear();
+  MergeFrom(from);
+}
+
+bool OneofOptions::IsInitialized() const {
+
+  if (!::google::protobuf::internal::AllAreInitialized(this->uninterpreted_option())) return false;
+
+  if (!_extensions_.IsInitialized()) return false;  return true;
+}
+
+void OneofOptions::Swap(OneofOptions* other) {
+  if (other == this) return;
+  InternalSwap(other);
+}
+void OneofOptions::InternalSwap(OneofOptions* other) {
+  uninterpreted_option_.UnsafeArenaSwap(&other->uninterpreted_option_);
+  std::swap(_has_bits_[0], other->_has_bits_[0]);
+  _internal_metadata_.Swap(&other->_internal_metadata_);
+  std::swap(_cached_size_, other->_cached_size_);
+  _extensions_.Swap(&other->_extensions_);
+}
+
+::google::protobuf::Metadata OneofOptions::GetMetadata() const {
+  protobuf_AssignDescriptorsOnce();
+  ::google::protobuf::Metadata metadata;
+  metadata.descriptor = OneofOptions_descriptor_;
+  metadata.reflection = OneofOptions_reflection_;
+  return metadata;
+}
+
+#if PROTOBUF_INLINE_NOT_IN_HEADERS
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+int OneofOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+void OneofOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+const ::google::protobuf::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+::google::protobuf::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+::google::protobuf::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+#endif  // PROTOBUF_INLINE_NOT_IN_HEADERS
+
+// ===================================================================
+
+#if !defined(_MSC_VER) || _MSC_VER >= 1900
 const int EnumOptions::kAllowAliasFieldNumber;
 const int EnumOptions::kDeprecatedFieldNumber;
 const int EnumOptions::kUninterpretedOptionFieldNumber;
@@ -10834,8 +11253,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.EnumOptions)
 }
 
-::google::protobuf::uint8* EnumOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumOptions)
   // optional bool allow_alias = 2;
   if (has_allow_alias()) {
@@ -10850,13 +11269,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11231,8 +11650,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValueOptions)
 }
 
-::google::protobuf::uint8* EnumValueOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValueOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValueOptions)
   // optional bool deprecated = 1 [default = false];
   if (has_deprecated()) {
@@ -11242,13 +11661,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11588,8 +12007,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.ServiceOptions)
 }
 
-::google::protobuf::uint8* ServiceOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ServiceOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ServiceOptions)
   // optional bool deprecated = 33 [default = false];
   if (has_deprecated()) {
@@ -11599,13 +12018,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -11945,8 +12364,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.MethodOptions)
 }
 
-::google::protobuf::uint8* MethodOptions::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* MethodOptions::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.MethodOptions)
   // optional bool deprecated = 33 [default = false];
   if (has_deprecated()) {
@@ -11956,13 +12375,13 @@
   // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
   for (unsigned int i = 0, n = this->uninterpreted_option_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        999, this->uninterpreted_option(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        999, this->uninterpreted_option(i), false, target);
   }
 
   // Extension range [1000, 536870912)
-  target = _extensions_.SerializeWithCachedSizesToArray(
-      1000, 536870912, target);
+  target = _extensions_.InternalSerializeWithCachedSizesToArray(
+      1000, 536870912, false, target);
 
   if (_internal_metadata_.have_unknown_fields()) {
     target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(
@@ -12303,8 +12722,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption.NamePart)
 }
 
-::google::protobuf::uint8* UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UninterpretedOption_NamePart::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption.NamePart)
   // required string name_part = 1;
   if (has_name_part()) {
@@ -12765,14 +13184,14 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.UninterpretedOption)
 }
 
-::google::protobuf::uint8* UninterpretedOption::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UninterpretedOption::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UninterpretedOption)
   // repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
   for (unsigned int i = 0, n = this->name_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->name(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->name(i), false, target);
   }
 
   // optional string identifier_value = 3;
@@ -13606,8 +14025,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo.Location)
 }
 
-::google::protobuf::uint8* SourceCodeInfo_Location::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceCodeInfo_Location::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo.Location)
   // repeated int32 path = 1 [packed = true];
   if (this->path_size() > 0) {
@@ -13964,14 +14383,14 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.SourceCodeInfo)
 }
 
-::google::protobuf::uint8* SourceCodeInfo::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceCodeInfo::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceCodeInfo)
   // repeated .google.protobuf.SourceCodeInfo.Location location = 1;
   for (unsigned int i = 0, n = this->location_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        1, this->location(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        1, this->location(i), false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
@@ -14571,8 +14990,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo.Annotation)
 }
 
-::google::protobuf::uint8* GeneratedCodeInfo_Annotation::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* GeneratedCodeInfo_Annotation::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo.Annotation)
   // repeated int32 path = 1 [packed = true];
   if (this->path_size() > 0) {
@@ -14886,14 +15305,14 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.GeneratedCodeInfo)
 }
 
-::google::protobuf::uint8* GeneratedCodeInfo::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* GeneratedCodeInfo::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.GeneratedCodeInfo)
   // repeated .google.protobuf.GeneratedCodeInfo.Annotation annotation = 1;
   for (unsigned int i = 0, n = this->annotation_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        1, this->annotation(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        1, this->annotation(i), false, target);
   }
 
   if (_internal_metadata_.have_unknown_fields()) {
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 92a0a3a..5a9e12b 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -56,6 +56,7 @@
 class MethodDescriptorProto;
 class MethodOptions;
 class OneofDescriptorProto;
+class OneofOptions;
 class ServiceDescriptorProto;
 class ServiceOptions;
 class SourceCodeInfo;
@@ -180,7 +181,7 @@
 }
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorSet) */ {
  public:
   FileDescriptorSet();
   virtual ~FileDescriptorSet();
@@ -222,7 +223,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -272,7 +277,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileDescriptorProto) */ {
  public:
   FileDescriptorProto();
   virtual ~FileDescriptorProto();
@@ -314,7 +319,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -515,7 +524,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ExtensionRange) */ {
  public:
   DescriptorProto_ExtensionRange();
   virtual ~DescriptorProto_ExtensionRange();
@@ -557,7 +566,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -614,7 +627,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto_ReservedRange : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto.ReservedRange) */ {
  public:
   DescriptorProto_ReservedRange();
   virtual ~DescriptorProto_ReservedRange();
@@ -656,7 +669,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -713,7 +730,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DescriptorProto) */ {
  public:
   DescriptorProto();
   virtual ~DescriptorProto();
@@ -755,7 +772,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -930,7 +951,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldDescriptorProto) */ {
  public:
   FieldDescriptorProto();
   virtual ~FieldDescriptorProto();
@@ -972,7 +993,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1222,7 +1247,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT OneofDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofDescriptorProto) */ {
  public:
   OneofDescriptorProto();
   virtual ~OneofDescriptorProto();
@@ -1264,7 +1289,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1298,15 +1327,27 @@
   ::std::string* release_name();
   void set_allocated_name(::std::string* name);
 
+  // optional .google.protobuf.OneofOptions options = 2;
+  bool has_options() const;
+  void clear_options();
+  static const int kOptionsFieldNumber = 2;
+  const ::google::protobuf::OneofOptions& options() const;
+  ::google::protobuf::OneofOptions* mutable_options();
+  ::google::protobuf::OneofOptions* release_options();
+  void set_allocated_options(::google::protobuf::OneofOptions* options);
+
   // @@protoc_insertion_point(class_scope:google.protobuf.OneofDescriptorProto)
  private:
   inline void set_has_name();
   inline void clear_has_name();
+  inline void set_has_options();
+  inline void clear_has_options();
 
   ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
   ::google::protobuf::uint32 _has_bits_[1];
   mutable int _cached_size_;
   ::google::protobuf::internal::ArenaStringPtr name_;
+  ::google::protobuf::OneofOptions* options_;
   friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
   friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
@@ -1316,7 +1357,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumDescriptorProto) */ {
  public:
   EnumDescriptorProto();
   virtual ~EnumDescriptorProto();
@@ -1358,7 +1399,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1435,7 +1480,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueDescriptorProto) */ {
  public:
   EnumValueDescriptorProto();
   virtual ~EnumValueDescriptorProto();
@@ -1477,7 +1522,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1551,7 +1600,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceDescriptorProto) */ {
  public:
   ServiceDescriptorProto();
   virtual ~ServiceDescriptorProto();
@@ -1593,7 +1642,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1670,7 +1723,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodDescriptorProto) */ {
  public:
   MethodDescriptorProto();
   virtual ~MethodDescriptorProto();
@@ -1712,7 +1765,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -1826,7 +1883,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FileOptions) */ {
  public:
   FileOptions();
   virtual ~FileOptions();
@@ -1868,7 +1925,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2114,7 +2175,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MessageOptions) */ {
  public:
   MessageOptions();
   virtual ~MessageOptions();
@@ -2156,7 +2217,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2249,7 +2314,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldOptions) */ {
  public:
   FieldOptions();
   virtual ~FieldOptions();
@@ -2291,7 +2356,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2460,7 +2529,106 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT OneofOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.OneofOptions) */ {
+ public:
+  OneofOptions();
+  virtual ~OneofOptions();
+
+  OneofOptions(const OneofOptions& from);
+
+  inline OneofOptions& operator=(const OneofOptions& from) {
+    CopyFrom(from);
+    return *this;
+  }
+
+  inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {
+    return _internal_metadata_.unknown_fields();
+  }
+
+  inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {
+    return _internal_metadata_.mutable_unknown_fields();
+  }
+
+  static const ::google::protobuf::Descriptor* descriptor();
+  static const OneofOptions& default_instance();
+
+  void Swap(OneofOptions* other);
+
+  // implements Message ----------------------------------------------
+
+  inline OneofOptions* New() const { return New(NULL); }
+
+  OneofOptions* New(::google::protobuf::Arena* arena) const;
+  void CopyFrom(const ::google::protobuf::Message& from);
+  void MergeFrom(const ::google::protobuf::Message& from);
+  void CopyFrom(const OneofOptions& from);
+  void MergeFrom(const OneofOptions& from);
+  void Clear();
+  bool IsInitialized() const;
+
+  int ByteSize() const;
+  bool MergePartialFromCodedStream(
+      ::google::protobuf::io::CodedInputStream* input);
+  void SerializeWithCachedSizes(
+      ::google::protobuf::io::CodedOutputStream* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
+  int GetCachedSize() const { return _cached_size_; }
+  private:
+  void SharedCtor();
+  void SharedDtor();
+  void SetCachedSize(int size) const;
+  void InternalSwap(OneofOptions* other);
+  private:
+  inline ::google::protobuf::Arena* GetArenaNoVirtual() const {
+    return _internal_metadata_.arena();
+  }
+  inline void* MaybeArenaPtr() const {
+    return _internal_metadata_.raw_arena_ptr();
+  }
+  public:
+
+  ::google::protobuf::Metadata GetMetadata() const;
+
+  // nested types ----------------------------------------------------
+
+  // accessors -------------------------------------------------------
+
+  // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+  int uninterpreted_option_size() const;
+  void clear_uninterpreted_option();
+  static const int kUninterpretedOptionFieldNumber = 999;
+  const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const;
+  ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index);
+  ::google::protobuf::UninterpretedOption* add_uninterpreted_option();
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+      mutable_uninterpreted_option();
+  const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+      uninterpreted_option() const;
+
+  GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(OneofOptions)
+  // @@protoc_insertion_point(class_scope:google.protobuf.OneofOptions)
+ private:
+
+  ::google::protobuf::internal::ExtensionSet _extensions_;
+
+  ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;
+  ::google::protobuf::uint32 _has_bits_[1];
+  mutable int _cached_size_;
+  ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
+  friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto();
+  friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto();
+
+  void InitAsDefaultInstance();
+  static OneofOptions* default_instance_;
+};
+// -------------------------------------------------------------------
+
+class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumOptions) */ {
  public:
   EnumOptions();
   virtual ~EnumOptions();
@@ -2502,7 +2670,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2575,7 +2747,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValueOptions) */ {
  public:
   EnumValueOptions();
   virtual ~EnumValueOptions();
@@ -2617,7 +2789,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2680,7 +2856,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ServiceOptions) */ {
  public:
   ServiceOptions();
   virtual ~ServiceOptions();
@@ -2722,7 +2898,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2785,7 +2965,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.MethodOptions) */ {
  public:
   MethodOptions();
   virtual ~MethodOptions();
@@ -2827,7 +3007,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2890,7 +3074,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption.NamePart) */ {
  public:
   UninterpretedOption_NamePart();
   virtual ~UninterpretedOption_NamePart();
@@ -2932,7 +3116,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -2997,7 +3185,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UninterpretedOption) */ {
  public:
   UninterpretedOption();
   virtual ~UninterpretedOption();
@@ -3039,7 +3227,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -3166,7 +3358,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceCodeInfo_Location : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo.Location) */ {
  public:
   SourceCodeInfo_Location();
   virtual ~SourceCodeInfo_Location();
@@ -3208,7 +3400,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -3320,7 +3516,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceCodeInfo : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceCodeInfo) */ {
  public:
   SourceCodeInfo();
   virtual ~SourceCodeInfo();
@@ -3362,7 +3558,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -3414,7 +3614,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo_Annotation : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo.Annotation) */ {
  public:
   GeneratedCodeInfo_Annotation();
   virtual ~GeneratedCodeInfo_Annotation();
@@ -3456,7 +3656,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -3542,7 +3746,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT GeneratedCodeInfo : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.GeneratedCodeInfo) */ {
  public:
   GeneratedCodeInfo();
   virtual ~GeneratedCodeInfo();
@@ -3584,7 +3788,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -5106,6 +5314,50 @@
   // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.name)
 }
 
+// optional .google.protobuf.OneofOptions options = 2;
+inline bool OneofDescriptorProto::has_options() const {
+  return (_has_bits_[0] & 0x00000002u) != 0;
+}
+inline void OneofDescriptorProto::set_has_options() {
+  _has_bits_[0] |= 0x00000002u;
+}
+inline void OneofDescriptorProto::clear_has_options() {
+  _has_bits_[0] &= ~0x00000002u;
+}
+inline void OneofDescriptorProto::clear_options() {
+  if (options_ != NULL) options_->::google::protobuf::OneofOptions::Clear();
+  clear_has_options();
+}
+inline const ::google::protobuf::OneofOptions& OneofDescriptorProto::options() const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofDescriptorProto.options)
+  return options_ != NULL ? *options_ : *default_instance_->options_;
+}
+inline ::google::protobuf::OneofOptions* OneofDescriptorProto::mutable_options() {
+  set_has_options();
+  if (options_ == NULL) {
+    options_ = new ::google::protobuf::OneofOptions;
+  }
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofDescriptorProto.options)
+  return options_;
+}
+inline ::google::protobuf::OneofOptions* OneofDescriptorProto::release_options() {
+  // @@protoc_insertion_point(field_release:google.protobuf.OneofDescriptorProto.options)
+  clear_has_options();
+  ::google::protobuf::OneofOptions* temp = options_;
+  options_ = NULL;
+  return temp;
+}
+inline void OneofDescriptorProto::set_allocated_options(::google::protobuf::OneofOptions* options) {
+  delete options_;
+  options_ = options;
+  if (options) {
+    set_has_options();
+  } else {
+    clear_has_options();
+  }
+  // @@protoc_insertion_point(field_set_allocated:google.protobuf.OneofDescriptorProto.options)
+}
+
 // -------------------------------------------------------------------
 
 // EnumDescriptorProto
@@ -6587,6 +6839,40 @@
 
 // -------------------------------------------------------------------
 
+// OneofOptions
+
+// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
+inline int OneofOptions::uninterpreted_option_size() const {
+  return uninterpreted_option_.size();
+}
+inline void OneofOptions::clear_uninterpreted_option() {
+  uninterpreted_option_.Clear();
+}
+inline const ::google::protobuf::UninterpretedOption& OneofOptions::uninterpreted_option(int index) const {
+  // @@protoc_insertion_point(field_get:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Get(index);
+}
+inline ::google::protobuf::UninterpretedOption* OneofOptions::mutable_uninterpreted_option(int index) {
+  // @@protoc_insertion_point(field_mutable:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Mutable(index);
+}
+inline ::google::protobuf::UninterpretedOption* OneofOptions::add_uninterpreted_option() {
+  // @@protoc_insertion_point(field_add:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_.Add();
+}
+inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >*
+OneofOptions::mutable_uninterpreted_option() {
+  // @@protoc_insertion_point(field_mutable_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return &uninterpreted_option_;
+}
+inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >&
+OneofOptions::uninterpreted_option() const {
+  // @@protoc_insertion_point(field_list:google.protobuf.OneofOptions.uninterpreted_option)
+  return uninterpreted_option_;
+}
+
+// -------------------------------------------------------------------
+
 // EnumOptions
 
 // optional bool allow_alias = 2;
@@ -7669,6 +7955,8 @@
 
 // -------------------------------------------------------------------
 
+// -------------------------------------------------------------------
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 08b1555..da853db 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -202,6 +202,7 @@
 // Describes a oneof.
 message OneofDescriptorProto {
   optional string name = 1;
+  optional OneofOptions options = 2;
 }
 
 // Describes an enum type.
@@ -538,6 +539,14 @@
   extensions 1000 to max;
 }
 
+message OneofOptions {
+  // The parser stores options it doesn't recognize here. See above.
+  repeated UninterpretedOption uninterpreted_option = 999;
+
+  // Clients can define custom options in extensions of this message. See above.
+  extensions 1000 to max;
+}
+
 message EnumOptions {
 
   // Set this option to true to allow mapping different tag names to the same
diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc
index 1fc3816..4f568f7 100644
--- a/src/google/protobuf/descriptor_database_unittest.cc
+++ b/src/google/protobuf/descriptor_database_unittest.cc
@@ -48,7 +48,6 @@
 
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index f937b9e..4183138 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -55,7 +55,6 @@
 #include <google/protobuf/stubs/common.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/logging.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -2705,6 +2704,7 @@
       protobuf_unittest::TestMessageWithCustomOptions::descriptor();
   const FileDescriptor* file = message->file();
   const FieldDescriptor* field = message->FindFieldByName("field1");
+  const OneofDescriptor* oneof = message->FindOneofByName("AnOneof");
   const EnumDescriptor* enm = message->FindEnumTypeByName("AnEnum");
   // TODO(benjy): Support EnumValue options, once the compiler does.
   const ServiceDescriptor* service =
@@ -2719,6 +2719,8 @@
             field->options().GetExtension(protobuf_unittest::field_opt1));
   EXPECT_EQ(42,  // Check that we get the default for an option we don't set.
             field->options().GetExtension(protobuf_unittest::field_opt2));
+  EXPECT_EQ(-99,
+            oneof->options().GetExtension(protobuf_unittest::oneof_opt1));
   EXPECT_EQ(-789,
             enm->options().GetExtension(protobuf_unittest::enum_opt1));
   EXPECT_EQ(123,
@@ -5027,7 +5029,7 @@
   BuildFileWithErrors(
       EmbedAggregateValue("aggregate_value: \"1+2\""),
       "foo.proto: foo.proto: OPTION_VALUE: Error while parsing option "
-      "value for \"foo\": Expected identifier.\n");
+      "value for \"foo\": Expected identifier, got: 1\n");
 }
 
 TEST_F(ValidationErrorTest, AggregateValueUnknownFields) {
@@ -5834,7 +5836,7 @@
       "  field { name:'name' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
       "  field { name:'Name' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
       "}",
-      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"Name\" "
+      "foo.proto: Foo: OTHER: The JSON camel-case name of field \"Name\" "
       "conflicts with field \"name\". This is not allowed in proto3.\n");
   // Underscores are ignored.
   BuildFileWithErrors(
@@ -5845,7 +5847,7 @@
       "  field { name:'ab' number:1 label:LABEL_OPTIONAL type:TYPE_INT32 }"
       "  field { name:'_a__b_' number:2 label:LABEL_OPTIONAL type:TYPE_INT32 }"
       "}",
-      "foo.proto: Foo: OTHER: The JSON camcel-case name of field \"_a__b_\" "
+      "foo.proto: Foo: OTHER: The JSON camel-case name of field \"_a__b_\" "
       "conflicts with field \"ab\". This is not allowed in proto3.\n");
 }
 
diff --git a/src/google/protobuf/duration.pb.cc b/src/google/protobuf/duration.pb.cc
index e363934..b0c641b 100644
--- a/src/google/protobuf/duration.pb.cc
+++ b/src/google/protobuf/duration.pb.cc
@@ -279,8 +279,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Duration)
 }
 
-::google::protobuf::uint8* Duration::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Duration::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Duration)
   // optional int64 seconds = 1;
   if (this->seconds() != 0) {
diff --git a/src/google/protobuf/duration.pb.h b/src/google/protobuf/duration.pb.h
index 215a52c..ad47963 100644
--- a/src/google/protobuf/duration.pb.h
+++ b/src/google/protobuf/duration.pb.h
@@ -41,7 +41,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Duration : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Duration) */ {
  public:
   Duration();
   virtual ~Duration();
@@ -75,7 +75,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc
index 9e83bd2..5d914bf 100644
--- a/src/google/protobuf/dynamic_message.cc
+++ b/src/google/protobuf/dynamic_message.cc
@@ -70,7 +70,6 @@
 #endif
 
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 70e437d..fe51d8c 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -45,8 +45,6 @@
 #include <google/protobuf/stubs/shared_ptr.h>
 #endif
 
-#include <google/protobuf/stubs/scoped_ptr.h>
-#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/dynamic_message.h>
 #include <google/protobuf/descriptor.h>
 #include <google/protobuf/descriptor.pb.h>
@@ -55,6 +53,7 @@
 #include <google/protobuf/unittest_no_field_presence.pb.h>
 
 #include <google/protobuf/stubs/logging.h>
+#include <google/protobuf/stubs/common.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
diff --git a/src/google/protobuf/empty.pb.cc b/src/google/protobuf/empty.pb.cc
index dcf8426..8b46120 100644
--- a/src/google/protobuf/empty.pb.cc
+++ b/src/google/protobuf/empty.pb.cc
@@ -221,8 +221,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Empty)
 }
 
-::google::protobuf::uint8* Empty::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Empty::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Empty)
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Empty)
   return target;
diff --git a/src/google/protobuf/empty.pb.h b/src/google/protobuf/empty.pb.h
index 868009f..8e78733 100644
--- a/src/google/protobuf/empty.pb.h
+++ b/src/google/protobuf/empty.pb.h
@@ -41,7 +41,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Empty : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Empty) */ {
  public:
   Empty();
   virtual ~Empty();
@@ -80,7 +80,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc
index 9afb236..7d20a0f 100644
--- a/src/google/protobuf/extension_set.cc
+++ b/src/google/protobuf/extension_set.cc
@@ -177,7 +177,8 @@
 // ===================================================================
 // Constructors and basic methods.
 
-ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena) : arena_(arena) {
+ExtensionSet::ExtensionSet(::google::protobuf::Arena* arena)
+    : arena_(arena) {
   if (arena_ != NULL) {
     arena_->OwnDestructor(&extensions_);
   }
@@ -188,7 +189,7 @@
 ExtensionSet::~ExtensionSet() {
   // Deletes all allocated extensions.
   if (arena_ == NULL) {
-    for (map<int, Extension>::iterator iter = extensions_.begin();
+    for (ExtensionMap::iterator iter = extensions_.begin();
          iter != extensions_.end(); ++iter) {
       iter->second.Free();
     }
@@ -201,7 +202,7 @@
 //                                 vector<const FieldDescriptor*>* output) const
 
 bool ExtensionSet::Has(int number) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) return false;
   GOOGLE_DCHECK(!iter->second.is_repeated);
   return !iter->second.is_cleared;
@@ -209,7 +210,7 @@
 
 int ExtensionSet::NumExtensions() const {
   int result = 0;
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     if (!iter->second.is_cleared) {
       ++result;
@@ -219,13 +220,13 @@
 }
 
 int ExtensionSet::ExtensionSize(int number) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) return false;
   return iter->second.GetSize();
 }
 
 FieldType ExtensionSet::ExtensionType(int number) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) {
     GOOGLE_LOG(DFATAL) << "Don't lookup extension types if they aren't present (1). ";
     return 0;
@@ -237,7 +238,7 @@
 }
 
 void ExtensionSet::ClearExtension(int number) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) return;
   iter->second.Clear();
 }
@@ -265,7 +266,7 @@
                                                                                \
 LOWERCASE ExtensionSet::Get##CAMELCASE(int number,                             \
                                        LOWERCASE default_value) const {        \
-  map<int, Extension>::const_iterator iter = extensions_.find(number);         \
+  ExtensionMap::const_iterator iter = extensions_.find(number);                \
   if (iter == extensions_.end() || iter->second.is_cleared) {                  \
     return default_value;                                                      \
   } else {                                                                     \
@@ -290,7 +291,7 @@
 }                                                                              \
                                                                                \
 LOWERCASE ExtensionSet::GetRepeated##CAMELCASE(int number, int index) const {  \
-  map<int, Extension>::const_iterator iter = extensions_.find(number);         \
+  ExtensionMap::const_iterator iter = extensions_.find(number);                \
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE);                              \
   return iter->second.repeated_##LOWERCASE##_value->Get(index);                \
@@ -298,7 +299,7 @@
                                                                                \
 void ExtensionSet::SetRepeated##CAMELCASE(                                     \
     int number, int index, LOWERCASE value) {                                  \
-  map<int, Extension>::iterator iter = extensions_.find(number);               \
+  ExtensionMap::iterator iter = extensions_.find(number);                      \
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty)."; \
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, UPPERCASE);                              \
   iter->second.repeated_##LOWERCASE##_value->Set(index, value);                \
@@ -334,7 +335,7 @@
 
 const void* ExtensionSet::GetRawRepeatedField(int number,
                                               const void* default_value) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) {
     return default_value;
   }
@@ -408,7 +409,7 @@
 // Compatible version using old call signature. Does not create extensions when
 // the don't already exist; instead, just GOOGLE_CHECK-fails.
 void* ExtensionSet::MutableRawRepeatedField(int number) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter == extensions_.end()) << "Extension not found.";
   // We assume that all the RepeatedField<>* pointers have the same
   // size and alignment within the anonymous union in Extension.
@@ -420,7 +421,7 @@
 // Enums
 
 int ExtensionSet::GetEnum(int number, int default_value) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end() || iter->second.is_cleared) {
     // Not present.  Return the default value.
     return default_value;
@@ -445,14 +446,14 @@
 }
 
 int ExtensionSet::GetRepeatedEnum(int number, int index) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM);
   return iter->second.repeated_enum_value->Get(index);
 }
 
 void ExtensionSet::SetRepeatedEnum(int number, int index, int value) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, ENUM);
   iter->second.repeated_enum_value->Set(index, value);
@@ -481,7 +482,7 @@
 
 const string& ExtensionSet::GetString(int number,
                                       const string& default_value) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end() || iter->second.is_cleared) {
     // Not present.  Return the default value.
     return default_value;
@@ -507,14 +508,14 @@
 }
 
 const string& ExtensionSet::GetRepeatedString(int number, int index) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING);
   return iter->second.repeated_string_value->Get(index);
 }
 
 string* ExtensionSet::MutableRepeatedString(int number, int index) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, STRING);
   return iter->second.repeated_string_value->Mutable(index);
@@ -541,7 +542,7 @@
 
 const MessageLite& ExtensionSet::GetMessage(
     int number, const MessageLite& default_value) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) {
     // Not present.  Return the default value.
     return default_value;
@@ -664,7 +665,7 @@
 
 MessageLite* ExtensionSet::ReleaseMessage(int number,
                                           const MessageLite& prototype) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) {
     // Not present.  Return NULL.
     return NULL;
@@ -693,7 +694,7 @@
 
 MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
     int number, const MessageLite& prototype) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   if (iter == extensions_.end()) {
     // Not present.  Return NULL.
     return NULL;
@@ -720,14 +721,14 @@
 
 const MessageLite& ExtensionSet::GetRepeatedMessage(
     int number, int index) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE);
   return iter->second.repeated_message_value->Get(index);
 }
 
 MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
   GOOGLE_DCHECK_TYPE(iter->second, REPEATED, MESSAGE);
   return iter->second.repeated_message_value->Mutable(index);
@@ -766,7 +767,7 @@
 #undef GOOGLE_DCHECK_TYPE
 
 void ExtensionSet::RemoveLast(int number) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
 
   Extension* extension = &iter->second;
@@ -807,7 +808,7 @@
 }
 
 MessageLite* ExtensionSet::ReleaseLast(int number) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
 
   Extension* extension = &iter->second;
@@ -817,7 +818,7 @@
 }
 
 void ExtensionSet::SwapElements(int number, int index1, int index2) {
-  map<int, Extension>::iterator iter = extensions_.find(number);
+  ExtensionMap::iterator iter = extensions_.find(number);
   GOOGLE_CHECK(iter != extensions_.end()) << "Index out-of-bounds (field is empty).";
 
   Extension* extension = &iter->second;
@@ -860,14 +861,14 @@
 // ===================================================================
 
 void ExtensionSet::Clear() {
-  for (map<int, Extension>::iterator iter = extensions_.begin();
+  for (ExtensionMap::iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     iter->second.Clear();
   }
 }
 
 void ExtensionSet::MergeFrom(const ExtensionSet& other) {
-  for (map<int, Extension>::const_iterator iter = other.extensions_.begin();
+  for (ExtensionMap::const_iterator iter = other.extensions_.begin();
        iter != other.extensions_.end(); ++iter) {
     const Extension& other_extension = iter->second;
     InternalExtensionMergeFrom(iter->first, other_extension);
@@ -1031,8 +1032,8 @@
 void ExtensionSet::SwapExtension(ExtensionSet* other,
                                  int number) {
   if (this == other) return;
-  map<int, Extension>::iterator this_iter = extensions_.find(number);
-  map<int, Extension>::iterator other_iter = other->extensions_.find(number);
+  ExtensionMap::iterator this_iter = extensions_.find(number);
+  ExtensionMap::iterator other_iter = other->extensions_.find(number);
 
   if (this_iter == extensions_.end() &&
       other_iter == other->extensions_.end()) {
@@ -1052,7 +1053,7 @@
       // implemented in ExtensionSet's MergeFrom.
       ExtensionSet temp;
       temp.InternalExtensionMergeFrom(number, other_iter->second);
-      map<int, Extension>::iterator temp_iter = temp.extensions_.find(number);
+      ExtensionMap::iterator temp_iter = temp.extensions_.find(number);
       other_iter->second.Clear();
       other->InternalExtensionMergeFrom(number, this_iter->second);
       this_iter->second.Clear();
@@ -1085,7 +1086,7 @@
 bool ExtensionSet::IsInitialized() const {
   // Extensions are never required.  However, we need to check that all
   // embedded messages are initialized.
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     const Extension& extension = iter->second;
     if (cpp_type(extension.type) == WireFormatLite::CPPTYPE_MESSAGE) {
@@ -1345,7 +1346,7 @@
 void ExtensionSet::SerializeWithCachedSizes(
     int start_field_number, int end_field_number,
     io::CodedOutputStream* output) const {
-  map<int, Extension>::const_iterator iter;
+  ExtensionMap::const_iterator iter;
   for (iter = extensions_.lower_bound(start_field_number);
        iter != extensions_.end() && iter->first < end_field_number;
        ++iter) {
@@ -1356,7 +1357,7 @@
 int ExtensionSet::ByteSize() const {
   int total_size = 0;
 
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     total_size += iter->second.ByteSize(iter->first);
   }
@@ -1370,7 +1371,7 @@
 bool ExtensionSet::MaybeNewExtension(int number,
                                      const FieldDescriptor* descriptor,
                                      Extension** result) {
-  pair<map<int, Extension>::iterator, bool> insert_result =
+  pair<ExtensionMap::iterator, bool> insert_result =
       extensions_.insert(std::make_pair(number, Extension()));
   *result = &insert_result.first->second;
   (*result)->descriptor = descriptor;
diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h
index bca179b..a92c504 100644
--- a/src/google/protobuf/extension_set.h
+++ b/src/google/protobuf/extension_set.h
@@ -273,6 +273,8 @@
 
   MessageLite* ReleaseMessage(const FieldDescriptor* descriptor,
                               MessageFactory* factory);
+  MessageLite* UnsafeArenaReleaseMessage(const FieldDescriptor* descriptor,
+                                         MessageFactory* factory);
 #undef desc
   ::google::protobuf::Arena* GetArenaNoVirtual() const { return arena_; }
 
@@ -403,13 +405,27 @@
   // serialized extensions.
   //
   // Returns a pointer past the last written byte.
-  uint8* SerializeWithCachedSizesToArray(int start_field_number,
-                                         int end_field_number,
-                                         uint8* target) const;
+  uint8* InternalSerializeWithCachedSizesToArray(int start_field_number,
+                                                 int end_field_number,
+                                                 bool deterministic,
+                                                 uint8* target) const;
 
   // Like above but serializes in MessageSet format.
   void SerializeMessageSetWithCachedSizes(io::CodedOutputStream* output) const;
-  uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const;
+  uint8* InternalSerializeMessageSetWithCachedSizesToArray(bool deterministic,
+                                                           uint8* target) const;
+
+  // For backward-compatibility, versions of two of the above methods that
+  // are never forced to serialize deterministically.
+  uint8* SerializeWithCachedSizesToArray(int start_field_number,
+                                         int end_field_number,
+                                         uint8* target) const {
+    return InternalSerializeWithCachedSizesToArray(
+        start_field_number, end_field_number, false, target);
+  }
+  uint8* SerializeMessageSetWithCachedSizesToArray(uint8* target) const {
+    return InternalSerializeMessageSetWithCachedSizesToArray(false, target);
+  }
 
   // Returns the total serialized size of all the extensions.
   int ByteSize() const;
@@ -456,6 +472,13 @@
     virtual void WriteMessage(int number,
                               io::CodedOutputStream* output) const = 0;
     virtual uint8* WriteMessageToArray(int number, uint8* target) const = 0;
+    virtual uint8* InternalWriteMessageToArray(int number, bool,
+                                               uint8* target) const {
+      // TODO(gpike): make this pure virtual. This is a placeholder because we
+      // need to update third_party/upb, for example.
+      return WriteMessageToArray(number, target);
+    }
+
    private:
     GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(LazyMessageExtension);
   };
@@ -522,14 +545,16 @@
     void SerializeFieldWithCachedSizes(
         int number,
         io::CodedOutputStream* output) const;
-    uint8* SerializeFieldWithCachedSizesToArray(
+    uint8* InternalSerializeFieldWithCachedSizesToArray(
         int number,
+        bool deterministic,
         uint8* target) const;
     void SerializeMessageSetItemWithCachedSizes(
         int number,
         io::CodedOutputStream* output) const;
-    uint8* SerializeMessageSetItemWithCachedSizesToArray(
+    uint8* InternalSerializeMessageSetItemWithCachedSizesToArray(
         int number,
+        bool deterministic,
         uint8* target) const;
     int ByteSize(int number) const;
     int MessageSetItemByteSize(int number) const;
@@ -538,6 +563,7 @@
     void Free();
     int SpaceUsedExcludingSelf() const;
   };
+  typedef std::map<int, Extension> ExtensionMap;
 
 
   // Merges existing Extension from other_extension
@@ -608,7 +634,7 @@
   // only contain a small number of extensions whereas hash_map is optimized
   // for 100 elements or more.  Also, we want AppendToList() to order fields
   // by field number.
-  std::map<int, Extension> extensions_;
+  ExtensionMap extensions_;
   ::google::protobuf::Arena* arena_;
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionSet);
 };
@@ -980,11 +1006,22 @@
                                   MutableType message, ExtensionSet* set) {
     set->SetAllocatedMessage(number, field_type, NULL, message);
   }
+  static inline void UnsafeArenaSetAllocated(int number, FieldType field_type,
+                                             MutableType message,
+                                             ExtensionSet* set) {
+    set->UnsafeArenaSetAllocatedMessage(number, field_type, NULL, message);
+  }
   static inline MutableType Release(int number, FieldType /* field_type */,
                                     ExtensionSet* set) {
     return static_cast<Type*>(set->ReleaseMessage(
         number, Type::default_instance()));
   }
+  static inline MutableType UnsafeArenaRelease(int number,
+                                               FieldType /* field_type */,
+                                               ExtensionSet* set) {
+    return static_cast<Type*>(set->UnsafeArenaReleaseMessage(
+        number, Type::default_instance()));
+  }
 };
 
 // forward declaration
@@ -1178,12 +1215,32 @@
   template <typename _proto_TypeTraits,                                       \
             ::google::protobuf::internal::FieldType _field_type,                        \
             bool _is_packed>                                                  \
+  inline void UnsafeArenaSetAllocatedExtension(                               \
+      const ::google::protobuf::internal::ExtensionIdentifier<                          \
+        CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id,           \
+      typename _proto_TypeTraits::Singular::MutableType value) {              \
+    _proto_TypeTraits::UnsafeArenaSetAllocated(id.number(), _field_type,      \
+                                               value, &_extensions_);         \
+  }                                                                           \
+  template <typename _proto_TypeTraits,                                       \
+            ::google::protobuf::internal::FieldType _field_type,                        \
+            bool _is_packed>                                                  \
   inline typename _proto_TypeTraits::Singular::MutableType ReleaseExtension(  \
       const ::google::protobuf::internal::ExtensionIdentifier<                          \
         CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {         \
     return _proto_TypeTraits::Release(id.number(), _field_type,               \
                                       &_extensions_);                         \
   }                                                                           \
+  template <typename _proto_TypeTraits,                                       \
+            ::google::protobuf::internal::FieldType _field_type,                        \
+            bool _is_packed>                                                  \
+  inline typename _proto_TypeTraits::Singular::MutableType                    \
+      UnsafeArenaReleaseExtension(                                            \
+          const ::google::protobuf::internal::ExtensionIdentifier<                      \
+            CLASSNAME, _proto_TypeTraits, _field_type, _is_packed>& id) {     \
+    return _proto_TypeTraits::UnsafeArenaRelease(id.number(), _field_type,    \
+                                                 &_extensions_);              \
+  }                                                                           \
                                                                               \
   /* Repeated accessors */                                                    \
   template <typename _proto_TypeTraits,                                       \
diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc
index 82e3e09..7177d78 100644
--- a/src/google/protobuf/extension_set_heavy.cc
+++ b/src/google/protobuf/extension_set_heavy.cc
@@ -95,7 +95,7 @@
     const Descriptor* containing_type,
     const DescriptorPool* pool,
     std::vector<const FieldDescriptor*>* output) const {
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     bool has = false;
     if (iter->second.is_repeated) {
@@ -144,7 +144,7 @@
 const MessageLite& ExtensionSet::GetMessage(int number,
                                             const Descriptor* message_type,
                                             MessageFactory* factory) const {
-  map<int, Extension>::const_iterator iter = extensions_.find(number);
+  ExtensionMap::const_iterator iter = extensions_.find(number);
   if (iter == extensions_.end() || iter->second.is_cleared) {
     // Not present.  Return the default value.
     return *factory->GetPrototype(message_type);
@@ -187,7 +187,7 @@
 
 MessageLite* ExtensionSet::ReleaseMessage(const FieldDescriptor* descriptor,
                                           MessageFactory* factory) {
-  map<int, Extension>::iterator iter = extensions_.find(descriptor->number());
+  ExtensionMap::iterator iter = extensions_.find(descriptor->number());
   if (iter == extensions_.end()) {
     // Not present.  Return NULL.
     return NULL;
@@ -213,6 +213,29 @@
   }
 }
 
+MessageLite* ExtensionSet::UnsafeArenaReleaseMessage(
+    const FieldDescriptor* descriptor, MessageFactory* factory) {
+  ExtensionMap::iterator iter = extensions_.find(descriptor->number());
+  if (iter == extensions_.end()) {
+    // Not present.  Return NULL.
+    return NULL;
+  } else {
+    GOOGLE_DCHECK_TYPE(iter->second, OPTIONAL, MESSAGE);
+    MessageLite* ret = NULL;
+    if (iter->second.is_lazy) {
+      ret = iter->second.lazymessage_value->UnsafeArenaReleaseMessage(
+          *factory->GetPrototype(descriptor->message_type()));
+      if (arena_ == NULL) {
+        delete iter->second.lazymessage_value;
+      }
+    } else {
+      ret = iter->second.message_value;
+    }
+    extensions_.erase(descriptor->number());
+    return ret;
+  }
+}
+
 ExtensionSet::Extension* ExtensionSet::MaybeNewRepeatedExtension(const FieldDescriptor* descriptor) {
   Extension* extension;
   if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) {
@@ -319,7 +342,7 @@
 int ExtensionSet::SpaceUsedExcludingSelf() const {
   int total_size =
       extensions_.size() * sizeof(map<int, Extension>::value_type);
-  for (map<int, Extension>::const_iterator iter = extensions_.begin(),
+  for (ExtensionMap::const_iterator iter = extensions_.begin(),
        end = extensions_.end();
        iter != end;
        ++iter) {
@@ -386,31 +409,31 @@
 
 // The Serialize*ToArray methods are only needed in the heavy library, as
 // the lite library only generates SerializeWithCachedSizes.
-uint8* ExtensionSet::SerializeWithCachedSizesToArray(
+uint8* ExtensionSet::InternalSerializeWithCachedSizesToArray(
     int start_field_number, int end_field_number,
-    uint8* target) const {
-  map<int, Extension>::const_iterator iter;
+    bool deterministic, uint8* target) const {
+  ExtensionMap::const_iterator iter;
   for (iter = extensions_.lower_bound(start_field_number);
        iter != extensions_.end() && iter->first < end_field_number;
        ++iter) {
-    target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first,
-                                                               target);
+    target = iter->second.InternalSerializeFieldWithCachedSizesToArray(
+        iter->first, deterministic, target);
   }
   return target;
 }
 
-uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray(
-    uint8* target) const {
-  map<int, Extension>::const_iterator iter;
+uint8* ExtensionSet::InternalSerializeMessageSetWithCachedSizesToArray(
+    bool deterministic, uint8* target) const {
+  ExtensionMap::const_iterator iter;
   for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) {
-    target = iter->second.SerializeMessageSetItemWithCachedSizesToArray(
-        iter->first, target);
+    target = iter->second.InternalSerializeMessageSetItemWithCachedSizesToArray(
+        iter->first, deterministic, target);
   }
   return target;
 }
 
-uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray(
-    int number, uint8* target) const {
+uint8* ExtensionSet::Extension::InternalSerializeFieldWithCachedSizesToArray(
+    int number, bool deterministic, uint8* target) const {
   if (is_repeated) {
     if (is_packed) {
       if (cached_size == 0) return target;
@@ -477,6 +500,16 @@
         HANDLE_TYPE(  STRING,   String,  string);
         HANDLE_TYPE(   BYTES,    Bytes,  string);
         HANDLE_TYPE(    ENUM,     Enum,    enum);
+#undef HANDLE_TYPE
+#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE)                        \
+        case FieldDescriptor::TYPE_##UPPERCASE:                             \
+          for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) {  \
+            target = WireFormatLite::InternalWrite##CAMELCASE##ToArray(     \
+                      number, repeated_##LOWERCASE##_value->Get(i),         \
+                      deterministic, target);                               \
+          }                                                                 \
+          break
+
         HANDLE_TYPE(   GROUP,    Group, message);
         HANDLE_TYPE( MESSAGE,  Message, message);
 #undef HANDLE_TYPE
@@ -510,10 +543,11 @@
 #undef HANDLE_TYPE
       case FieldDescriptor::TYPE_MESSAGE:
         if (is_lazy) {
-          target = lazymessage_value->WriteMessageToArray(number, target);
+          target = lazymessage_value->InternalWriteMessageToArray(
+              number, deterministic, target);
         } else {
-          target = WireFormatLite::WriteMessageToArray(
-              number, *message_value, target);
+          target = WireFormatLite::InternalWriteMessageToArray(
+              number, *message_value, deterministic, target);
         }
         break;
     }
@@ -521,13 +555,14 @@
   return target;
 }
 
-uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray(
-    int number,
-    uint8* target) const {
+uint8*
+ExtensionSet::Extension::InternalSerializeMessageSetItemWithCachedSizesToArray(
+    int number, bool deterministic, uint8* target) const {
   if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) {
     // Not a valid MessageSet extension, but serialize it the normal way.
     GOOGLE_LOG(WARNING) << "Invalid message set extension.";
-    return SerializeFieldWithCachedSizesToArray(number, target);
+    return InternalSerializeFieldWithCachedSizesToArray(number, deterministic,
+                                                        target);
   }
 
   if (is_cleared) return target;
@@ -732,7 +767,7 @@
 
 void ExtensionSet::SerializeMessageSetWithCachedSizes(
     io::CodedOutputStream* output) const {
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     iter->second.SerializeMessageSetItemWithCachedSizes(iter->first, output);
   }
@@ -741,7 +776,7 @@
 int ExtensionSet::MessageSetByteSize() const {
   int total_size = 0;
 
-  for (map<int, Extension>::const_iterator iter = extensions_.begin();
+  for (ExtensionMap::const_iterator iter = extensions_.begin();
        iter != extensions_.end(); ++iter) {
     total_size += iter->second.MessageSetItemByteSize(iter->first);
   }
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index f40fcbc..688afed 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -205,6 +205,74 @@
   delete released_extension;
 }
 
+TEST(ExtensionSetTest, ArenaUnsafeArenaSetAllocatedAndRelease) {
+  ::google::protobuf::Arena arena;
+  unittest::TestAllExtensions* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  unittest::ForeignMessage extension;
+  message->UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension,
+      &extension);
+  // No copy when set.
+  unittest::ForeignMessage* mutable_extension =
+      message->MutableExtension(unittest::optional_foreign_message_extension);
+  EXPECT_EQ(&extension, mutable_extension);
+  // No copy when unsafe released.
+  unittest::ForeignMessage* released_extension =
+      message->UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(&extension, released_extension);
+  EXPECT_FALSE(message->HasExtension(
+      unittest::optional_foreign_message_extension));
+  // Set the ownership back and let the destructors run.  It should not take
+  // ownership, so this should not crash.
+  message->UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension,
+      &extension);
+}
+
+TEST(ExtensionSetTest, UnsafeArenaSetAllocatedAndRelease) {
+  unittest::TestAllExtensions message;
+  unittest::ForeignMessage* extension = new unittest::ForeignMessage();
+  message.UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension,
+      extension);
+  // No copy when set.
+  unittest::ForeignMessage* mutable_extension =
+      message.MutableExtension(unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, mutable_extension);
+  // No copy when unsafe released.
+  unittest::ForeignMessage* released_extension =
+      message.UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, released_extension);
+  EXPECT_FALSE(message.HasExtension(
+      unittest::optional_foreign_message_extension));
+  // Set the ownership back and let the destructors run.  It should take
+  // ownership, so this should not leak.
+  message.UnsafeArenaSetAllocatedExtension(
+      unittest::optional_foreign_message_extension,
+      extension);
+}
+
+TEST(ExtensionSetTest, ArenaUnsafeArenaReleaseOfHeapAlloc) {
+  ::google::protobuf::Arena arena;
+  unittest::TestAllExtensions* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  unittest::ForeignMessage* extension = new unittest::ForeignMessage;
+  message->SetAllocatedExtension(
+      unittest::optional_foreign_message_extension,
+      extension);
+  // The arena should maintain ownership of the heap allocated proto because we
+  // used UnsafeArenaReleaseExtension.  The leak checker will ensure this.
+  unittest::ForeignMessage* released_extension =
+      message->UnsafeArenaReleaseExtension(
+          unittest::optional_foreign_message_extension);
+  EXPECT_EQ(extension, released_extension);
+  EXPECT_FALSE(message->HasExtension(
+      unittest::optional_foreign_message_extension));
+}
+
 
 TEST(ExtensionSetTest, CopyFrom) {
   unittest::TestAllExtensions message1, message2;
diff --git a/src/google/protobuf/field_mask.pb.cc b/src/google/protobuf/field_mask.pb.cc
index c49ebce..d197b40 100644
--- a/src/google/protobuf/field_mask.pb.cc
+++ b/src/google/protobuf/field_mask.pb.cc
@@ -245,8 +245,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FieldMask)
 }
 
-::google::protobuf::uint8* FieldMask::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FieldMask::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FieldMask)
   // repeated string paths = 1;
   for (int i = 0; i < this->paths_size(); i++) {
diff --git a/src/google/protobuf/field_mask.pb.h b/src/google/protobuf/field_mask.pb.h
index f5e0b65..7a19c4a 100644
--- a/src/google/protobuf/field_mask.pb.h
+++ b/src/google/protobuf/field_mask.pb.h
@@ -41,7 +41,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FieldMask : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FieldMask) */ {
  public:
   FieldMask();
   virtual ~FieldMask();
@@ -75,7 +75,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/field_mask.proto b/src/google/protobuf/field_mask.proto
index 6af6dbe..c51de09 100644
--- a/src/google/protobuf/field_mask.proto
+++ b/src/google/protobuf/field_mask.proto
@@ -107,6 +107,58 @@
 // describe the updated values, the API ignores the values of all
 // fields not covered by the mask.
 //
+// If a repeated field is specified for an update operation, the existing
+// repeated values in the target resource will be overwritten by the new values.
+// Note that a repeated field is only allowed in the last position of a field
+// mask.
+//
+// If a sub-message is specified in the last position of the field mask for an
+// update operation, then the existing sub-message in the target resource is
+// overwritten. Given the target message:
+//
+//     f {
+//       b {
+//         d : 1
+//         x : 2
+//       }
+//       c : 1
+//     }
+//
+// And an update message:
+//
+//     f {
+//       b {
+//         d : 10
+//       }
+//     }
+//
+// then if the field mask is:
+//
+//  paths: "f.b"
+//
+// then the result will be:
+//
+//     f {
+//       b {
+//         d : 10
+//       }
+//       c : 1
+//     }
+//
+// However, if the update mask was:
+//
+//  paths: "f.b.d"
+//
+// then the result would be:
+//
+//     f {
+//       b {
+//         d : 10
+//         x : 2
+//       }
+//       c : 1
+//     }
+//
 // In order to reset a field's value to the default, the field must
 // be in the mask and set to the default value in the provided resource.
 // Hence, in order to reset all fields of a resource, provide a default
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc
index 2313181..347bac5 100644
--- a/src/google/protobuf/generated_message_reflection.cc
+++ b/src/google/protobuf/generated_message_reflection.cc
@@ -1579,7 +1579,8 @@
 
   if (field->is_extension()) {
     return static_cast<Message*>(
-        MutableExtensionSet(message)->ReleaseMessage(field, factory));
+        MutableExtensionSet(message)->UnsafeArenaReleaseMessage(field,
+                                                                factory));
   } else {
     ClearBit(message, field);
     if (field->containing_oneof()) {
diff --git a/src/google/protobuf/generated_message_reflection_unittest.cc b/src/google/protobuf/generated_message_reflection_unittest.cc
index 85ebdef..6276b66 100644
--- a/src/google/protobuf/generated_message_reflection_unittest.cc
+++ b/src/google/protobuf/generated_message_reflection_unittest.cc
@@ -795,6 +795,73 @@
   EXPECT_TRUE(released == NULL);
 }
 
+TEST(GeneratedMessageReflectionTest, ArenaReleaseMessageTest) {
+  ::google::protobuf::Arena arena;
+  unittest::TestAllTypes* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllTypes>(&arena);
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllTypes::descriptor());
+
+  // When nothing is set, we expect all released messages to be NULL.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-NULL releases.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  message->Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseExtensionMessageTest) {
+  ::google::protobuf::Arena arena;
+  unittest::TestAllExtensions* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestAllExtensions>(&arena);
+  TestUtil::ReflectionTester reflection_tester(
+      unittest::TestAllExtensions::descriptor());
+
+  // When nothing is set, we expect all released messages to be NULL.
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::IS_NULL);
+
+  // After fields are set we should get non-NULL releases.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::NOT_NULL);
+
+  // After Clear() we may or may not get a message from ReleaseMessage().
+  // This is implementation specific.
+  reflection_tester.SetAllFieldsViaReflection(message);
+  message->Clear();
+  reflection_tester.ExpectMessagesReleasedViaReflection(
+      message, TestUtil::ReflectionTester::CAN_BE_NULL);
+}
+
+TEST(GeneratedMessageReflectionTest, ArenaReleaseOneofMessageTest) {
+  ::google::protobuf::Arena arena;
+  unittest::TestOneof2* message =
+      ::google::protobuf::Arena::CreateMessage<unittest::TestOneof2>(&arena);
+  TestUtil::ReflectionTester::SetOneofViaReflection(message);
+
+  const Descriptor* descriptor = unittest::TestOneof2::descriptor();
+  const Reflection* reflection = message->GetReflection();
+  Message* released = reflection->ReleaseMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+
+  EXPECT_TRUE(released != NULL);
+  delete released;
+
+  released = reflection->ReleaseMessage(
+      message, descriptor->FindFieldByName("foo_lazy_message"));
+  EXPECT_TRUE(released == NULL);
+}
+
 #ifdef PROTOBUF_HAS_DEATH_TEST
 
 TEST(GeneratedMessageReflectionTest, UsageErrors) {
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index d8354c1..148eee0 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -376,6 +376,49 @@
   return std::make_pair(true, ptr);
 }
 
+GOOGLE_ATTRIBUTE_ALWAYS_INLINE::std::pair<bool, const uint8*> ReadVarint64FromArray(
+    const uint8* buffer, uint64* value);
+inline ::std::pair<bool, const uint8*> ReadVarint64FromArray(
+    const uint8* buffer, uint64* value) {
+  const uint8* ptr = buffer;
+  uint32 b;
+
+  // Splitting into 32-bit pieces gives better performance on 32-bit
+  // processors.
+  uint32 part0 = 0, part1 = 0, part2 = 0;
+
+  b = *(ptr++); part0  = b      ; if (!(b & 0x80)) goto done;
+  part0 -= 0x80;
+  b = *(ptr++); part0 += b <<  7; if (!(b & 0x80)) goto done;
+  part0 -= 0x80 << 7;
+  b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
+  part0 -= 0x80 << 14;
+  b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
+  part0 -= 0x80 << 21;
+  b = *(ptr++); part1  = b      ; if (!(b & 0x80)) goto done;
+  part1 -= 0x80;
+  b = *(ptr++); part1 += b <<  7; if (!(b & 0x80)) goto done;
+  part1 -= 0x80 << 7;
+  b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
+  part1 -= 0x80 << 14;
+  b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
+  part1 -= 0x80 << 21;
+  b = *(ptr++); part2  = b      ; if (!(b & 0x80)) goto done;
+  part2 -= 0x80;
+  b = *(ptr++); part2 += b <<  7; if (!(b & 0x80)) goto done;
+  // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
+
+  // We have overrun the maximum size of a varint (10 bytes).  Assume
+  // the data is corrupt.
+  return std::make_pair(false, ptr);
+
+ done:
+  *value = (static_cast<uint64>(part0)) |
+           (static_cast<uint64>(part1) << 28) |
+           (static_cast<uint64>(part2) << 56);
+  return std::make_pair(true, ptr);
+}
+
 }  // namespace
 
 bool CodedInputStream::ReadVarint32Slow(uint32* value) {
@@ -408,6 +451,32 @@
   }
 }
 
+int CodedInputStream::ReadVarintSizeAsIntSlow() {
+  // Directly invoke ReadVarint64Fallback, since we already tried to optimize
+  // for one-byte varints.
+  std::pair<uint64, bool> p = ReadVarint64Fallback();
+  if (!p.second || p.first > static_cast<uint64>(INT_MAX)) return -1;
+  return p.first;
+}
+
+int CodedInputStream::ReadVarintSizeAsIntFallback() {
+  if (BufferSize() >= kMaxVarintBytes ||
+      // Optimization:  We're also safe if the buffer is non-empty and it ends
+      // with a byte that would terminate a varint.
+      (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
+    uint64 temp;
+    ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first || temp > static_cast<uint64>(INT_MAX)) return -1;
+    buffer_ = p.second;
+    return temp;
+  } else {
+    // Really slow case: we will incur the cost of an extra function call here,
+    // but moving this out of line reduces the size of this function, which
+    // improves the common case. In micro benchmarks, this is worth about 10-15%
+    return ReadVarintSizeAsIntSlow();
+  }
+}
+
 uint32 CodedInputStream::ReadTagSlow() {
   if (buffer_ == buffer_end_) {
     // Call refresh.
@@ -499,47 +568,13 @@
       // Optimization:  We're also safe if the buffer is non-empty and it ends
       // with a byte that would terminate a varint.
       (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) {
-    // Fast path:  We have enough bytes left in the buffer to guarantee that
-    // this read won't cross the end, so we can skip the checks.
-
-    const uint8* ptr = buffer_;
-    uint32 b;
-
-    // Splitting into 32-bit pieces gives better performance on 32-bit
-    // processors.
-    uint32 part0 = 0, part1 = 0, part2 = 0;
-
-    b = *(ptr++); part0  = b      ; if (!(b & 0x80)) goto done;
-    part0 -= 0x80;
-    b = *(ptr++); part0 += b <<  7; if (!(b & 0x80)) goto done;
-    part0 -= 0x80 << 7;
-    b = *(ptr++); part0 += b << 14; if (!(b & 0x80)) goto done;
-    part0 -= 0x80 << 14;
-    b = *(ptr++); part0 += b << 21; if (!(b & 0x80)) goto done;
-    part0 -= 0x80 << 21;
-    b = *(ptr++); part1  = b      ; if (!(b & 0x80)) goto done;
-    part1 -= 0x80;
-    b = *(ptr++); part1 += b <<  7; if (!(b & 0x80)) goto done;
-    part1 -= 0x80 << 7;
-    b = *(ptr++); part1 += b << 14; if (!(b & 0x80)) goto done;
-    part1 -= 0x80 << 14;
-    b = *(ptr++); part1 += b << 21; if (!(b & 0x80)) goto done;
-    part1 -= 0x80 << 21;
-    b = *(ptr++); part2  = b      ; if (!(b & 0x80)) goto done;
-    part2 -= 0x80;
-    b = *(ptr++); part2 += b <<  7; if (!(b & 0x80)) goto done;
-    // "part2 -= 0x80 << 7" is irrelevant because (0x80 << 7) << 56 is 0.
-
-    // We have overrun the maximum size of a varint (10 bytes).  The data
-    // must be corrupt.
-    return std::make_pair(0, false);
-
-   done:
-    Advance(ptr - buffer_);
-    return std::make_pair((static_cast<uint64>(part0)) |
-                              (static_cast<uint64>(part1) << 28) |
-                              (static_cast<uint64>(part2) << 56),
-                          true);
+    uint64 temp;
+    ::std::pair<bool, const uint8*> p = ReadVarint64FromArray(buffer_, &temp);
+    if (!p.first) {
+      return std::make_pair(0, false);
+    }
+    buffer_ = p.second;
+    return std::make_pair(temp, true);
   } else {
     uint64 temp;
     bool success = ReadVarint64Slow(&temp);
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index c81a33a..eb32074 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -237,6 +237,17 @@
   // Read an unsigned integer with Varint encoding.
   bool ReadVarint64(uint64* value);
 
+  // Reads a varint off the wire into an "int". This should be used for reading
+  // sizes off the wire (sizes of strings, submessages, bytes fields, etc).
+  //
+  // The value from the wire is interpreted as unsigned.  If its value exceeds
+  // the representable value of an integer on this platform, instead of
+  // truncating we return false. Truncating (as performed by ReadVarint32()
+  // above) is an acceptable approach for fields representing an integer, but
+  // when we are parsing a size from the wire, truncating the value would result
+  // in us misparsing the payload.
+  bool ReadVarintSizeAsInt(int* value);
+
   // Read a tag.  This calls ReadVarint32() and returns the result, or returns
   // zero (which is not a valid tag) if ReadVarint32() fails.  Also, it updates
   // the last tag value, which can be checked with LastTagWas().
@@ -594,9 +605,11 @@
   // if it fails and the uint32 it read otherwise.  The latter has a bool
   // indicating success or failure as part of its return type.
   int64 ReadVarint32Fallback(uint32 first_byte_or_zero);
+  int ReadVarintSizeAsIntFallback();
   std::pair<uint64, bool> ReadVarint64Fallback();
   bool ReadVarint32Slow(uint32* value);
   bool ReadVarint64Slow(uint64* value);
+  int ReadVarintSizeAsIntSlow();
   bool ReadLittleEndian32Fallback(uint32* value);
   bool ReadLittleEndian64Fallback(uint64* value);
   // Fallback/slow methods for reading tags. These do not update last_tag_,
@@ -868,6 +881,19 @@
   return p.second;
 }
 
+inline bool CodedInputStream::ReadVarintSizeAsInt(int* value) {
+  if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_)) {
+    int v = *buffer_;
+    if (v < 0x80) {
+      *value = v;
+      Advance(1);
+      return true;
+    }
+  }
+  *value = ReadVarintSizeAsIntFallback();
+  return *value >= 0;
+}
+
 // static
 inline const uint8* CodedInputStream::ReadLittleEndian32FromArray(
     const uint8* buffer,
diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h
index 2ba8455..e78e2ef 100644
--- a/src/google/protobuf/io/printer.h
+++ b/src/google/protobuf/io/printer.h
@@ -200,6 +200,26 @@
     Annotate(begin_varname, end_varname, descriptor->file()->name(), path);
   }
 
+  // Link a subsitution variable emitted by the last call to Print to the file
+  // with path file_name.
+  void Annotate(const char* varname, const string& file_name) {
+    Annotate(varname, varname, file_name);
+  }
+
+  // Link the output range defined by the substitution variables as emitted by
+  // the last call to Print to the file with path file_name. The range begins
+  // at begin_varname's value and ends after the last character of the value
+  // substituted for end_varname.
+  void Annotate(const char* begin_varname, const char* end_varname,
+                const string& file_name) {
+    if (annotation_collector_ == NULL) {
+      // Annotations aren't turned on for this Printer.
+      return;
+    }
+    vector<int> empty_path;
+    Annotate(begin_varname, end_varname, file_name, empty_path);
+  }
+
   // Print some text after applying variable substitutions.  If a particular
   // variable in the text is not defined, this will crash.  Variables to be
   // substituted are identified by their names surrounded by delimiter
diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
index 9d81ccf..e4d6a02 100644
--- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h
+++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h
@@ -53,7 +53,6 @@
 #include <google/protobuf/io/zero_copy_stream.h>
 #include <google/protobuf/stubs/callback.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/stl_util.h>
 
 
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h
index 31593c1..42bcfd9 100644
--- a/src/google/protobuf/map.h
+++ b/src/google/protobuf/map.h
@@ -520,7 +520,7 @@
   typedef size_t size_type;
   typedef hash<Key> hasher;
 
-  Map(bool old_style = true)
+  explicit Map(bool old_style = true)
       : arena_(NULL),
         default_enum_value_(0),
         old_style_(old_style) {
@@ -1621,6 +1621,24 @@
     return *this;
   }
 
+  void swap(Map& other) {
+    if (arena_ == other.arena_ && old_style_ == other.old_style_) {
+      std::swap(default_enum_value_, other.default_enum_value_);
+      if (old_style_) {
+        std::swap(deprecated_elements_, other.deprecated_elements_);
+      } else {
+        std::swap(elements_, other.elements_);
+      }
+    } else {
+      // TODO(zuguang): optimize this. The temporary copy can be allocated
+      // in the same arena as the other message, and the "other = copy" can
+      // be replaced with the fast-path swap above.
+      Map copy = *this;
+      *this = other;
+      other = copy;
+    }
+  }
+
   // Access to hasher.  Currently this returns a copy, but it may
   // be modified to return a const reference in the future.
   hasher hash_function() const {
diff --git a/src/google/protobuf/map_entry.h b/src/google/protobuf/map_entry.h
index 987c4e2..801e752 100644
--- a/src/google/protobuf/map_entry.h
+++ b/src/google/protobuf/map_entry.h
@@ -166,8 +166,10 @@
     entry_lite_.SerializeWithCachedSizes(output);
   }
 
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
-    return entry_lite_.SerializeWithCachedSizesToArray(output);
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+                                                   ::google::protobuf::uint8* output) const {
+    return entry_lite_.InternalSerializeWithCachedSizesToArray(deterministic,
+                                                               output);
   }
 
   int GetCachedSize() const {
diff --git a/src/google/protobuf/map_entry_lite.h b/src/google/protobuf/map_entry_lite.h
index 7cdf1b9..23ac7b8 100644
--- a/src/google/protobuf/map_entry_lite.h
+++ b/src/google/protobuf/map_entry_lite.h
@@ -31,6 +31,7 @@
 #ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
 #define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
 
+#include <assert.h>
 #include <google/protobuf/map_type_handler.h>
 #include <google/protobuf/wire_format_lite_inl.h>
 
@@ -54,6 +55,38 @@
 namespace protobuf {
 namespace internal {
 
+// MoveHelper::Move is used to set *dest.  It copies *src, or moves it (in
+// the C++11 sense), or swaps it. *src is left in a sane state for
+// subsequent destruction, but shouldn't be used for anything.
+template <bool is_enum, bool is_message, bool is_stringlike, typename T>
+struct MoveHelper {  // primitives
+  static void Move(T* src, T* dest) { *dest = *src; }
+};
+
+template <bool is_message, bool is_stringlike, typename T>
+struct MoveHelper<true, is_message, is_stringlike, T> {  // enums
+  static void Move(T* src, T* dest) { *dest = *src; }
+  // T is an enum here, so allow conversions to and from int.
+  static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
+  static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
+};
+
+template <bool is_stringlike, typename T>
+struct MoveHelper<false, true, is_stringlike, T> {  // messages
+  static void Move(T* src, T* dest) { dest->Swap(src); }
+};
+
+template <typename T>
+struct MoveHelper<false, false, true, T> {  // strings and similar
+  static void Move(T* src, T* dest) {
+#if __cplusplus >= 201103L
+    *dest = std::move(*src);
+#else
+    dest->swap(*src);
+#endif
+  }
+};
+
 // MapEntryLite is used to implement parsing and serialization of map for lite
 // runtime.
 template <typename Key, typename Value,
@@ -180,11 +213,17 @@
     ValueTypeHandler::Write(kValueFieldNumber, value(), output);
   }
 
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
-    output = KeyTypeHandler::WriteToArray(kKeyFieldNumber, key(), output);
-    output = ValueTypeHandler::WriteToArray(kValueFieldNumber, value(), output);
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+                                                   ::google::protobuf::uint8* output) const {
+    output = KeyTypeHandler::InternalWriteToArray(kKeyFieldNumber, key(),
+                                                  deterministic, output);
+    output = ValueTypeHandler::InternalWriteToArray(kValueFieldNumber, value(),
+                                                    deterministic, output);
     return output;
   }
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
 
   int GetCachedSize() const {
     int size = 0;
@@ -271,6 +310,108 @@
         arena, key, value);
   }
 
+  // Parsing using MergePartialFromCodedStream, above, is not as
+  // efficient as it could be.  This helper class provides a speedier way.
+  template <typename MapField, typename Map>
+  class Parser {
+   public:
+    explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
+
+    // This does what the typical MergePartialFromCodedStream() is expected to
+    // do, with the additional side-effect that if successful (i.e., if true is
+    // going to be its return value) it inserts the key-value pair into map_.
+    bool MergePartialFromCodedStream(::google::protobuf::io::CodedInputStream* input) {
+      // Look for the expected thing: a key and then a value.  If it fails,
+      // invoke the enclosing class's MergePartialFromCodedStream, or return
+      // false if that would be pointless.
+      if (input->ExpectTag(kKeyTag)) {
+        if (!KeyTypeHandler::Read(input, &key_)) {
+          return false;
+        }
+        // Peek at the next byte to see if it is kValueTag.  If not, bail out.
+        const void* data;
+        int size;
+        input->GetDirectBufferPointerInline(&data, &size);
+        // We could use memcmp here, but we don't bother. The tag is one byte.
+        assert(kTagSize == 1);
+        if (size > 0 && *reinterpret_cast<const char*>(data) == kValueTag) {
+          typename Map::size_type size = map_->size();
+          value_ptr_ = &(*map_)[key_];
+          if (GOOGLE_PREDICT_TRUE(size != map_->size())) {
+            // We created a new key-value pair.  Fill in the value.
+            typedef
+                typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type T;
+            input->Skip(kTagSize);  // Skip kValueTag.
+            if (!ValueTypeHandler::Read(input,
+                                        reinterpret_cast<T>(value_ptr_))) {
+              map_->erase(key_);  // Failure! Undo insertion.
+              return false;
+            }
+            if (input->ExpectAtEnd()) return true;
+            return ReadBeyondKeyValuePair(input);
+          }
+        }
+      } else {
+        key_ = Key();
+      }
+
+      entry_.reset(mf_->NewEntry());
+      *entry_->mutable_key() = key_;
+      if (!entry_->MergePartialFromCodedStream(input)) return false;
+      return UseKeyAndValueFromEntry();
+    }
+
+    const Key& key() const { return key_; }
+    const Value& value() const { return *value_ptr_; }
+
+   private:
+    bool UseKeyAndValueFromEntry() GOOGLE_ATTRIBUTE_COLD {
+      // Update key_ in case we need it later (because key() is called).
+      // This is potentially inefficient, especially if the key is
+      // expensive to copy (e.g., a long string), but this is a cold
+      // path, so it's not a big deal.
+      key_ = entry_->key();
+      value_ptr_ = &(*map_)[key_];
+      MoveHelper<ValueTypeHandler::kIsEnum,
+                 ValueTypeHandler::kIsMessage,
+                 ValueTypeHandler::kWireType ==
+                 WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                 Value>::Move(entry_->mutable_value(), value_ptr_);
+      if (entry_->GetArena() != NULL) entry_.release();
+      return true;
+    }
+
+    // After reading a key and value successfully, and inserting that data
+    // into map_, we are not at the end of the input.  This is unusual, but
+    // allowed by the spec.
+    bool ReadBeyondKeyValuePair(::google::protobuf::io::CodedInputStream* input)
+        GOOGLE_ATTRIBUTE_COLD {
+      typedef MoveHelper<KeyTypeHandler::kIsEnum,
+                         KeyTypeHandler::kIsMessage,
+                         KeyTypeHandler::kWireType ==
+                         WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                         Key> KeyMover;
+      typedef MoveHelper<ValueTypeHandler::kIsEnum,
+                         ValueTypeHandler::kIsMessage,
+                         ValueTypeHandler::kWireType ==
+                         WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
+                         Value> ValueMover;
+      entry_.reset(mf_->NewEntry());
+      ValueMover::Move(value_ptr_, entry_->mutable_value());
+      map_->erase(key_);
+      KeyMover::Move(&key_, entry_->mutable_key());
+      if (!entry_->MergePartialFromCodedStream(input)) return false;
+      return UseKeyAndValueFromEntry();
+    }
+
+    MapField* const mf_;
+    Map* const map_;
+    Key key_;
+    Value* value_ptr_;
+    // On the fast path entry_ is not used.
+    google::protobuf::scoped_ptr<MapEntryLite> entry_;
+  };
+
  protected:
   void set_has_key() { _has_bits_[0] |= 0x00000001u; }
   bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc
index 223d42f..dd5061c 100644
--- a/src/google/protobuf/map_field_test.cc
+++ b/src/google/protobuf/map_field_test.cc
@@ -47,8 +47,8 @@
 #include <google/protobuf/repeated_field.h>
 #include <google/protobuf/wire_format_lite_inl.h>
 #include <gtest/gtest.h>
-
 namespace google {
+
 namespace protobuf {
 
 namespace internal {
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc
index 9d4d6c1..dccb31c 100644
--- a/src/google/protobuf/map_test.cc
+++ b/src/google/protobuf/map_test.cc
@@ -50,7 +50,6 @@
 #include <google/protobuf/stubs/casts.h>
 #include <google/protobuf/stubs/logging.h>
 #include <google/protobuf/stubs/common.h>
-#include <google/protobuf/stubs/scoped_ptr.h>
 #include <google/protobuf/stubs/stringprintf.h>
 #include <google/protobuf/testing/file.h>
 #include <google/protobuf/arena_test_util.h>
@@ -77,6 +76,7 @@
 #include <google/protobuf/util/time_util.h>
 #include <google/protobuf/stubs/strutil.h>
 #include <google/protobuf/stubs/substitute.h>
+#include <gmock/gmock.h>
 #include <google/protobuf/testing/googletest.h>
 #include <gtest/gtest.h>
 
@@ -915,6 +915,55 @@
   EXPECT_EQ(101, std_vec[0].second);
 }
 
+TEST_P(MapImplTest, SwapSameStyle) {
+  Map<int32, int32> another(GetParam());  // same old_style_ value
+  map_[9398] = 41999;
+  another[9398] = 41999;
+  another[8070] = 42056;
+  another.swap(map_);
+  EXPECT_THAT(another, testing::UnorderedElementsAre(
+      testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(
+      testing::Pair(8070, 42056),
+      testing::Pair(9398, 41999)));
+}
+
+TEST_P(MapImplTest, SwapDifferentStyle) {
+  Map<int32, int32> another(!GetParam());  // different old_style_ value
+  map_[9398] = 41999;
+  another[9398] = 41999;
+  another[8070] = 42056;
+  another.swap(map_);
+  EXPECT_THAT(another, testing::UnorderedElementsAre(
+      testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(
+      testing::Pair(8070, 42056),
+      testing::Pair(9398, 41999)));
+}
+
+TEST_P(MapImplTest, SwapArena) {
+  Arena arena1, arena2;
+  Map<int32, int32> m1(&arena1, false);
+  Map<int32, int32> m2(&arena2, false);
+  map_[9398] = 41999;
+  m1[9398] = 41999;
+  m1[8070] = 42056;
+  m2[10244] = 10247;
+  m2[8070] = 42056;
+  m1.swap(map_);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(
+      testing::Pair(9398, 41999)));
+  EXPECT_THAT(map_, testing::UnorderedElementsAre(
+      testing::Pair(8070, 42056),
+      testing::Pair(9398, 41999)));
+  m2.swap(m1);
+  EXPECT_THAT(m1, testing::UnorderedElementsAre(
+      testing::Pair(8070, 42056),
+      testing::Pair(10244, 10247)));
+  EXPECT_THAT(m2, testing::UnorderedElementsAre(
+      testing::Pair(9398, 41999)));
+}
+
 INSTANTIATE_TEST_CASE_P(BoolSequence, MapImplTest, testing::Bool());
 
 // Map Field Reflection Test ========================================
@@ -2106,6 +2155,76 @@
   EXPECT_TRUE(message.ParseFromString(data));
   EXPECT_EQ(1, message.map_int32_int32().size());
   EXPECT_EQ(1, message.map_int32_int32().at(2));
+
+  // A similar test, but with a map from int to a message type.
+  // Again, we want to be sure that the "second one wins" when
+  // there are two separate entries with the same key.
+  const int key = 99;
+  unittest::TestRequiredMessageMap map_message;
+  unittest::TestRequired with_dummy4;
+  with_dummy4.set_a(0);
+  with_dummy4.set_b(0);
+  with_dummy4.set_c(0);
+  with_dummy4.set_dummy4(11);
+  (*map_message.mutable_map_field())[key] = with_dummy4;
+  string s = map_message.SerializeAsString();
+  unittest::TestRequired with_dummy5;
+  with_dummy5.set_a(0);
+  with_dummy5.set_b(0);
+  with_dummy5.set_c(0);
+  with_dummy5.set_dummy5(12);
+  (*map_message.mutable_map_field())[key] = with_dummy5;
+  string both = s + map_message.SerializeAsString();
+  // We don't expect a merge now.  The "second one wins."
+  ASSERT_TRUE(map_message.ParseFromString(both));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.c());
+  EXPECT_FALSE(map_message.map_field().find(key)->second.has_dummy4());
+  ASSERT_TRUE(map_message.map_field().find(key)->second.has_dummy5());
+  EXPECT_EQ(12, map_message.map_field().find(key)->second.dummy5());
+}
+
+// Exhaustive combinations of keys, values, and junk in any order.
+// This re-tests some of the things tested above, but if it fails
+// it's more work to determine what went wrong, so it isn't necessarily
+// bad that we have the simpler tests too.
+TEST(GeneratedMapFieldTest, KeysValuesUnknownsWireFormat) {
+  unittest::TestMap message;
+  const int kMaxNumKeysAndValuesAndJunk = 4;
+  const char kKeyTag = 0x08;
+  const char kValueTag = 0x10;
+  const char kJunkTag = 0x20;
+  for (int items = 0; items <= kMaxNumKeysAndValuesAndJunk; items++) {
+    string data = "\x0A";
+    // Encode length of what will follow.
+    data.push_back(items * 2);
+    static const int kBitsOfIPerItem = 4;
+    static const int mask = (1 << kBitsOfIPerItem) - 1;
+    // Each iteration of the following is a test.  It uses i as bit vector
+    // encoding the keys and values to put in the wire format.
+    for (int i = 0; i < (1 << (items * kBitsOfIPerItem)); i++) {
+      string wire_format = data;
+      int expected_key = 0;
+      int expected_value = 0;
+      for (int k = i, j = 0; j < items; j++, k >>= kBitsOfIPerItem) {
+        bool is_key = k & 0x1;
+        bool is_value = !is_key && (k & 0x2);
+        wire_format.push_back(is_key ? kKeyTag :
+                              is_value ? kValueTag : kJunkTag);
+        char c = static_cast<char>(k & mask) >> 2;  // One char after the tag.
+        wire_format.push_back(c);
+        if (is_key) expected_key = static_cast<int>(c);
+        if (is_value) expected_value = static_cast<int>(c);
+        ASSERT_TRUE(message.ParseFromString(wire_format));
+        ASSERT_EQ(1, message.map_int32_int32().size());
+        ASSERT_EQ(expected_key, message.map_int32_int32().begin()->first);
+        ASSERT_EQ(expected_value, message.map_int32_int32().begin()->second);
+      }
+    }
+  }
 }
 
 TEST(GeneratedMapFieldTest, DuplicatedValueWireFormat) {
@@ -2189,6 +2308,74 @@
   EXPECT_TRUE(map_message.IsInitialized());
 }
 
+TEST(GeneratedMapFieldTest, MessagesMustMerge) {
+  unittest::TestRequiredMessageMap map_message;
+  unittest::TestRequired with_dummy4;
+  with_dummy4.set_a(97);
+  with_dummy4.set_b(0);
+  with_dummy4.set_c(0);
+  with_dummy4.set_dummy4(98);
+
+  EXPECT_TRUE(with_dummy4.IsInitialized());
+  (*map_message.mutable_map_field())[0] = with_dummy4;
+  EXPECT_TRUE(map_message.IsInitialized());
+  string s = map_message.SerializeAsString();
+
+  // Modify s so that there are two values in the entry for key 0.
+  // The first will have no value for c.  The second will have no value for a.
+  // Those are required fields.  Also, make some other little changes, to
+  // ensure we are merging the two values (because they're messages).
+  ASSERT_EQ(s.size() - 2, s[1]);  // encoding of the length of what follows
+  string encoded_val(s.data() + 4, s.data() + s.size());
+  // In s, change the encoding of c to an encoding of dummy32.
+  s[s.size() - 3] -= 8;
+  // Make encoded_val slightly different from what's in s.
+  encoded_val[encoded_val.size() - 1] += 33;  // Encode c = 33.
+  for (int i = 0; i < encoded_val.size(); i++) {
+    if (encoded_val[i] == 97) {
+      // Encode b = 91 instead of a = 97.  But this won't matter, because
+      // we also encode b = 0 right after this.  The point is to leave out
+      // a required field, and make sure the parser doesn't complain, because
+      // every required field is set after the merge of the two values.
+      encoded_val[i - 1] += 16;
+      encoded_val[i] = 91;
+    } else if (encoded_val[i] == 98) {
+      // Encode dummy5 = 99 instead of dummy4 = 98.
+      encoded_val[i - 1] += 8;  // The tag for dummy5 is 8 more.
+      encoded_val[i]++;
+      break;
+    }
+  }
+
+  s += encoded_val;            // Add the second message.
+  s[1] += encoded_val.size();  // Adjust encoded size.
+
+  // Test key then value then value.
+  int key = 0;
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+
+  // Test key then value then value then key.
+  s.push_back(s[2]);       // Copy the key's tag.
+  key = 19;
+  s.push_back(key);        // Second key is 19 instead of 0.
+  s[1] += 2;               // Adjust encoded size.
+  ASSERT_TRUE(map_message.ParseFromString(s));
+  ASSERT_EQ(1, map_message.map_field().size());
+  ASSERT_EQ(1, map_message.map_field().count(key));
+  EXPECT_EQ(97, map_message.map_field().find(key)->second.a());
+  EXPECT_EQ(0, map_message.map_field().find(key)->second.b());
+  EXPECT_EQ(33, map_message.map_field().find(key)->second.c());
+  EXPECT_EQ(98, map_message.map_field().find(key)->second.dummy4());
+  EXPECT_EQ(99, map_message.map_field().find(key)->second.dummy5());
+}
+
 // Generated Message Reflection Test ================================
 
 TEST(GeneratedMapFieldReflectionTest, SpaceUsed) {
@@ -2783,6 +2970,21 @@
   ASSERT_FALSE(message == NULL);
 }
 
+TEST(ArenaTest, IsInitialized) {
+  // Allocate a large initial polluted block.
+  std::vector<char> arena_block(128 * 1024);
+  std::fill(arena_block.begin(), arena_block.end(), '\xff');
+
+  ArenaOptions options;
+  options.initial_block = &arena_block[0];
+  options.initial_block_size = arena_block.size();
+  Arena arena(options);
+
+  unittest::TestArenaMap* message =
+      Arena::CreateMessage<unittest::TestArenaMap>(&arena);
+  EXPECT_EQ(0, (*message->mutable_map_int32_int32())[0]);
+}
+
 }  // namespace internal
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/map_type_handler.h b/src/google/protobuf/map_type_handler.h
index f8ad758..74e8bb5 100644
--- a/src/google/protobuf/map_type_handler.h
+++ b/src/google/protobuf/map_type_handler.h
@@ -164,6 +164,9 @@
                           MapEntryAccessorType* value);
   static inline void Write(int field, const MapEntryAccessorType& value,
                            io::CodedOutputStream* output);
+  static inline uint8* InternalWriteToArray(int field,
+                                            const MapEntryAccessorType& value,
+                                            bool deterministic, uint8* output);
   static inline uint8* WriteToArray(int field,
                                     const MapEntryAccessorType& value,
                                     uint8* output);
@@ -220,9 +223,16 @@
                             MapEntryAccessorType* value);                     \
     static inline void Write(int field, const MapEntryAccessorType& value,    \
                              io::CodedOutputStream* output);                  \
+    static inline uint8* InternalWriteToArray(                                \
+        int field,                                                            \
+        const MapEntryAccessorType& value,                                    \
+        bool deterministic,                                                   \
+        uint8* output);                                                       \
     static inline uint8* WriteToArray(int field,                              \
                                       const MapEntryAccessorType& value,      \
-                                      uint8* output);                         \
+                                      uint8* output) {                        \
+      return InternalWriteToArray(field, value, false, output);               \
+    }                                                                         \
     static inline const MapEntryAccessorType& GetExternalReference(           \
         const TypeOnMemory& value);                                           \
     static inline void DeleteNoArena(const TypeOnMemory& x);                  \
@@ -362,9 +372,11 @@
 
 template <typename Type>
 inline uint8*
-MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::WriteToArray(
-    int field, const MapEntryAccessorType& value, uint8* output) {
-  return WireFormatLite::WriteMessageToArray(field, value, output);
+MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::InternalWriteToArray(
+    int field, const MapEntryAccessorType& value, bool deterministic,
+    uint8* output) {
+  return WireFormatLite::InternalWriteMessageToArray(field, value,
+                                                     deterministic, output);
 }
 
 #define WRITE_METHOD(FieldType, DeclaredType)                                  \
@@ -376,8 +388,9 @@
   }                                                                            \
   template <typename Type>                                                     \
   inline uint8*                                                                \
-  MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::WriteToArray(        \
-      int field, const MapEntryAccessorType& value, uint8* output) {           \
+  MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
+                 Type>::InternalWriteToArray(                                  \
+      int field, const MapEntryAccessorType& value, bool, uint8* output) {     \
     return WireFormatLite::Write##DeclaredType##ToArray(field, value, output); \
   }
 
@@ -543,7 +556,7 @@
                                        Type>::MapEntryAccessorType&            \
   MapTypeHandler<WireFormatLite::TYPE_##FieldType,                             \
                  Type>::GetExternalReference(const TypeOnMemory& value) {      \
-    return value.Get(&::google::protobuf::internal::GetEmptyString());                   \
+    return value.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());      \
   }                                                                            \
   template <typename Type>                                                     \
   inline int                                                                   \
@@ -564,7 +577,8 @@
   template <typename Type>                                                     \
   inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear(   \
       TypeOnMemory* value, Arena* arena) {                                     \
-    value->ClearToEmpty(&::google::protobuf::internal::GetEmptyString(), arena);         \
+    value->ClearToEmpty(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),    \
+                        arena);                                                \
   }                                                                            \
   template <typename Type>                                                     \
   inline void                                                                  \
@@ -577,12 +591,12 @@
   template <typename Type>                                                     \
   inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge(   \
       const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) {      \
-    to->Set(&::google::protobuf::internal::GetEmptyString(), from, arena);               \
+    to->Set(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from, arena);  \
   }                                                                            \
   template <typename Type>                                                     \
   void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena(  \
       TypeOnMemory& value) {                                                   \
-    value.DestroyNoArena(&::google::protobuf::internal::GetEmptyString());               \
+    value.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited());  \
   }                                                                            \
   template <typename Type>                                                     \
   inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
@@ -591,7 +605,8 @@
   inline void                                                                  \
   MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Initialize(          \
       TypeOnMemory* value, Arena* arena) {                                     \
-    value->UnsafeSetDefault(&::google::protobuf::internal::GetEmptyString());            \
+    value->UnsafeSetDefault(                                                   \
+        &::google::protobuf::internal::GetEmptyStringAlreadyInited());                   \
   }                                                                            \
   template <typename Type>                                                     \
   inline void                                                                  \
@@ -606,7 +621,8 @@
                                  Type>::MapEntryAccessorType*                  \
   MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::EnsureMutable(       \
       TypeOnMemory* value, Arena* arena) {                                     \
-    return value->Mutable(&::google::protobuf::internal::GetEmptyString(), arena);       \
+    return value->Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(),  \
+                          arena);                                              \
   }                                                                            \
   template <typename Type>                                                     \
   inline const typename MapTypeHandler<WireFormatLite::TYPE_##FieldType,       \
@@ -615,7 +631,7 @@
                  Type>::DefaultIfNotInitialized(const TypeOnMemory& value,     \
                                                 const TypeOnMemory&            \
                                                     default_value) {           \
-    return value.Get(&::google::protobuf::internal::GetEmptyString());                   \
+    return value.Get(&::google::protobuf::internal::GetEmptyStringAlreadyInited());      \
   }                                                                            \
   template <typename Type>                                                     \
   inline bool MapTypeHandler<WireFormatLite::TYPE_##FieldType,                 \
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index a4d9277..dcdffe1 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -585,8 +585,8 @@
   // If you have no idea what that meant, then you probably don't need to worry
   // about it (don't provide a MessageFactory).  WARNING:  If the
   // FieldDescriptor is for a compiled-in extension, then
-  // factory->GetPrototype(field->message_type() MUST return an instance of the
-  // compiled-in class for this type, NOT DynamicMessage.
+  // factory->GetPrototype(field->message_type()) MUST return an instance of
+  // the compiled-in class for this type, NOT DynamicMessage.
   virtual Message* MutableMessage(Message* message,
                                   const FieldDescriptor* field,
                                   MessageFactory* factory = NULL) const = 0;
diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc
index 9d7b64f..3913be1 100644
--- a/src/google/protobuf/message_lite.cc
+++ b/src/google/protobuf/message_lite.cc
@@ -221,7 +221,8 @@
 
 // ===================================================================
 
-uint8* MessageLite::SerializeWithCachedSizesToArray(uint8* target) const {
+uint8* MessageLite::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, uint8* target) const {
   // We only optimize this when using optimize_for = SPEED.  In other cases
   // we just use the CodedOutputStream path.
   int size = GetCachedSize();
diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h
index 4c16f4c..f606aee 100644
--- a/src/google/protobuf/message_lite.h
+++ b/src/google/protobuf/message_lite.h
@@ -51,6 +51,9 @@
   class ZeroCopyInputStream;
   class ZeroCopyOutputStream;
 }
+namespace internal {
+  class WireFormatLite;
+}
 
 // Interface to light weight protocol messages.
 //
@@ -249,10 +252,11 @@
   virtual void SerializeWithCachedSizes(
       io::CodedOutputStream* output) const = 0;
 
-  // Like SerializeWithCachedSizes, but writes directly to *target, returning
-  // a pointer to the byte immediately after the last byte written.  "target"
-  // must point at a byte array of at least ByteSize() bytes.
-  virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const;
+  // A version of SerializeWithCachedSizesToArray, below, that does
+  // not guarantee deterministic serialization.
+  virtual uint8* SerializeWithCachedSizesToArray(uint8* target) const {
+    return InternalSerializeWithCachedSizesToArray(false, target);
+  }
 
   // Returns the result of the last call to ByteSize().  An embedded message's
   // size is needed both to serialize it (because embedded messages are
@@ -267,7 +271,22 @@
   // method.)
   virtual int GetCachedSize() const = 0;
 
+  // Functions below here are not part of the public interface.  It isn't
+  // enforced, but they should be treated as private, and will be private
+  // at some future time.  Unfortunately the implementation of the "friend"
+  // keyword in GCC is broken at the moment, but we expect it will be fixed.
+
+  // Like SerializeWithCachedSizes, but writes directly to *target, returning
+  // a pointer to the byte immediately after the last byte written.  "target"
+  // must point at a byte array of at least ByteSize() bytes.  If deterministic
+  // is true then we use deterministic serialization, e.g., map keys are sorted.
+  // FOR INTERNAL USE ONLY!
+  virtual uint8* InternalSerializeWithCachedSizesToArray(bool deterministic,
+                                                         uint8* target) const;
+
  private:
+  friend class internal::WireFormatLite;
+
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageLite);
 };
 
diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h
index 1961bc4..38358db 100644
--- a/src/google/protobuf/repeated_field.h
+++ b/src/google/protobuf/repeated_field.h
@@ -564,12 +564,16 @@
     return ::google::protobuf::Arena::CreateMaybeMessage<Type>(
         arena, static_cast<GenericType*>(0));
   }
-  // We force NewFromPrototype() and Delete() to be non-inline to reduce code
-  // size: else, several other methods get inlined copies of message types'
-  // constructors and destructors.
+  // We force NewFromPrototype() to be non-inline to reduce code size:
+  // else, several other methods get inlined copies of message types'
+  // constructors.
   GOOGLE_ATTRIBUTE_NOINLINE static GenericType* NewFromPrototype(
       const GenericType* prototype, ::google::protobuf::Arena* arena = NULL);
-  GOOGLE_ATTRIBUTE_NOINLINE static void Delete(GenericType* value, Arena* arena);
+  static inline void Delete(GenericType* value, Arena* arena) {
+    if (arena == NULL) {
+      delete value;
+    }
+  }
   static inline ::google::protobuf::Arena* GetArena(GenericType* value) {
     return ::google::protobuf::Arena::GetArena<Type>(value);
   }
@@ -594,12 +598,6 @@
   return New(arena);
 }
 template <typename GenericType>
-void GenericTypeHandler<GenericType>::Delete(GenericType* value, Arena* arena) {
-  if (arena == NULL) {
-    delete value;
-  }
-}
-template <typename GenericType>
 void GenericTypeHandler<GenericType>::Merge(const GenericType& from,
                                             GenericType* to) {
   to->MergeFrom(from);
@@ -1359,13 +1357,13 @@
 
 template <typename TypeHandler>
 void RepeatedPtrFieldBase::Destroy() {
-  if (rep_ != NULL) {
-    for (int i = 0; i < rep_->allocated_size; i++) {
-      TypeHandler::Delete(cast<TypeHandler>(rep_->elements[i]), arena_);
+  if (rep_ != NULL && arena_ == NULL) {
+    int n = rep_->allocated_size;
+    void* const* elements = rep_->elements;
+    for (int i = 0; i < n; i++) {
+      TypeHandler::Delete(cast<TypeHandler>(elements[i]), NULL);
     }
-    if (arena_ == NULL) {
-      delete [] reinterpret_cast<char*>(rep_);
-    }
+    delete[] reinterpret_cast<char*>(rep_);
   }
   rep_ = NULL;
 }
diff --git a/src/google/protobuf/source_context.pb.cc b/src/google/protobuf/source_context.pb.cc
index c67cd10..4d8e77c 100644
--- a/src/google/protobuf/source_context.pb.cc
+++ b/src/google/protobuf/source_context.pb.cc
@@ -244,8 +244,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.SourceContext)
 }
 
-::google::protobuf::uint8* SourceContext::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* SourceContext::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.SourceContext)
   // optional string file_name = 1;
   if (this->file_name().size() > 0) {
diff --git a/src/google/protobuf/source_context.pb.h b/src/google/protobuf/source_context.pb.h
index ccfd365..341a453 100644
--- a/src/google/protobuf/source_context.pb.h
+++ b/src/google/protobuf/source_context.pb.h
@@ -41,7 +41,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT SourceContext : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.SourceContext) */ {
  public:
   SourceContext();
   virtual ~SourceContext();
@@ -75,7 +75,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/source_context.proto b/src/google/protobuf/source_context.proto
index d76252c..a2c08e2 100644
--- a/src/google/protobuf/source_context.proto
+++ b/src/google/protobuf/source_context.proto
@@ -43,6 +43,6 @@
 // protobuf element, like the file in which it is defined.
 message SourceContext {
   // The path-qualified name of the .proto file that contained the associated
-  // protobuf element.  For example: `"google/protobuf/source.proto"`.
+  // protobuf element.  For example: `"google/protobuf/source_context.proto"`.
   string file_name = 1;
 }
diff --git a/src/google/protobuf/struct.pb.cc b/src/google/protobuf/struct.pb.cc
index 11ccabb..dd6b78d 100644
--- a/src/google/protobuf/struct.pb.cc
+++ b/src/google/protobuf/struct.pb.cc
@@ -239,6 +239,7 @@
 
 void Struct::SharedCtor() {
     _is_default_instance_ = false;
+  ::google::protobuf::internal::GetEmptyString();
   _cached_size_ = 0;
   fields_.SetAssignDescriptorCallback(
       protobuf_AssignDescriptorsOnce);
@@ -301,12 +302,16 @@
         if (tag == 10) {
           DO_(input->IncrementRecursionDepth());
          parse_loop_fields:
-          ::google::protobuf::scoped_ptr<Struct_FieldsEntry> entry(fields_.NewEntry());
+          Struct_FieldsEntry::Parser< ::google::protobuf::internal::MapField<
+              ::std::string, ::google::protobuf::Value,
+              ::google::protobuf::internal::WireFormatLite::TYPE_STRING,
+              ::google::protobuf::internal::WireFormatLite::TYPE_MESSAGE,
+              0 >,
+            ::google::protobuf::Map< ::std::string, ::google::protobuf::Value > > parser(&fields_);
           DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(
-              input, entry.get()));
-          (*mutable_fields())[entry->key()].Swap(entry->mutable_value());
+              input, &parser));
           DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
-            entry->key().data(), entry->key().length(),
+            parser.key().data(), parser.key().length(),
             ::google::protobuf::internal::WireFormatLite::PARSE,
             "google.protobuf.Struct.FieldsEntry.key"));
         } else {
@@ -361,8 +366,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Struct)
 }
 
-::google::protobuf::uint8* Struct::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Struct::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Struct)
   // map<string, .google.protobuf.Value> fields = 1;
   {
@@ -372,8 +377,8 @@
         it != this->fields().end(); ++it) {
       entry.reset(fields_.NewEntryWrapper(it->first, it->second));
       target = ::google::protobuf::internal::WireFormatLite::
-          WriteMessageNoVirtualToArray(
-              1, *entry, target);
+          InternalWriteMessageNoVirtualToArray(
+              1, *entry, false, target);
       ::google::protobuf::internal::WireFormatLite::VerifyUtf8String(
         it->first.data(), it->first.length(),
         ::google::protobuf::internal::WireFormatLite::SERIALIZE,
@@ -774,8 +779,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Value)
 }
 
-::google::protobuf::uint8* Value::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Value::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Value)
   // optional .google.protobuf.NullValue null_value = 1;
   if (has_null_value()) {
@@ -807,15 +812,15 @@
   // optional .google.protobuf.Struct struct_value = 5;
   if (has_struct_value()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        5, *kind_.struct_value_, target);
+      InternalWriteMessageNoVirtualToArray(
+        5, *kind_.struct_value_, false, target);
   }
 
   // optional .google.protobuf.ListValue list_value = 6;
   if (has_list_value()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        6, *kind_.list_value_, target);
+      InternalWriteMessageNoVirtualToArray(
+        6, *kind_.list_value_, false, target);
   }
 
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Value)
@@ -1367,14 +1372,14 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.ListValue)
 }
 
-::google::protobuf::uint8* ListValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* ListValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.ListValue)
   // repeated .google.protobuf.Value values = 1;
   for (unsigned int i = 0, n = this->values_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        1, this->values(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        1, this->values(i), false, target);
   }
 
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.ListValue)
diff --git a/src/google/protobuf/struct.pb.h b/src/google/protobuf/struct.pb.h
index 6a4764a..b085b84 100644
--- a/src/google/protobuf/struct.pb.h
+++ b/src/google/protobuf/struct.pb.h
@@ -66,7 +66,7 @@
 }
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Struct : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Struct) */ {
  public:
   Struct();
   virtual ~Struct();
@@ -100,7 +100,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -158,7 +162,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Value) */ {
  public:
   Value();
   virtual ~Value();
@@ -202,7 +206,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -320,7 +328,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT ListValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.ListValue) */ {
  public:
   ListValue();
   virtual ~ListValue();
@@ -354,7 +362,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/stubs/mathlimits.h b/src/google/protobuf/stubs/mathlimits.h
index d984694..70e47bf 100644
--- a/src/google/protobuf/stubs/mathlimits.h
+++ b/src/google/protobuf/stubs/mathlimits.h
@@ -230,11 +230,11 @@
   static bool IsNegInf(const Type x) { return _fpclass(x) == _FPCLASS_NINF; }
 #else
 #define DECL_FP_LIMIT_FUNCS \
-  static bool IsFinite(const Type x) { return !isinf(x)  &&  !isnan(x); } \
+  static bool IsFinite(const Type x) { return !isinf(x) && !isnan(x); } \
   static bool IsNaN(const Type x) { return isnan(x); } \
   static bool IsInf(const Type x) { return isinf(x); } \
-  static bool IsPosInf(const Type x) { return isinf(x)  &&  x > 0; } \
-  static bool IsNegInf(const Type x) { return isinf(x)  &&  x < 0; }
+  static bool IsPosInf(const Type x) { return isinf(x) && x > 0; } \
+  static bool IsNegInf(const Type x) { return isinf(x) && x < 0; }
 #endif
 
 // We can't put floating-point constant values in the header here because
diff --git a/src/google/protobuf/stubs/port.h b/src/google/protobuf/stubs/port.h
index 0e65fc8..328258b 100644
--- a/src/google/protobuf/stubs/port.h
+++ b/src/google/protobuf/stubs/port.h
@@ -174,6 +174,15 @@
 #endif
 #endif
 
+#ifndef GOOGLE_ATTRIBUTE_NORETURN
+#ifdef __GNUC__
+// Tell the compiler that a given function never returns.
+#define GOOGLE_ATTRIBUTE_NORETURN __attribute__((noreturn))
+#else
+#define GOOGLE_ATTRIBUTE_NORETURN
+#endif
+#endif
+
 #ifndef GOOGLE_ATTRIBUTE_DEPRECATED
 #ifdef __GNUC__
 // If the method/variable/type is used anywhere, produce a warning.
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index 07aa1d7..658c8ee 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -3332,7 +3332,11 @@
         break;
       case NOT_NULL:
         EXPECT_TRUE(released != NULL);
-        EXPECT_EQ(&sub_message, released);
+        if (message->GetArena() == NULL) {
+          // released message must be same as sub_message if source message is
+          // not on arena.
+          EXPECT_EQ(&sub_message, released);
+        }
         break;
       case CAN_BE_NULL:
         break;
diff --git a/src/google/protobuf/testing/googletest.cc b/src/google/protobuf/testing/googletest.cc
index 2b9cdde..d45706b 100644
--- a/src/google/protobuf/testing/googletest.cc
+++ b/src/google/protobuf/testing/googletest.cc
@@ -66,6 +66,9 @@
 
 string TestSourceDir() {
 #ifndef GOOGLE_THIRD_PARTY_PROTOBUF
+#ifdef GOOGLE_PROTOBUF_TEST_SOURCE_PATH
+  return GOOGLE_PROTOBUF_TEST_SOURCE_PATH;
+#else
 #ifndef _MSC_VER
   // automake sets the "srcdir" environment variable.
   char* result = getenv("srcdir");
@@ -86,6 +89,7 @@
     prefix += "/..";
   }
   return prefix + "/src";
+#endif  // GOOGLE_PROTOBUF_TEST_SOURCE_PATH
 #else
   return "third_party/protobuf/src";
 #endif  // GOOGLE_THIRD_PARTY_PROTOBUF
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc
index c0dfd53..d49d858 100644
--- a/src/google/protobuf/text_format.cc
+++ b/src/google/protobuf/text_format.cc
@@ -234,7 +234,8 @@
              bool allow_unknown_field,
              bool allow_unknown_enum,
              bool allow_field_number,
-             bool allow_relaxed_whitespace)
+             bool allow_relaxed_whitespace,
+             bool allow_partial)
     : error_collector_(error_collector),
       finder_(finder),
       parse_info_tree_(parse_info_tree),
@@ -246,6 +247,7 @@
       allow_unknown_field_(allow_unknown_field),
       allow_unknown_enum_(allow_unknown_enum),
       allow_field_number_(allow_field_number),
+      allow_partial_(allow_partial),
       had_errors_(false) {
     // For backwards-compatibility with proto1, we need to allow the 'f' suffix
     // for floats.
@@ -718,7 +720,8 @@
           value = SimpleItoa(int_value);        // for error reporting
           enum_value = enum_type->FindValueByNumber(int_value);
         } else {
-          ReportError("Expected integer or identifier.");
+          ReportError("Expected integer or identifier, got: " +
+                      tokenizer_.current().text);
           return false;
         }
 
@@ -831,7 +834,7 @@
       return true;
     }
 
-    ReportError("Expected identifier.");
+    ReportError("Expected identifier, got: " + tokenizer_.current().text);
     return false;
   }
 
@@ -851,7 +854,7 @@
   // Returns false if the token is not of type STRING.
   bool ConsumeString(string* text) {
     if (!LookingAtType(io::Tokenizer::TYPE_STRING)) {
-      ReportError("Expected string.");
+      ReportError("Expected string, got: " + tokenizer_.current().text);
       return false;
     }
 
@@ -869,13 +872,13 @@
   // Returns false if the token is not of type INTEGER.
   bool ConsumeUnsignedInteger(uint64* value, uint64 max_value) {
     if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
-      ReportError("Expected integer.");
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
       return false;
     }
 
     if (!io::Tokenizer::ParseInteger(tokenizer_.current().text,
                                      max_value, value)) {
-      ReportError("Integer out of range.");
+      ReportError("Integer out of range (" + tokenizer_.current().text + ")");
       return false;
     }
 
@@ -902,10 +905,14 @@
 
     DO(ConsumeUnsignedInteger(&unsigned_value, max_value));
 
-    *value = static_cast<int64>(unsigned_value);
-
     if (negative) {
-      *value = -*value;
+      if ((static_cast<uint64>(kint64max) + 1) == unsigned_value) {
+        *value = kint64min;
+      } else {
+        *value = -static_cast<int64>(unsigned_value);
+      }
+    } else {
+      *value = static_cast<int64>(unsigned_value);
     }
 
     return true;
@@ -915,18 +922,18 @@
   // Accepts decimal numbers only, rejects hex or oct numbers.
   bool ConsumeUnsignedDecimalInteger(uint64* value, uint64 max_value) {
     if (!LookingAtType(io::Tokenizer::TYPE_INTEGER)) {
-      ReportError("Expected integer.");
+      ReportError("Expected integer, got: " + tokenizer_.current().text);
       return false;
     }
 
     const string& text = tokenizer_.current().text;
     if (IsHexNumber(text) || IsOctNumber(text)) {
-      ReportError("Expect a decimal number.");
+      ReportError("Expect a decimal number, got: " + text);
       return false;
     }
 
     if (!io::Tokenizer::ParseInteger(text, max_value, value)) {
-      ReportError("Integer out of range.");
+      ReportError("Integer out of range (" + text + ")");
       return false;
     }
 
@@ -971,11 +978,11 @@
         *value = std::numeric_limits<double>::quiet_NaN();
         tokenizer_.Next();
       } else {
-        ReportError("Expected double.");
+        ReportError("Expected double, got: " + text);
         return false;
       }
     } else {
-      ReportError("Expected double.");
+      ReportError("Expected double, got: " + tokenizer_.current().text);
       return false;
     }
 
@@ -1033,7 +1040,17 @@
     DO(ConsumeMessageDelimiter(&sub_delimiter));
     DO(ConsumeMessage(value.get(), sub_delimiter));
 
-    value->AppendToString(serialized_value);
+    if (allow_partial_) {
+      value->AppendPartialToString(serialized_value);
+    } else {
+      if (!value->IsInitialized()) {
+        ReportError(
+            "Value of type \"" + full_type_name +
+            "\" stored in google.protobuf.Any has missing required fields");
+        return false;
+      }
+      value->AppendToString(serialized_value);
+    }
     return true;
   }
 
@@ -1098,6 +1115,7 @@
   const bool allow_unknown_field_;
   const bool allow_unknown_enum_;
   const bool allow_field_number_;
+  const bool allow_partial_;
   bool had_errors_;
 };
 
@@ -1259,7 +1277,7 @@
                     overwrites_policy,
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_enum_, allow_field_number_,
-                    allow_relaxed_whitespace_);
+                    allow_relaxed_whitespace_, allow_partial_);
   return MergeUsingImpl(input, output, &parser);
 }
 
@@ -1276,7 +1294,7 @@
                     ParserImpl::ALLOW_SINGULAR_OVERWRITES,
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_enum_, allow_field_number_,
-                    allow_relaxed_whitespace_);
+                    allow_relaxed_whitespace_, allow_partial_);
   return MergeUsingImpl(input, output, &parser);
 }
 
@@ -1310,7 +1328,7 @@
                     ParserImpl::ALLOW_SINGULAR_OVERWRITES,
                     allow_case_insensitive_field_, allow_unknown_field_,
                     allow_unknown_enum_, allow_field_number_,
-                    allow_relaxed_whitespace_);
+                    allow_relaxed_whitespace_, allow_partial_);
   return parser.ParseField(field, output);
 }
 
diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc
index 410e548..c9521cc 100644
--- a/src/google/protobuf/text_format_unittest.cc
+++ b/src/google/protobuf/text_format_unittest.cc
@@ -1196,11 +1196,13 @@
 
 
 TEST_F(TextFormatParserTest, InvalidToken) {
-  ExpectFailure("optional_bool: true\n-5\n", "Expected identifier.",
+  ExpectFailure("optional_bool: true\n-5\n", "Expected identifier, got: -",
                 2, 1);
 
-  ExpectFailure("optional_bool: true!\n", "Expected identifier.", 1, 20);
-  ExpectFailure("\"some string\"", "Expected identifier.", 1, 1);
+  ExpectFailure("optional_bool: true!\n", "Expected identifier, got: !", 1,
+                20);
+  ExpectFailure("\"some string\"",
+                "Expected identifier, got: \"some string\"", 1, 1);
 }
 
 TEST_F(TextFormatParserTest, InvalidFieldName) {
@@ -1248,46 +1250,52 @@
 
 TEST_F(TextFormatParserTest, InvalidFieldValues) {
   // Invalid values for a double/float field.
-  ExpectFailure("optional_double: \"hello\"\n", "Expected double.", 1, 18);
-  ExpectFailure("optional_double: true\n", "Expected double.", 1, 18);
-  ExpectFailure("optional_double: !\n", "Expected double.", 1, 18);
+  ExpectFailure("optional_double: \"hello\"\n",
+                "Expected double, got: \"hello\"", 1, 18);
+  ExpectFailure("optional_double: true\n", "Expected double, got: true", 1,
+                18);
+  ExpectFailure("optional_double: !\n", "Expected double, got: !", 1, 18);
   ExpectFailure("optional_double {\n  \n}\n", "Expected \":\", found \"{\".",
                 1, 17);
 
   // Invalid values for a signed integer field.
-  ExpectFailure("optional_int32: \"hello\"\n", "Expected integer.", 1, 17);
-  ExpectFailure("optional_int32: true\n", "Expected integer.", 1, 17);
-  ExpectFailure("optional_int32: 4.5\n", "Expected integer.", 1, 17);
-  ExpectFailure("optional_int32: !\n", "Expected integer.", 1, 17);
+  ExpectFailure("optional_int32: \"hello\"\n",
+                "Expected integer, got: \"hello\"", 1, 17);
+  ExpectFailure("optional_int32: true\n", "Expected integer, got: true", 1, 17);
+  ExpectFailure("optional_int32: 4.5\n", "Expected integer, got: 4.5", 1, 17);
+  ExpectFailure("optional_int32: !\n", "Expected integer, got: !", 1, 17);
   ExpectFailure("optional_int32 {\n \n}\n", "Expected \":\", found \"{\".",
                 1, 16);
   ExpectFailure("optional_int32: 0x80000000\n",
-                "Integer out of range.", 1, 17);
+                "Integer out of range (0x80000000)", 1, 17);
   ExpectFailure("optional_int64: 0x8000000000000000\n",
-                "Integer out of range.", 1, 17);
+                "Integer out of range (0x8000000000000000)", 1, 17);
   ExpectFailure("optional_int32: -0x80000001\n",
-                "Integer out of range.", 1, 18);
+                "Integer out of range (0x80000001)", 1, 18);
   ExpectFailure("optional_int64: -0x8000000000000001\n",
-                "Integer out of range.", 1, 18);
+                "Integer out of range (0x8000000000000001)", 1, 18);
 
   // Invalid values for an unsigned integer field.
-  ExpectFailure("optional_uint64: \"hello\"\n", "Expected integer.", 1, 18);
-  ExpectFailure("optional_uint64: true\n", "Expected integer.", 1, 18);
-  ExpectFailure("optional_uint64: 4.5\n", "Expected integer.", 1, 18);
-  ExpectFailure("optional_uint64: -5\n", "Expected integer.", 1, 18);
-  ExpectFailure("optional_uint64: !\n", "Expected integer.", 1, 18);
+  ExpectFailure("optional_uint64: \"hello\"\n",
+                "Expected integer, got: \"hello\"", 1, 18);
+  ExpectFailure("optional_uint64: true\n",
+                "Expected integer, got: true", 1, 18);
+  ExpectFailure("optional_uint64: 4.5\n", "Expected integer, got: 4.5", 1, 18);
+  ExpectFailure("optional_uint64: -5\n", "Expected integer, got: -", 1, 18);
+  ExpectFailure("optional_uint64: !\n", "Expected integer, got: !", 1, 18);
   ExpectFailure("optional_uint64 {\n \n}\n", "Expected \":\", found \"{\".",
                 1, 17);
   ExpectFailure("optional_uint32: 0x100000000\n",
-                "Integer out of range.", 1, 18);
+                "Integer out of range (0x100000000)", 1, 18);
   ExpectFailure("optional_uint64: 0x10000000000000000\n",
-                "Integer out of range.", 1, 18);
+                "Integer out of range (0x10000000000000000)", 1, 18);
 
   // Invalid values for a boolean field.
-  ExpectFailure("optional_bool: \"hello\"\n", "Expected identifier.", 1, 16);
-  ExpectFailure("optional_bool: 5\n", "Integer out of range.", 1, 16);
-  ExpectFailure("optional_bool: -7.5\n", "Expected identifier.", 1, 16);
-  ExpectFailure("optional_bool: !\n", "Expected identifier.", 1, 16);
+  ExpectFailure("optional_bool: \"hello\"\n",
+                "Expected identifier, got: \"hello\"", 1, 16);
+  ExpectFailure("optional_bool: 5\n", "Integer out of range (5)", 1, 16);
+  ExpectFailure("optional_bool: -7.5\n", "Expected identifier, got: -", 1, 16);
+  ExpectFailure("optional_bool: !\n", "Expected identifier, got: !", 1, 16);
 
   ExpectFailure(
       "optional_bool: meh\n",
@@ -1298,16 +1306,16 @@
                 1, 15);
 
   // Invalid values for a string field.
-  ExpectFailure("optional_string: true\n", "Expected string.", 1, 18);
-  ExpectFailure("optional_string: 5\n", "Expected string.", 1, 18);
-  ExpectFailure("optional_string: -7.5\n", "Expected string.", 1, 18);
-  ExpectFailure("optional_string: !\n", "Expected string.", 1, 18);
+  ExpectFailure("optional_string: true\n", "Expected string, got: true", 1, 18);
+  ExpectFailure("optional_string: 5\n", "Expected string, got: 5", 1, 18);
+  ExpectFailure("optional_string: -7.5\n", "Expected string, got: -", 1, 18);
+  ExpectFailure("optional_string: !\n", "Expected string, got: !", 1, 18);
   ExpectFailure("optional_string {\n \n}\n", "Expected \":\", found \"{\".",
                 1, 17);
 
   // Invalid values for an enumeration field.
   ExpectFailure("optional_nested_enum: \"hello\"\n",
-                "Expected integer or identifier.", 1, 23);
+                "Expected integer or identifier, got: \"hello\"", 1, 23);
 
   // Valid token, but enum value is not defined.
   ExpectFailure("optional_nested_enum: 5\n",
@@ -1315,9 +1323,10 @@
                 "\"optional_nested_enum\".", 2, 1);
   // We consume the negative sign, so the error position starts one character
   // later.
-  ExpectFailure("optional_nested_enum: -7.5\n", "Expected integer.", 1, 24);
+  ExpectFailure("optional_nested_enum: -7.5\n", "Expected integer, got: 7.5", 1,
+                24);
   ExpectFailure("optional_nested_enum: !\n",
-                "Expected integer or identifier.", 1, 23);
+                "Expected integer or identifier, got: !", 1, 23);
 
   ExpectFailure(
       "optional_nested_enum: grah\n",
@@ -1340,7 +1349,7 @@
 
   // Unending message.
   ExpectFailure("optional_nested_message {\n \nbb: 118\n",
-                "Expected identifier.",
+                "Expected identifier, got: ",
                 4, 1);
 }
 
diff --git a/src/google/protobuf/timestamp.pb.cc b/src/google/protobuf/timestamp.pb.cc
index 7cdf509..2ec4bc5 100644
--- a/src/google/protobuf/timestamp.pb.cc
+++ b/src/google/protobuf/timestamp.pb.cc
@@ -293,8 +293,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Timestamp)
 }
 
-::google::protobuf::uint8* Timestamp::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Timestamp::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Timestamp)
   // optional int64 seconds = 1;
   if (this->seconds() != 0) {
diff --git a/src/google/protobuf/timestamp.pb.h b/src/google/protobuf/timestamp.pb.h
index 7bf6259..19f4f86 100644
--- a/src/google/protobuf/timestamp.pb.h
+++ b/src/google/protobuf/timestamp.pb.h
@@ -41,7 +41,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Timestamp : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Timestamp) */ {
  public:
   Timestamp();
   virtual ~Timestamp();
@@ -80,7 +80,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/type.pb.cc b/src/google/protobuf/type.pb.cc
index 759cab2..f9182a7 100644
--- a/src/google/protobuf/type.pb.cc
+++ b/src/google/protobuf/type.pb.cc
@@ -548,8 +548,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Type)
 }
 
-::google::protobuf::uint8* Type::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Type::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Type)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -565,8 +565,8 @@
   // repeated .google.protobuf.Field fields = 2;
   for (unsigned int i = 0, n = this->fields_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->fields(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->fields(i), false, target);
   }
 
   // repeated string oneofs = 3;
@@ -582,15 +582,15 @@
   // repeated .google.protobuf.Option options = 4;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        4, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        4, this->options(i), false, target);
   }
 
   // optional .google.protobuf.SourceContext source_context = 5;
   if (this->has_source_context()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        5, *this->source_context_, target);
+      InternalWriteMessageNoVirtualToArray(
+        5, *this->source_context_, false, target);
   }
 
   // optional .google.protobuf.Syntax syntax = 6;
@@ -1417,8 +1417,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Field)
 }
 
-::google::protobuf::uint8* Field::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Field::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Field)
   // optional .google.protobuf.Field.Kind kind = 1;
   if (this->kind() != 0) {
@@ -1472,8 +1472,8 @@
   // repeated .google.protobuf.Option options = 9;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        9, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        9, this->options(i), false, target);
   }
 
   // optional string json_name = 10;
@@ -2192,8 +2192,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Enum)
 }
 
-::google::protobuf::uint8* Enum::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Enum::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Enum)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -2209,22 +2209,22 @@
   // repeated .google.protobuf.EnumValue enumvalue = 2;
   for (unsigned int i = 0, n = this->enumvalue_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, this->enumvalue(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        2, this->enumvalue(i), false, target);
   }
 
   // repeated .google.protobuf.Option options = 3;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        3, this->options(i), false, target);
   }
 
   // optional .google.protobuf.SourceContext source_context = 4;
   if (this->has_source_context()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        4, *this->source_context_, target);
+      InternalWriteMessageNoVirtualToArray(
+        4, *this->source_context_, false, target);
   }
 
   // optional .google.protobuf.Syntax syntax = 5;
@@ -2700,8 +2700,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.EnumValue)
 }
 
-::google::protobuf::uint8* EnumValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* EnumValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.EnumValue)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -2722,8 +2722,8 @@
   // repeated .google.protobuf.Option options = 3;
   for (unsigned int i = 0, n = this->options_size(); i < n; i++) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        3, this->options(i), target);
+      InternalWriteMessageNoVirtualToArray(
+        3, this->options(i), false, target);
   }
 
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.EnumValue)
@@ -3082,8 +3082,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Option)
 }
 
-::google::protobuf::uint8* Option::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Option::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Option)
   // optional string name = 1;
   if (this->name().size() > 0) {
@@ -3099,8 +3099,8 @@
   // optional .google.protobuf.Any value = 2;
   if (this->has_value()) {
     target = ::google::protobuf::internal::WireFormatLite::
-      WriteMessageNoVirtualToArray(
-        2, *this->value_, target);
+      InternalWriteMessageNoVirtualToArray(
+        2, *this->value_, false, target);
   }
 
   // @@protoc_insertion_point(serialize_to_array_end:google.protobuf.Option)
diff --git a/src/google/protobuf/type.pb.h b/src/google/protobuf/type.pb.h
index 4255fa8..ce29c28 100644
--- a/src/google/protobuf/type.pb.h
+++ b/src/google/protobuf/type.pb.h
@@ -130,7 +130,7 @@
 }
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Type : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Type) */ {
  public:
   Type();
   virtual ~Type();
@@ -164,7 +164,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -273,7 +277,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Field : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Field) */ {
  public:
   Field();
   virtual ~Field();
@@ -307,7 +311,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -530,7 +538,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Enum : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Enum) */ {
  public:
   Enum();
   virtual ~Enum();
@@ -564,7 +572,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -656,7 +668,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT EnumValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.EnumValue) */ {
  public:
   EnumValue();
   virtual ~EnumValue();
@@ -690,7 +702,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -759,7 +775,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Option : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Option) */ {
  public:
   Option();
   virtual ~Option();
@@ -793,7 +809,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index da56ae0..d5206d2 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -195,6 +195,7 @@
 // that.
 message ForeignMessage {
   optional int32 c = 1;
+  optional int32 d = 2;
 }
 
 enum ForeignEnum {
diff --git a/src/google/protobuf/unittest_custom_options.proto b/src/google/protobuf/unittest_custom_options.proto
index 4cc0e36..218447e 100644
--- a/src/google/protobuf/unittest_custom_options.proto
+++ b/src/google/protobuf/unittest_custom_options.proto
@@ -69,6 +69,10 @@
   optional int32 field_opt2 = 7753913 [default=42];
 }
 
+extend google.protobuf.OneofOptions {
+  optional int32 oneof_opt1 = 7740111;
+}
+
 extend google.protobuf.EnumOptions {
   optional sfixed32 enum_opt1 = 7753576;
 }
@@ -100,6 +104,11 @@
   optional string field1 = 1 [ctype=CORD,
                               (field_opt1)=8765432109];
 
+  oneof AnOneof {
+    option (oneof_opt1) = -99;
+    int32 oneof_field = 2;
+  }
+
   enum AnEnum {
     option (enum_opt1) = -789;
 
diff --git a/src/google/protobuf/util/field_mask_util.cc b/src/google/protobuf/util/field_mask_util.cc
index 547c9fb..409010a 100644
--- a/src/google/protobuf/util/field_mask_util.cc
+++ b/src/google/protobuf/util/field_mask_util.cc
@@ -200,6 +200,15 @@
     MergeMessage(&root_, source, options, destination);
   }
 
+  // Trims all fields not specified by this tree from the given message.
+  void TrimMessage(Message* message) {
+    // Do nothing if the tree is empty.
+    if (root_.children.empty()) {
+      return;
+    }
+    TrimMessage(&root_, message);
+  }
+
  private:
   struct Node {
     Node() {}
@@ -233,6 +242,9 @@
                     const FieldMaskUtil::MergeOptions& options,
                     Message* destination);
 
+  // Trims all fields not specified by this sub-tree from the given message.
+  void TrimMessage(const Node* node, Message* message);
+
   Node root_;
 
   GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
@@ -367,11 +379,15 @@
     }
     if (!field->is_repeated()) {
       switch (field->cpp_type()) {
-#define COPY_VALUE(TYPE, Name)                                            \
-  case FieldDescriptor::CPPTYPE_##TYPE: {                                 \
-    destination_reflection->Set##Name(                                    \
-        destination, field, source_reflection->Get##Name(source, field)); \
-    break;                                                                \
+#define COPY_VALUE(TYPE, Name)                                              \
+  case FieldDescriptor::CPPTYPE_##TYPE: {                                   \
+    if (source_reflection->HasField(source, field)) {                       \
+      destination_reflection->Set##Name(                                    \
+          destination, field, source_reflection->Get##Name(source, field)); \
+    } else {                                                                \
+      destination_reflection->ClearField(destination, field);               \
+    }                                                                       \
+    break;                                                                  \
   }
         COPY_VALUE(BOOL, Bool)
         COPY_VALUE(INT32, Int32)
@@ -433,6 +449,26 @@
   }
 }
 
+void FieldMaskTree::TrimMessage(const Node* node, Message* message) {
+  GOOGLE_DCHECK(!node->children.empty());
+  const Reflection* reflection = message->GetReflection();
+  const Descriptor* descriptor = message->GetDescriptor();
+  const int32 field_count = descriptor->field_count();
+  for (int index = 0; index < field_count; ++index) {
+    const FieldDescriptor* field = descriptor->field(index);
+    if (!ContainsKey(node->children, field->name())) {
+      reflection->ClearField(message, field);
+    } else {
+      if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+        Node* child = node->children.at(field->name());
+        if (!child->children.empty()) {
+          TrimMessage(child, reflection->MutableMessage(message, field));
+        }
+      }
+    }
+  }
+}
+
 }  // namespace
 
 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
@@ -489,6 +525,14 @@
   tree.MergeMessage(source, options, destination);
 }
 
+void FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* destination) {
+  // Build a FieldMaskTree and walk through the tree to merge all specified
+  // fields.
+  FieldMaskTree tree;
+  tree.MergeFromFieldMask(mask);
+  tree.TrimMessage(GOOGLE_CHECK_NOTNULL(destination));
+}
+
 }  // namespace util
 }  // namespace protobuf
 }  // namespace google
diff --git a/src/google/protobuf/util/field_mask_util.h b/src/google/protobuf/util/field_mask_util.h
index 644161b..e79b65e 100644
--- a/src/google/protobuf/util/field_mask_util.h
+++ b/src/google/protobuf/util/field_mask_util.h
@@ -107,10 +107,16 @@
   static bool IsPathInFieldMask(StringPiece path, const FieldMask& mask);
 
   class MergeOptions;
-  // Merges fields specified in a FieldMask into another message.
+  // Merges fields specified in a FieldMask into another message. See the
+  // comments in MergeOptions regarding compatibility with
+  // google/protobuf/field_mask.proto
   static void MergeMessageTo(const Message& source, const FieldMask& mask,
                              const MergeOptions& options, Message* destination);
 
+  // Removes from 'message' any field that is not represented in the given
+  // FieldMask. If the FieldMask is empty, does nothing.
+  static void TrimMessage(const FieldMask& mask, Message* message);
+
  private:
   friend class SnakeCaseCamelCaseTest;
   // Converts a field name from snake_case to camelCase:
@@ -148,6 +154,10 @@
                                                FieldMask* out);
 };
 
+// Note that for compatibility with the defined behaviour for FieldMask in
+// google/protobuf/field_mask.proto, set replace_message_fields and
+// replace_repeated_fields to 'true'. The default options are not compatible
+// with google/protobuf/field_mask.proto.
 class LIBPROTOBUF_EXPORT FieldMaskUtil::MergeOptions {
  public:
   MergeOptions()
diff --git a/src/google/protobuf/util/field_mask_util_test.cc b/src/google/protobuf/util/field_mask_util_test.cc
index 9b7fb62..43fb790 100644
--- a/src/google/protobuf/util/field_mask_util_test.cc
+++ b/src/google/protobuf/util/field_mask_util_test.cc
@@ -349,6 +349,10 @@
     dst.Clear();                                             \
     FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
     EXPECT_EQ(tmp.DebugString(), dst.DebugString());         \
+    src.clear_##field_name();                                \
+    tmp.clear_##field_name();                                \
+    FieldMaskUtil::MergeMessageTo(src, mask, options, &dst); \
+    EXPECT_EQ(tmp.DebugString(), dst.DebugString());         \
   }
   TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int32)
   TEST_MERGE_ONE_PRIMITIVE_FIELD(optional_int64)
@@ -484,6 +488,117 @@
   EXPECT_EQ(1234, nested_dst.payload().repeated_int32(0));
 }
 
+TEST(FieldMaskUtilTest, TrimMessage) {
+#define TEST_TRIM_ONE_PRIMITIVE_FIELD(field_name)    \
+  {                                                  \
+    TestAllTypes msg;                                \
+    TestUtil::SetAllFields(&msg);                    \
+    TestAllTypes tmp;                                \
+    tmp.set_##field_name(msg.field_name());          \
+    FieldMask mask;                                  \
+    mask.add_paths(#field_name);                     \
+    FieldMaskUtil::TrimMessage(mask, &msg);          \
+    EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+  }
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_int64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_uint64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sint64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_fixed64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed32)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_sfixed64)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_float)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_double)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bool)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_string)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_bytes)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_nested_enum)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_foreign_enum)
+  TEST_TRIM_ONE_PRIMITIVE_FIELD(optional_import_enum)
+#undef TEST_TRIM_ONE_PRIMITIVE_FIELD
+
+#define TEST_TRIM_ONE_FIELD(field_name)              \
+  {                                                  \
+    TestAllTypes msg;                                \
+    TestUtil::SetAllFields(&msg);                    \
+    TestAllTypes tmp;                                \
+    *tmp.mutable_##field_name() = msg.field_name();  \
+    FieldMask mask;                                  \
+    mask.add_paths(#field_name);                     \
+    FieldMaskUtil::TrimMessage(mask, &msg);          \
+    EXPECT_EQ(tmp.DebugString(), msg.DebugString()); \
+  }
+  TEST_TRIM_ONE_FIELD(optional_nested_message)
+  TEST_TRIM_ONE_FIELD(optional_foreign_message)
+  TEST_TRIM_ONE_FIELD(optional_import_message)
+
+  TEST_TRIM_ONE_FIELD(repeated_int32)
+  TEST_TRIM_ONE_FIELD(repeated_int64)
+  TEST_TRIM_ONE_FIELD(repeated_uint32)
+  TEST_TRIM_ONE_FIELD(repeated_uint64)
+  TEST_TRIM_ONE_FIELD(repeated_sint32)
+  TEST_TRIM_ONE_FIELD(repeated_sint64)
+  TEST_TRIM_ONE_FIELD(repeated_fixed32)
+  TEST_TRIM_ONE_FIELD(repeated_fixed64)
+  TEST_TRIM_ONE_FIELD(repeated_sfixed32)
+  TEST_TRIM_ONE_FIELD(repeated_sfixed64)
+  TEST_TRIM_ONE_FIELD(repeated_float)
+  TEST_TRIM_ONE_FIELD(repeated_double)
+  TEST_TRIM_ONE_FIELD(repeated_bool)
+  TEST_TRIM_ONE_FIELD(repeated_string)
+  TEST_TRIM_ONE_FIELD(repeated_bytes)
+  TEST_TRIM_ONE_FIELD(repeated_nested_message)
+  TEST_TRIM_ONE_FIELD(repeated_foreign_message)
+  TEST_TRIM_ONE_FIELD(repeated_import_message)
+  TEST_TRIM_ONE_FIELD(repeated_nested_enum)
+  TEST_TRIM_ONE_FIELD(repeated_foreign_enum)
+  TEST_TRIM_ONE_FIELD(repeated_import_enum)
+#undef TEST_TRIM_ONE_FIELD
+
+  // Test trim nested fields.
+  NestedTestAllTypes nested_msg;
+  nested_msg.mutable_child()->mutable_payload()->set_optional_int32(1234);
+  nested_msg.mutable_child()
+      ->mutable_child()
+      ->mutable_payload()
+      ->set_optional_int32(5678);
+  NestedTestAllTypes trimmed_msg(nested_msg);
+  FieldMask mask;
+  FieldMaskUtil::FromString("child.payload", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(0, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child.child.payload", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(1234, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  trimmed_msg = nested_msg;
+  FieldMaskUtil::FromString("child.child", &mask);
+  FieldMaskUtil::TrimMessage(mask, &trimmed_msg);
+  EXPECT_EQ(0, trimmed_msg.child().payload().optional_int32());
+  EXPECT_EQ(5678, trimmed_msg.child().child().payload().optional_int32());
+
+  // Verify than an empty FieldMask trims nothing
+  TestAllTypes all_types_msg;
+  TestUtil::SetAllFields(&all_types_msg);
+  TestAllTypes trimmed_all_types(all_types_msg);
+  FieldMask empty_mask;
+  FieldMaskUtil::TrimMessage(empty_mask, &trimmed_all_types);
+  EXPECT_EQ(trimmed_all_types.DebugString(), all_types_msg.DebugString());
+}
+
 
 }  // namespace
 }  // namespace util
diff --git a/src/google/protobuf/util/internal/datapiece.cc b/src/google/protobuf/util/internal/datapiece.cc
index 72c0aca..ef8da42 100644
--- a/src/google/protobuf/util/internal/datapiece.cc
+++ b/src/google/protobuf/util/internal/datapiece.cc
@@ -329,9 +329,8 @@
       // WebSafeBase64Escape does no padding by default.
       WebSafeBase64Escape(*dest, &encoded);
       // Remove trailing padding '=' characters before comparison.
-      StringPiece src_no_padding(src, 0, src.ends_with("=")
-                                             ? src.find_last_not_of('=') + 1
-                                             : src.length());
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length());
       return encoded == src_no_padding;
     }
     return true;
@@ -343,9 +342,8 @@
       Base64Escape(
           reinterpret_cast<const unsigned char*>(dest->data()), dest->length(),
           &encoded, false);
-      StringPiece src_no_padding(src, 0, src.ends_with("=")
-                                             ? src.find_last_not_of('=') + 1
-                                             : src.length());
+      StringPiece src_no_padding = StringPiece(src).substr(
+          0, src.ends_with("=") ? src.find_last_not_of('=') + 1 : src.length());
       return encoded == src_no_padding;
     }
     return true;
@@ -354,6 +352,26 @@
   return false;
 }
 
+void DataPiece::InternalCopy(const DataPiece& other) {
+  type_ = other.type_;
+  switch (type_) {
+    case TYPE_INT32:
+    case TYPE_INT64:
+    case TYPE_UINT32:
+    case TYPE_UINT64:
+    case TYPE_DOUBLE:
+    case TYPE_FLOAT:
+    case TYPE_BOOL:
+    case TYPE_ENUM:
+    case TYPE_NULL:
+    case TYPE_BYTES:
+    case TYPE_STRING: {
+      str_ = other.str_;
+      break;
+    }
+  }
+}
+
 }  // namespace converter
 }  // namespace util
 }  // namespace protobuf
diff --git a/src/google/protobuf/util/internal/datapiece.h b/src/google/protobuf/util/internal/datapiece.h
index 8b2e35d..e82cdba 100644
--- a/src/google/protobuf/util/internal/datapiece.h
+++ b/src/google/protobuf/util/internal/datapiece.h
@@ -92,10 +92,11 @@
       : type_(TYPE_BYTES),
         str_(StringPiecePod::CreateFromStringPiece(value)),
         use_strict_base64_decoding_(use_strict_base64_decoding) {}
-  DataPiece(const DataPiece& r) : type_(r.type_), str_(r.str_) {}
+
+  DataPiece(const DataPiece& r) : type_(r.type_) { InternalCopy(r); }
+
   DataPiece& operator=(const DataPiece& x) {
-    type_ = x.type_;
-    str_ = x.str_;
+    InternalCopy(x);
     return *this;
   }
 
@@ -171,6 +172,9 @@
   // Decodes a base64 string. Returns true on success.
   bool DecodeBase64(StringPiece src, string* dest) const;
 
+  // Helper function to initialize this DataPiece with 'other'.
+  void InternalCopy(const DataPiece& other);
+
   // Data type for this piece of data.
   Type type_;
 
diff --git a/src/google/protobuf/util/internal/json_escaping.cc b/src/google/protobuf/util/internal/json_escaping.cc
index 24bd554..06d2791 100644
--- a/src/google/protobuf/util/internal/json_escaping.cc
+++ b/src/google/protobuf/util/internal/json_escaping.cc
@@ -255,7 +255,7 @@
   buffer[3] = kHex[cp & 0x0f];
   cp >>= 4;
   buffer[2] = kHex[cp & 0x0f];
-  return StringPiece(buffer, 0, 6);
+  return StringPiece(buffer).substr(0, 6);
 }
 
 // Stores the 32-bit unicode code point as its hexadecimal digits in buffer
diff --git a/src/google/protobuf/util/internal/object_writer.h b/src/google/protobuf/util/internal/object_writer.h
index 9f07363..5781aa1 100644
--- a/src/google/protobuf/util/internal/object_writer.h
+++ b/src/google/protobuf/util/internal/object_writer.h
@@ -101,6 +101,7 @@
   // Renders a Null value.
   virtual ObjectWriter* RenderNull(StringPiece name) = 0;
 
+
   // Renders a DataPiece object to a ObjectWriter.
   static void RenderDataPieceTo(const DataPiece& data, StringPiece name,
                                 ObjectWriter* ow);
diff --git a/src/google/protobuf/util/internal/proto_writer.cc b/src/google/protobuf/util/internal/proto_writer.cc
index 36b7941..18cc123 100644
--- a/src/google/protobuf/util/internal/proto_writer.cc
+++ b/src/google/protobuf/util/internal/proto_writer.cc
@@ -293,10 +293,14 @@
       ow_(enclosing),
       parent_field_(NULL),
       typeinfo_(typeinfo),
+      proto3_(type.syntax() == google::protobuf::SYNTAX_PROTO3),
       type_(type),
-      required_fields_(GetRequiredFields(type)),
       size_index_(-1),
-      array_index_(-1) {}
+      array_index_(-1) {
+  if (!proto3_) {
+    required_fields_ = GetRequiredFields(type_);
+  }
+}
 
 ProtoWriter::ProtoElement::ProtoElement(ProtoWriter::ProtoElement* parent,
                                         const google::protobuf::Field* field,
@@ -306,6 +310,7 @@
       ow_(this->parent()->ow_),
       parent_field_(field),
       typeinfo_(this->parent()->typeinfo_),
+      proto3_(this->parent()->proto3_),
       type_(type),
       size_index_(
           !is_list && field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE
@@ -316,12 +321,15 @@
     if (ow_->IsRepeated(*field)) {
       // Update array_index_ if it is an explicit list.
       if (this->parent()->array_index_ >= 0) this->parent()->array_index_++;
-    } else {
+    } else if (!proto3_) {
+      // For required fields tracking.
       this->parent()->RegisterField(field);
     }
 
     if (field->kind() == google::protobuf::Field_Kind_TYPE_MESSAGE) {
-      required_fields_ = GetRequiredFields(type_);
+      if (!proto3_) {
+        required_fields_ = GetRequiredFields(type_);
+      }
       int start_pos = ow_->stream_->ByteCount();
       // length of serialized message is the final buffer position minus
       // starting buffer position, plus length adjustments for size fields
@@ -334,12 +342,14 @@
 }
 
 ProtoWriter::ProtoElement* ProtoWriter::ProtoElement::pop() {
-  // Calls the registered error listener for any required field(s) not yet
-  // seen.
-  for (set<const google::protobuf::Field*>::iterator it =
-           required_fields_.begin();
-       it != required_fields_.end(); ++it) {
-    ow_->MissingField((*it)->name());
+  if (!proto3_) {
+    // Calls the registered error listener for any required field(s) not yet
+    // seen.
+    for (set<const google::protobuf::Field*>::iterator it =
+             required_fields_.begin();
+         it != required_fields_.end(); ++it) {
+      ow_->MissingField((*it)->name());
+    }
   }
   // Computes the total number of proto bytes used by a message, also adjusts
   // the size of all parent messages by the length of this size field.
diff --git a/src/google/protobuf/util/internal/proto_writer.h b/src/google/protobuf/util/internal/proto_writer.h
index 957565e..ffb8f60 100644
--- a/src/google/protobuf/util/internal/proto_writer.h
+++ b/src/google/protobuf/util/internal/proto_writer.h
@@ -117,6 +117,7 @@
     return RenderDataPiece(name, DataPiece::NullData());
   }
 
+
   // Renders a DataPiece 'value' into a field whose wire type is determined
   // from the given field 'name'.
   virtual ProtoWriter* RenderDataPiece(StringPiece name,
@@ -198,6 +199,9 @@
     // TypeInfo to lookup types.
     const TypeInfo* typeinfo_;
 
+    // Whether the root type is a proto3 or not.
+    bool proto3_;
+
     // Additional variables if this element is a message:
     // (Root element is always a message).
     // type_             : the type of this element.
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.cc b/src/google/protobuf/util/internal/protostream_objectsource.cc
index 1f3781a..0048d75 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.cc
+++ b/src/google/protobuf/util/internal/protostream_objectsource.cc
@@ -121,7 +121,8 @@
       type_(type),
       use_lower_camel_for_enums_(false),
       recursion_depth_(0),
-      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+      max_recursion_depth_(kDefaultMaxRecursionDepth),
+      render_unknown_fields_(false) {
   GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
 }
 
@@ -134,7 +135,8 @@
       type_(type),
       use_lower_camel_for_enums_(false),
       recursion_depth_(0),
-      max_recursion_depth_(kDefaultMaxRecursionDepth) {
+      max_recursion_depth_(kDefaultMaxRecursionDepth),
+      render_unknown_fields_(false) {
   GOOGLE_LOG_IF(DFATAL, stream == NULL) << "Input stream is NULL.";
 }
 
@@ -184,6 +186,7 @@
   string field_name;
   // last_tag set to dummy value that is different from tag.
   uint32 tag = stream_->ReadTag(), last_tag = tag + 1;
+  google::protobuf::UnknownFieldSet unknown_fields;
 
   if (include_start_and_end) {
     ow->StartObject(name);
@@ -199,7 +202,8 @@
     if (field == NULL) {
       // If we didn't find a field, skip this unknown tag.
       // TODO(wpoon): Check return boolean value.
-      WireFormat::SkipField(stream_, tag, NULL);
+      WireFormat::SkipField(stream_, tag,
+                            render_unknown_fields_ ? &unknown_fields : NULL);
       tag = stream_->ReadTag();
       continue;
     }
@@ -221,6 +225,8 @@
       tag = stream_->ReadTag();
     }
   }
+
+
   if (include_start_and_end) {
     ow->EndObject();
   }
diff --git a/src/google/protobuf/util/internal/protostream_objectsource.h b/src/google/protobuf/util/internal/protostream_objectsource.h
index d7d4347..243f85b 100644
--- a/src/google/protobuf/util/internal/protostream_objectsource.h
+++ b/src/google/protobuf/util/internal/protostream_objectsource.h
@@ -117,6 +117,7 @@
     max_recursion_depth_ = max_depth;
   }
 
+
  protected:
   // Writes a proto2 Message to the ObjectWriter. When the given end_tag is
   // found this method will complete, allowing it to be used for parsing both
@@ -287,6 +288,9 @@
   // Maximum allowed recursion depth.
   int max_recursion_depth_;
 
+  // Whether to render unknown fields.
+  bool render_unknown_fields_;
+
   GOOGLE_DISALLOW_IMPLICIT_CONSTRUCTORS(ProtoStreamObjectSource);
 };
 
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.cc b/src/google/protobuf/util/internal/protostream_objectwriter.cc
index 97a7909..8fa58a6 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.cc
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.cc
@@ -384,6 +384,9 @@
   if (item_type_ == ANY) {
     any_.reset(new AnyWriter(ow_));
   }
+  if (item_type == MAP) {
+    map_keys_.reset(new hash_set<string>);
+  }
 }
 
 ProtoStreamObjectWriter::Item::Item(ProtoStreamObjectWriter::Item* parent,
@@ -398,11 +401,14 @@
   if (item_type == ANY) {
     any_.reset(new AnyWriter(ow_));
   }
+  if (item_type == MAP) {
+    map_keys_.reset(new hash_set<string>);
+  }
 }
 
 bool ProtoStreamObjectWriter::Item::InsertMapKeyIfNotPresent(
     StringPiece map_key) {
-  return InsertIfNotPresent(&map_keys_, map_key.ToString());
+  return InsertIfNotPresent(map_keys_.get(), map_key.ToString());
 }
 
 ProtoStreamObjectWriter* ProtoStreamObjectWriter::StartObject(
@@ -1000,6 +1006,7 @@
                                  DataPiece(name, use_strict_base64_decoding()));
     field = Lookup("value");
     if (field == NULL) {
+      Pop();
       GOOGLE_LOG(DFATAL) << "Map does not have a value field.";
       return this;
     }
diff --git a/src/google/protobuf/util/internal/protostream_objectwriter.h b/src/google/protobuf/util/internal/protostream_objectwriter.h
index e1162d4..75e3d67 100644
--- a/src/google/protobuf/util/internal/protostream_objectwriter.h
+++ b/src/google/protobuf/util/internal/protostream_objectwriter.h
@@ -231,7 +231,7 @@
 
     // Set of map keys already seen for the type_. Used to validate incoming
     // messages so no map key appears more than once.
-    hash_set<string> map_keys_;
+    google::protobuf::scoped_ptr<hash_set<string> > map_keys_;
 
     // Conveys whether this Item is a placeholder or not. Placeholder items are
     // pushed to stack to account for special types.
@@ -249,19 +249,19 @@
                           strings::ByteSink* output, ErrorListener* listener);
 
   // Returns true if the field is a map.
-  bool IsMap(const google::protobuf::Field& field);
+  inline bool IsMap(const google::protobuf::Field& field);
 
   // Returns true if the field is an any.
-  bool IsAny(const google::protobuf::Field& field);
+  inline bool IsAny(const google::protobuf::Field& field);
 
   // Returns true if the field is google.protobuf.Struct.
-  bool IsStruct(const google::protobuf::Field& field);
+  inline bool IsStruct(const google::protobuf::Field& field);
 
   // Returns true if the field is google.protobuf.Value.
-  bool IsStructValue(const google::protobuf::Field& field);
+  inline bool IsStructValue(const google::protobuf::Field& field);
 
   // Returns true if the field is google.protobuf.ListValue.
-  bool IsStructListValue(const google::protobuf::Field& field);
+  inline bool IsStructListValue(const google::protobuf::Field& field);
 
   // Renders google.protobuf.Value in struct.proto. It picks the right oneof
   // type based on value's type.
diff --git a/src/google/protobuf/util/internal/utility.cc b/src/google/protobuf/util/internal/utility.cc
index ee7a51f..5f613e7 100644
--- a/src/google/protobuf/util/internal/utility.cc
+++ b/src/google/protobuf/util/internal/utility.cc
@@ -52,7 +52,7 @@
   for (i = 0; i < str.size() && isspace(str[i]); ++i) {
   }
   GOOGLE_DCHECK(i == str.size() || !isspace(str[i]));
-  return StringPiece(str, i);
+  return str.substr(i);
 }
 }  // namespace
 
@@ -128,8 +128,12 @@
 }
 
 const StringPiece GetTypeWithoutUrl(StringPiece type_url) {
-  size_t idx = type_url.rfind('/');
-  return type_url.substr(idx + 1);
+  if (type_url.size() > kTypeUrlSize && type_url[kTypeUrlSize] == '/') {
+    return type_url.substr(kTypeUrlSize + 1);
+  } else {
+    size_t idx = type_url.rfind('/');
+    return type_url.substr(idx + 1);
+  }
 }
 
 const string GetFullTypeWithUrl(StringPiece simple_type) {
diff --git a/src/google/protobuf/util/internal/utility.h b/src/google/protobuf/util/internal/utility.h
index 33df8ed..26fed44 100644
--- a/src/google/protobuf/util/internal/utility.h
+++ b/src/google/protobuf/util/internal/utility.h
@@ -64,6 +64,10 @@
 namespace protobuf {
 namespace util {
 namespace converter {
+
+// Size of "type.googleapis.com"
+static const int64 kTypeUrlSize = 19;
+
 // Finds the tech option identified by option_name. Parses the boolean value and
 // returns it.
 // When the option with the given name is not found, default_value is returned.
diff --git a/src/google/protobuf/util/json_format_proto3.proto b/src/google/protobuf/util/json_format_proto3.proto
index a1e24c1..3835b30 100644
--- a/src/google/protobuf/util/json_format_proto3.proto
+++ b/src/google/protobuf/util/json_format_proto3.proto
@@ -39,6 +39,7 @@
 import "google/protobuf/struct.proto";
 import "google/protobuf/any.proto";
 import "google/protobuf/field_mask.proto";
+import "google/protobuf/unittest.proto";
 
 enum EnumType {
   FOO = 0;
@@ -174,3 +175,7 @@
 message TestCustomJsonName {
   int32 value = 1 [json_name = "@value"];
 }
+
+message TestExtensions {
+  .protobuf_unittest.TestAllExtensions extensions = 1;
+}
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc
index fe8119b..fc55c2b 100644
--- a/src/google/protobuf/util/message_differencer.cc
+++ b/src/google/protobuf/util/message_differencer.cc
@@ -474,7 +474,10 @@
 
   // Retrieve all the set fields, including extensions.
   vector<const FieldDescriptor*> message1_fields;
+  message1_fields.reserve(1 + message1.GetDescriptor()->field_count());
+
   vector<const FieldDescriptor*> message2_fields;
+  message2_fields.reserve(1 + message2.GetDescriptor()->field_count());
 
   reflection1->ListFields(message1, &message1_fields);
   reflection2->ListFields(message2, &message2_fields);
diff --git a/src/google/protobuf/util/message_differencer.h b/src/google/protobuf/util/message_differencer.h
index 3ea74e6..1abbfcb 100644
--- a/src/google/protobuf/util/message_differencer.h
+++ b/src/google/protobuf/util/message_differencer.h
@@ -570,6 +570,12 @@
   // any differences found in human-readable form to the supplied
   // ZeroCopyOutputStream or Printer. If a printer is used, the delimiter
   // *must* be '$'.
+  //
+  // WARNING: this reporter does not necessarily flush its output until it is
+  // destroyed. As a result, it is not safe to assume the output is valid or
+  // complete until after you destroy the reporter. For example, if you use a
+  // StreamReporter to write to a StringOutputStream, the target string may
+  // contain uninitialized data until the reporter is destroyed.
   class LIBPROTOBUF_EXPORT StreamReporter : public Reporter {
    public:
     explicit StreamReporter(io::ZeroCopyOutputStream* output);
diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h
index 55fc7ec..580d4db 100644
--- a/src/google/protobuf/wire_format_lite.h
+++ b/src/google/protobuf/wire_format_lite.h
@@ -457,20 +457,48 @@
   INL static uint8* WriteBytesToArray(
     field_number, const string& value, output);
 
-  INL static uint8* WriteGroupToArray(
-      field_number, const MessageLite& value, output);
-  INL static uint8* WriteMessageToArray(
-      field_number, const MessageLite& value, output);
+  // Whether to serialize deterministically (e.g., map keys are
+  // sorted) is a property of a CodedOutputStream, and in the process
+  // of serialization, the "ToArray" variants may be invoked.  But they don't
+  // have a CodedOutputStream available, so they get an additional parameter
+  // telling them whether to serialize deterministically.
+  INL static uint8* InternalWriteGroupToArray(
+      field_number, const MessageLite& value, bool deterministic, output);
+  INL static uint8* InternalWriteMessageToArray(
+      field_number, const MessageLite& value, bool deterministic, output);
 
   // Like above, but de-virtualize the call to SerializeWithCachedSizes().  The
   // pointer must point at an instance of MessageType, *not* a subclass (or
   // the subclass must not override SerializeWithCachedSizes()).
   template<typename MessageType>
+  INL static uint8* InternalWriteGroupNoVirtualToArray(
+    field_number, const MessageType& value, bool deterministic, output);
+  template<typename MessageType>
+  INL static uint8* InternalWriteMessageNoVirtualToArray(
+    field_number, const MessageType& value, bool deterministic, output);
+
+  // For backward-compatibility, the last four methods also have versions
+  // that are non-deterministic always.
+  INL static uint8* WriteGroupToArray(
+      field_number, const MessageLite& value, output) {
+    return InternalWriteGroupToArray(field_number_arg, value, false, target);
+  }
+  INL static uint8* WriteMessageToArray(
+      field_number, const MessageLite& value, output) {
+    return InternalWriteMessageToArray(field_number_arg, value, false, target);
+  }
+  template<typename MessageType>
   INL static uint8* WriteGroupNoVirtualToArray(
-    field_number, const MessageType& value, output);
+      field_number, const MessageType& value, output) {
+    return InternalWriteGroupNoVirtualToArray(field_number_arg, value, false,
+                                              target);
+  }
   template<typename MessageType>
   INL static uint8* WriteMessageNoVirtualToArray(
-    field_number, const MessageType& value, output);
+      field_number, const MessageType& value, output) {
+    return InternalWriteMessageNoVirtualToArray(field_number_arg, value, false,
+                                                target);
+  }
 
 #undef output
 #undef input
diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h
index 7bce21c..ebd858f 100644
--- a/src/google/protobuf/wire_format_lite_inl.h
+++ b/src/google/protobuf/wire_format_lite_inl.h
@@ -329,8 +329,8 @@
 template <typename CType, enum WireFormatLite::FieldType DeclaredType>
 inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input,
                                                 RepeatedField<CType>* values) {
-  uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
   io::CodedInputStream::Limit limit = input->PushLimit(length);
   while (input->BytesUntilLimit() > 0) {
     CType value;
@@ -344,8 +344,8 @@
 template <typename CType, enum WireFormatLite::FieldType DeclaredType>
 inline bool WireFormatLite::ReadPackedFixedSizePrimitive(
     io::CodedInputStream* input, RepeatedField<CType>* values) {
-  uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
   const uint32 old_entries = values->size();
   const uint32 new_entries = length / sizeof(CType);
   const uint32 new_bytes = new_entries * sizeof(CType);
@@ -443,8 +443,8 @@
 }
 inline bool WireFormatLite::ReadMessage(io::CodedInputStream* input,
                                         MessageLite* value) {
-  uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
   std::pair<io::CodedInputStream::Limit, int> p =
       input->IncrementRecursionDepthAndPushLimit(length);
   if (p.second < 0 || !value->MergePartialFromCodedStream(input)) return false;
@@ -489,8 +489,8 @@
 template<typename MessageType_WorkAroundCppLookupDefect>
 inline bool WireFormatLite::ReadMessageNoVirtual(
     io::CodedInputStream* input, MessageType_WorkAroundCppLookupDefect* value) {
-  uint32 length;
-  if (!input->ReadVarint32(&length)) return false;
+  int length;
+  if (!input->ReadVarintSizeAsInt(&length)) return false;
   std::pair<io::CodedInputStream::Limit, int> p =
       input->IncrementRecursionDepthAndPushLimit(length);
   if (p.second < 0 || !value->
@@ -772,42 +772,40 @@
 }
 
 
-inline uint8* WireFormatLite::WriteGroupToArray(int field_number,
-                                                const MessageLite& value,
-                                                uint8* target) {
+inline uint8* WireFormatLite::InternalWriteGroupToArray(
+    int field_number, const MessageLite& value, bool deterministic,
+    uint8* target) {
   target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
-  target = value.SerializeWithCachedSizesToArray(target);
+  target = value.InternalSerializeWithCachedSizesToArray(deterministic, target);
   return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
 }
-inline uint8* WireFormatLite::WriteMessageToArray(int field_number,
-                                                  const MessageLite& value,
-                                                  uint8* target) {
+inline uint8* WireFormatLite::InternalWriteMessageToArray(
+    int field_number, const MessageLite& value, bool deterministic,
+    uint8* target) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   target = io::CodedOutputStream::WriteVarint32ToArray(
     value.GetCachedSize(), target);
-  return value.SerializeWithCachedSizesToArray(target);
+  return value.InternalSerializeWithCachedSizesToArray(deterministic, target);
 }
 
 // See comment on ReadGroupNoVirtual to understand the need for this template
 // parameter name.
 template<typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::WriteGroupNoVirtualToArray(
+inline uint8* WireFormatLite::InternalWriteGroupNoVirtualToArray(
     int field_number, const MessageType_WorkAroundCppLookupDefect& value,
-    uint8* target) {
+    bool deterministic, uint8* target) {
   target = WriteTagToArray(field_number, WIRETYPE_START_GROUP, target);
-  target = value.MessageType_WorkAroundCppLookupDefect
-      ::SerializeWithCachedSizesToArray(target);
+  target = value.InternalSerializeWithCachedSizesToArray(deterministic, target);
   return WriteTagToArray(field_number, WIRETYPE_END_GROUP, target);
 }
 template<typename MessageType_WorkAroundCppLookupDefect>
-inline uint8* WireFormatLite::WriteMessageNoVirtualToArray(
+inline uint8* WireFormatLite::InternalWriteMessageNoVirtualToArray(
     int field_number, const MessageType_WorkAroundCppLookupDefect& value,
-    uint8* target) {
+    bool deterministic, uint8* target) {
   target = WriteTagToArray(field_number, WIRETYPE_LENGTH_DELIMITED, target);
   target = io::CodedOutputStream::WriteVarint32ToArray(
     value.MessageType_WorkAroundCppLookupDefect::GetCachedSize(), target);
-  return value.MessageType_WorkAroundCppLookupDefect
-      ::SerializeWithCachedSizesToArray(target);
+  return value.InternalSerializeWithCachedSizesToArray(deterministic, target);
 }
 
 // ===================================================================
diff --git a/src/google/protobuf/wrappers.pb.cc b/src/google/protobuf/wrappers.pb.cc
index 6080142..08490f3 100644
--- a/src/google/protobuf/wrappers.pb.cc
+++ b/src/google/protobuf/wrappers.pb.cc
@@ -448,8 +448,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.DoubleValue)
 }
 
-::google::protobuf::uint8* DoubleValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* DoubleValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.DoubleValue)
   // optional double value = 1;
   if (this->value() != 0) {
@@ -706,8 +706,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.FloatValue)
 }
 
-::google::protobuf::uint8* FloatValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* FloatValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.FloatValue)
   // optional float value = 1;
   if (this->value() != 0) {
@@ -964,8 +964,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Int64Value)
 }
 
-::google::protobuf::uint8* Int64Value::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Int64Value::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int64Value)
   // optional int64 value = 1;
   if (this->value() != 0) {
@@ -1224,8 +1224,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.UInt64Value)
 }
 
-::google::protobuf::uint8* UInt64Value::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UInt64Value::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt64Value)
   // optional uint64 value = 1;
   if (this->value() != 0) {
@@ -1484,8 +1484,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.Int32Value)
 }
 
-::google::protobuf::uint8* Int32Value::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* Int32Value::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.Int32Value)
   // optional int32 value = 1;
   if (this->value() != 0) {
@@ -1744,8 +1744,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.UInt32Value)
 }
 
-::google::protobuf::uint8* UInt32Value::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* UInt32Value::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.UInt32Value)
   // optional uint32 value = 1;
   if (this->value() != 0) {
@@ -2004,8 +2004,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.BoolValue)
 }
 
-::google::protobuf::uint8* BoolValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* BoolValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BoolValue)
   // optional bool value = 1;
   if (this->value() != 0) {
@@ -2271,8 +2271,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.StringValue)
 }
 
-::google::protobuf::uint8* StringValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* StringValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.StringValue)
   // optional string value = 1;
   if (this->value().size() > 0) {
@@ -2590,8 +2590,8 @@
   // @@protoc_insertion_point(serialize_end:google.protobuf.BytesValue)
 }
 
-::google::protobuf::uint8* BytesValue::SerializeWithCachedSizesToArray(
-    ::google::protobuf::uint8* target) const {
+::google::protobuf::uint8* BytesValue::InternalSerializeWithCachedSizesToArray(
+    bool deterministic, ::google::protobuf::uint8* target) const {
   // @@protoc_insertion_point(serialize_to_array_start:google.protobuf.BytesValue)
   // optional bytes value = 1;
   if (this->value().size() > 0) {
diff --git a/src/google/protobuf/wrappers.pb.h b/src/google/protobuf/wrappers.pb.h
index 1078477..73f8ff6 100644
--- a/src/google/protobuf/wrappers.pb.h
+++ b/src/google/protobuf/wrappers.pb.h
@@ -49,7 +49,7 @@
 
 // ===================================================================
 
-class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT DoubleValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.DoubleValue) */ {
  public:
   DoubleValue();
   virtual ~DoubleValue();
@@ -88,7 +88,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -140,7 +144,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT FloatValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.FloatValue) */ {
  public:
   FloatValue();
   virtual ~FloatValue();
@@ -179,7 +183,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -231,7 +239,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Int64Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int64Value) */ {
  public:
   Int64Value();
   virtual ~Int64Value();
@@ -270,7 +278,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -322,7 +334,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UInt64Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt64Value) */ {
  public:
   UInt64Value();
   virtual ~UInt64Value();
@@ -361,7 +373,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -413,7 +429,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT Int32Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.Int32Value) */ {
  public:
   Int32Value();
   virtual ~Int32Value();
@@ -452,7 +468,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -504,7 +524,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT UInt32Value : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.UInt32Value) */ {
  public:
   UInt32Value();
   virtual ~UInt32Value();
@@ -543,7 +563,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -595,7 +619,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT BoolValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BoolValue) */ {
  public:
   BoolValue();
   virtual ~BoolValue();
@@ -634,7 +658,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -686,7 +714,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT StringValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.StringValue) */ {
  public:
   StringValue();
   virtual ~StringValue();
@@ -725,7 +753,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();
@@ -785,7 +817,7 @@
 };
 // -------------------------------------------------------------------
 
-class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message {
+class LIBPROTOBUF_EXPORT BytesValue : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:google.protobuf.BytesValue) */ {
  public:
   BytesValue();
   virtual ~BytesValue();
@@ -824,7 +856,11 @@
       ::google::protobuf::io::CodedInputStream* input);
   void SerializeWithCachedSizes(
       ::google::protobuf::io::CodedOutputStream* output) const;
-  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray(
+      bool deterministic, ::google::protobuf::uint8* output) const;
+  ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const {
+    return InternalSerializeWithCachedSizesToArray(false, output);
+  }
   int GetCachedSize() const { return _cached_size_; }
   private:
   void SharedCtor();