Add support for Java micro protobuf's to protobuf-2.3.0.

See README.android for additional information.

Change-Id: I6693e405c0d651eacacd3227a876129865dd0d3c
diff --git a/java/README.txt b/java/README.txt
index 3ed06a1..4a2839a 100644
--- a/java/README.txt
+++ b/java/README.txt
@@ -87,6 +87,180 @@
 
 4) Install the classes wherever you prefer.
 
+Micro version
+============================
+
+The runtime and generated code for MICRO_RUNTIME is smaller
+because it does not include support for the descriptor,
+reflection or extensions. Also, not currently supported
+are packed repeated elements nor testing of java_multiple_files.
+
+To create a jar file for the runtime and run tests invoke
+"mvn package -P micro" from the <protobuf-root>/java
+directory. The generated jar file is
+<protobuf-root>java/target/protobuf-java-2.2.0-micro.jar.
+
+If you wish to compile the MICRO_RUTIME your self, place
+the 7 files below, in <root>/com/google/protobuf and
+create a jar file for use with your code and the generated
+code:
+
+ByteStringMicro.java
+CodedInputStreamMicro.java
+CodedOutputStreamMicro.java
+InvalidProtocolBufferException.java
+MessageMicro.java
+StringUtf8Micro.java
+WireFormatMicro.java
+
+If you wish to change on the code generator it is located
+in /src/google/protobuf/compiler/javamicro.
+
+To generate code for the MICRO_RUNTIME invoke protoc with
+--javamicro_out command line parameter. javamciro_out takes
+a series of optional sub-parameters separated by comma's
+and a final parameter, with a colon separator, which defines
+the source directory. Sub-paraemeters begin with a name
+followed by an equal and if that sub-parameter has multiple
+parameters they are seperated by "|". The command line options
+are:
+
+opt                  -> speed or space
+java_use_vector      -> true or false
+java_package         -> <file-name>|<package-name>
+java_outer_classname -> <file-name>|<package-name>
+
+opt:
+  This change the code generation to optimize for speed,
+  opt=speed, or space, opt=space. When opt=speed this
+  changes the code generation for strings to use
+  StringUtf8Micro which eliminates multiple conversions
+  of the string to utf8. The default value is opt=space.
+
+java_use_vector:
+  Is a boolean flag either java_use_vector=true or
+  java_use_vector=false. When java_use_vector=true the
+  code generated for repeated elements uses
+  java.util.Vector and when java_use_vector=false the
+  java.util.ArrayList<> is used. When java.util.Vector
+  is used the code must be compiled with Java 1.3 and
+  when ArrayList is used Java 1.5 or above must be used.
+  The using javac the source parameter maybe used to
+  control the version of the srouce: "javac -source 1.3".
+  You can also change the <source> xml element for the
+  maven-compiler-plugin. Below is for 1.5 sources:
+
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.5</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+
+  When compiling for 1.5 java_use_vector=false or not
+  present where the default value is false.
+
+  And below would be for 1.3 sources note when changing
+  to 1.3 you must also set java_use_vector=true:
+
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <configuration>
+          <source>1.3</source>
+          <target>1.5</target>
+        </configuration>
+      </plugin>
+
+java_package:
+  The allows setting/overriding the java_package option
+  and associates allows a package name for a file to
+  be specified on the command line. Overriding any
+  "option java_package xxxx" in the file. The default
+  if not present is to use the value from the package
+  statment or "option java_package xxxx" in the file.
+
+java_outer_classname:
+  This allows the setting/overriding of the outer
+  class name option and associates a class name
+  to a file. An outer class name is required and
+  must be specified if there are multiple messages
+  in a single proto file either in the proto source
+  file or on the command line. If not present the
+  no outer class name will be used.
+
+Below are a series of examples for clarification of the
+various javamicro_out parameters using
+src/test/proto/simple-data.proto:
+
+package testprotobuf;
+
+message SimpleData {
+  optional fixed64 id = 1;
+  optional string description = 2;
+  optional bool ok = 3 [default = false];
+};
+
+
+Assuming you've only compiled and not installed protoc and
+your current working directory java/, then a simple
+command line to compile simple-data would be:
+
+../src/protoc --javamicro_out=. src/test/proto/simple-data.proto
+
+This will create testprotobuf/SimpleData.java
+
+The directory testprotobuf is created because on line 1
+of simple-data.proto is "package testprotobuf;". If you
+wanted a different package name you could use the
+java_package option command line sub-parameter:
+
+../src/protoc '--javamicro_out=java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto
+
+Here you see the new java_package sub-parameter which
+itself needs two parameters the file name and the
+package name, these are separated by "|". Now you'll
+find my_package/SimpleData.java.
+
+If you wanted to also change the optimization for
+speed you'd add opt=speed with the comma seperator
+as follows:
+
+../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package:.' src/test/proto/simple-data.proto
+
+Finally if you also wanted an outer class name you'd
+do the following:
+
+../src/protoc '--javamicro_out=opt=speed,java_package=src/test/proto/simple-data.proto|my_package,java_outer_classname=src/test/proto/simple-data.proto|OuterName:.' src/test/proto/simple-data.proto
+
+Now you'll find my_packate/OuterName.java.
+
+As mentioned java_package and java_outer_classname
+may also be specified in the file. In the example
+below we must define java_outer_classname because
+there are multiple messages in
+src/test/proto/two-messages.proto
+
+package testmicroruntime;
+
+option java_package = "com.example";
+option java_outer_classname = "TestMessages";
+
+message TestMessage1 {
+  required int32 id = 1;
+}
+
+message TestMessage2 {
+  required int32 id = 1;
+}
+
+This could be compiled using:
+
+../src/protoc --javamicro_out=. src/test/proto/two-message.proto
+
+With the result will be com/example/TestMessages.java
+
+
 Usage
 =====
 
diff --git a/java/pom.xml b/java/pom.xml
index b07f29b..a71a69a 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -96,6 +96,8 @@
             <configuration>
               <tasks>
                 <mkdir dir="target/generated-test-sources" />
+                <!--mkdir dir="target/generated-test-sources/opt-space" /-->
+                <!--mkdir dir="target/generated-test-sources/opt-speed" /-->
                 <exec executable="../src/protoc">
                   <arg value="--java_out=target/generated-test-sources" />
                   <arg value="--proto_path=../src" />
@@ -115,8 +117,20 @@
                   <arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
                   <arg value="../src/google/protobuf/unittest_no_generic_services.proto" />
                 </exec>
+                <exec executable="../src/protoc">
+                  <arg value="--javamicro_out=opt=speed,java_use_vector=false,java_package=google/protobuf/unittest_import_micro.proto|com.google.protobuf.micro,java_outer_classname=google/protobuf/unittest_import_micro.proto|UnittestImportMicro:target/generated-test-sources" />
+                  <arg value="--proto_path=../src" />
+                  <arg value="--proto_path=src/test/java" />
+                  <arg value="../src/google/protobuf/unittest_micro.proto" />
+                  <arg value="../src/google/protobuf/unittest_simple_micro.proto" />
+                  <arg value="../src/google/protobuf/unittest_stringutf8_micro.proto" />
+                  <arg value="../src/google/protobuf/unittest_recursive_micro.proto" />
+                  <arg value="../src/google/protobuf/unittest_import_micro.proto" />
+                </exec>
               </tasks>
               <testSourceRoot>target/generated-test-sources</testSourceRoot>
+              <!--testSourceRoot>target/generated-test-sources/opt-space</testSourceRoot-->
+              <!--testSourceRoot>target/generated-test-sources/opt-speed</testSourceRoot-->
             </configuration>
             <goals>
               <goal>run</goal>
@@ -171,5 +185,48 @@
         </plugins>
       </build>
     </profile>
+    <profile>
+      <id>micro</id>
+      <build>
+        <plugins>
+          <plugin>
+            <artifactId>maven-compiler-plugin</artifactId>
+            <configuration>
+              <includes>
+                <include>**/MessageMicro.java</include>
+                <include>**/ByteStringMicro.java</include>
+                <include>**/CodedInputStreamMicro.java</include>
+                <include>**/CodedOutputStreamMicro.java</include>
+                <include>**/InvalidProtocolBufferMicroException.java</include>
+                <include>**/StringUtf8Micro.java</include>
+                <include>**/WireFormatMicro.java</include>
+              </includes>
+              <testIncludes>
+                <testInclude>**/MicroTest.java</testInclude>
+                <testInclude>**/MicroOuterClass.java</testInclude>
+                <testInclude>**/SimpleMessageMicro.java</testInclude>
+                <testInclude>**/StringUtf8.java</testInclude>
+                <testInclude>**/RecursiveMessageMicro.java</testInclude>
+                <testInclude>**/UnittestImportMicro.java</testInclude>
+              </testIncludes>
+            </configuration>
+          </plugin>
+          <plugin>
+            <artifactId>maven-surefire-plugin</artifactId>
+            <configuration>
+              <includes>
+                <include>**/MicroTest.java</include>
+              </includes>
+            </configuration>
+          </plugin>
+          <plugin>
+            <artifactId>maven-jar-plugin</artifactId>
+            <configuration>
+              <classifier>micro</classifier>
+            </configuration>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
   </profiles>
 </project>
diff --git a/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java b/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java
new file mode 100644
index 0000000..6e87dc9
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/ByteStringMicro.java
@@ -0,0 +1,227 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Immutable array of bytes.
+ *
+ * @author crazybob@google.com Bob Lee
+ * @author kenton@google.com Kenton Varda
+ */
+public final class ByteStringMicro {
+  private final byte[] bytes;
+
+  private ByteStringMicro(final byte[] bytes) {
+    this.bytes = bytes;
+  }
+
+  /**
+   * Gets the byte at the given index.
+   *
+   * @throws ArrayIndexOutOfBoundsException {@code index} is < 0 or >= size
+   */
+  public byte byteAt(final int index) {
+    return bytes[index];
+  }
+
+  /**
+   * Gets the number of bytes.
+   */
+  public int size() {
+    return bytes.length;
+  }
+
+  /**
+   * Returns {@code true} if the size is {@code 0}, {@code false} otherwise.
+   */
+  public boolean isEmpty() {
+    return bytes.length == 0;
+  }
+
+  // =================================================================
+  // byte[] -> ByteStringMicro
+
+  /**
+   * Empty ByteStringMicro.
+   */
+  public static final ByteStringMicro EMPTY = new ByteStringMicro(new byte[0]);
+
+  /**
+   * Copies the given bytes into a {@code ByteStringMicro}.
+   */
+  public static ByteStringMicro copyFrom(final byte[] bytes, final int offset,
+                                    final int size) {
+    final byte[] copy = new byte[size];
+    System.arraycopy(bytes, offset, copy, 0, size);
+    return new ByteStringMicro(copy);
+  }
+
+  /**
+   * Copies the given bytes into a {@code ByteStringMicro}.
+   */
+  public static ByteStringMicro copyFrom(final byte[] bytes) {
+    return copyFrom(bytes, 0, bytes.length);
+  }
+
+  /**
+   * Encodes {@code text} into a sequence of bytes using the named charset
+   * and returns the result as a {@code ByteStringMicro}.
+   */
+  public static ByteStringMicro copyFrom(final String text, final String charsetName)
+      throws UnsupportedEncodingException {
+    return new ByteStringMicro(text.getBytes(charsetName));
+  }
+
+  /**
+   * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
+   * result as a {@code ByteStringMicro}.
+   */
+  public static ByteStringMicro copyFromUtf8(final String text) {
+    try {
+      return new ByteStringMicro(text.getBytes("UTF-8"));
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported?");
+    }
+  }
+
+  // =================================================================
+  // ByteStringMicro -> byte[]
+
+  /**
+   * Copies bytes into a buffer at the given offset.
+   *
+   * @param target buffer to copy into
+   * @param offset in the target buffer
+   */
+  public void copyTo(final byte[] target, final int offset) {
+    System.arraycopy(bytes, 0, target, offset, bytes.length);
+  }
+
+  /**
+   * Copies bytes into a buffer.
+   *
+   * @param target buffer to copy into
+   * @param sourceOffset offset within these bytes
+   * @param targetOffset offset within the target buffer
+   * @param size number of bytes to copy
+   */
+  public void copyTo(final byte[] target, final int sourceOffset,
+                     final int targetOffset,
+      final int size) {
+    System.arraycopy(bytes, sourceOffset, target, targetOffset, size);
+  }
+
+  /**
+   * Copies bytes to a {@code byte[]}.
+   */
+  public byte[] toByteArray() {
+    final int size = bytes.length;
+    final byte[] copy = new byte[size];
+    System.arraycopy(bytes, 0, copy, 0, size);
+    return copy;
+  }
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes using the
+   * specified charset.
+   */
+  public String toString(final String charsetName)
+      throws UnsupportedEncodingException {
+    return new String(bytes, charsetName);
+  }
+
+  /**
+   * Constructs a new {@code String} by decoding the bytes as UTF-8.
+   */
+  public String toStringUtf8() {
+    try {
+      return new String(bytes, "UTF-8");
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported?");
+    }
+  }
+
+  // =================================================================
+  // equals() and hashCode()
+
+  //@Override for compatibility with Java 1.3 code we can't use annotations
+  public boolean equals(final Object o) {
+    if (o == this) {
+      return true;
+    }
+
+    if (!(o instanceof ByteStringMicro)) {
+      return false;
+    }
+
+    final ByteStringMicro other = (ByteStringMicro) o;
+    final int size = bytes.length;
+    if (size != other.bytes.length) {
+      return false;
+    }
+
+    final byte[] thisBytes = bytes;
+    final byte[] otherBytes = other.bytes;
+    for (int i = 0; i < size; i++) {
+      if (thisBytes[i] != otherBytes[i]) {
+        return false;
+      }
+    }
+
+    return true;
+  }
+
+  private volatile int hash = 0;
+
+  //@Override for compatibility with Java 1.3 code we can't use annotations
+  public int hashCode() {
+    int h = hash;
+
+    if (h == 0) {
+      final byte[] thisBytes = bytes;
+      final int size = bytes.length;
+
+      h = size;
+      for (int i = 0; i < size; i++) {
+        h = h * 31 + thisBytes[i];
+      }
+      if (h == 0) {
+        h = 1;
+      }
+
+      hash = h;
+    }
+
+    return h;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java b/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java
new file mode 100644
index 0000000..0791b8f
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/CodedInputStreamMicro.java
@@ -0,0 +1,804 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Reads and decodes protocol message fields.
+ *
+ * This class contains two kinds of methods:  methods that read specific
+ * protocol message constructs and field types (e.g. {@link #readTag()} and
+ * {@link #readInt32()}) and methods that read low-level values (e.g.
+ * {@link #readRawVarint32()} and {@link #readRawBytes}).  If you are reading
+ * encoded protocol messages, you should use the former methods, but if you are
+ * reading some other format of your own design, use the latter.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class CodedInputStreamMicro {
+  /**
+   * Create a new CodedInputStream wrapping the given InputStream.
+   */
+  public static CodedInputStreamMicro newInstance(final InputStream input) {
+    return new CodedInputStreamMicro(input);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array.
+   */
+  public static CodedInputStreamMicro newInstance(final byte[] buf) {
+    return newInstance(buf, 0, buf.length);
+  }
+
+  /**
+   * Create a new CodedInputStream wrapping the given byte array slice.
+   */
+  public static CodedInputStreamMicro newInstance(final byte[] buf, final int off,
+                                             final int len) {
+    return new CodedInputStreamMicro(buf, off, len);
+  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Attempt to read a field tag, returning zero if we have reached EOF.
+   * Protocol message parsers use this to read tags, since a protocol message
+   * may legally end wherever a tag occurs, and zero is not a valid tag number.
+   */
+  public int readTag() throws IOException {
+    if (isAtEnd()) {
+      lastTag = 0;
+      return 0;
+    }
+
+    lastTag = readRawVarint32();
+    if (lastTag == 0) {
+      // If we actually read zero, that's not a valid tag.
+      throw InvalidProtocolBufferMicroException.invalidTag();
+    }
+    return lastTag;
+  }
+
+  /**
+   * Verifies that the last call to readTag() returned the given tag value.
+   * This is used to verify that a nested group ended with the correct
+   * end tag.
+   *
+   * @throws InvalidProtocolBufferMicroException {@code value} does not match the
+   *                                        last tag.
+   */
+  public void checkLastTagWas(final int value)
+                              throws InvalidProtocolBufferMicroException {
+    if (lastTag != value) {
+      throw InvalidProtocolBufferMicroException.invalidEndTag();
+    }
+  }
+
+  /**
+   * Reads and discards a single field, given its tag value.
+   *
+   * @return {@code false} if the tag is an endgroup tag, in which case
+   *         nothing is skipped.  Otherwise, returns {@code true}.
+   */
+  public boolean skipField(final int tag) throws IOException {
+    switch (WireFormatMicro.getTagWireType(tag)) {
+      case WireFormatMicro.WIRETYPE_VARINT:
+        readInt32();
+        return true;
+      case WireFormatMicro.WIRETYPE_FIXED64:
+        readRawLittleEndian64();
+        return true;
+      case WireFormatMicro.WIRETYPE_LENGTH_DELIMITED:
+        skipRawBytes(readRawVarint32());
+        return true;
+      case WireFormatMicro.WIRETYPE_START_GROUP:
+        skipMessage();
+        checkLastTagWas(
+          WireFormatMicro.makeTag(WireFormatMicro.getTagFieldNumber(tag),
+                             WireFormatMicro.WIRETYPE_END_GROUP));
+        return true;
+      case WireFormatMicro.WIRETYPE_END_GROUP:
+        return false;
+      case WireFormatMicro.WIRETYPE_FIXED32:
+        readRawLittleEndian32();
+        return true;
+      default:
+        throw InvalidProtocolBufferMicroException.invalidWireType();
+    }
+  }
+
+  /**
+   * Reads and discards an entire message.  This will read either until EOF
+   * or until an endgroup tag, whichever comes first.
+   */
+  public void skipMessage() throws IOException {
+    while (true) {
+      final int tag = readTag();
+      if (tag == 0 || !skipField(tag)) {
+        return;
+      }
+    }
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Read a {@code double} field value from the stream. */
+  public double readDouble() throws IOException {
+    return Double.longBitsToDouble(readRawLittleEndian64());
+  }
+
+  /** Read a {@code float} field value from the stream. */
+  public float readFloat() throws IOException {
+    return Float.intBitsToFloat(readRawLittleEndian32());
+  }
+
+  /** Read a {@code uint64} field value from the stream. */
+  public long readUInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int64} field value from the stream. */
+  public long readInt64() throws IOException {
+    return readRawVarint64();
+  }
+
+  /** Read an {@code int32} field value from the stream. */
+  public int readInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read a {@code fixed64} field value from the stream. */
+  public long readFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read a {@code fixed32} field value from the stream. */
+  public int readFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read a {@code bool} field value from the stream. */
+  public boolean readBool() throws IOException {
+    return readRawVarint32() != 0;
+  }
+
+  /** Read a {@code string} field value from the stream. */
+  public String readString() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final String result = new String(buffer, bufferPos, size, "UTF-8");
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return new String(readRawBytes(size), "UTF-8");
+    }
+  }
+
+  /** Read a {@code group} field value from the stream. */
+  public void readGroup(final MessageMicro msg, final int fieldNumber)
+      throws IOException {
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferMicroException.recursionLimitExceeded();
+    }
+    ++recursionDepth;
+    msg.mergeFrom(this);
+    checkLastTagWas(
+      WireFormatMicro.makeTag(fieldNumber, WireFormatMicro.WIRETYPE_END_GROUP));
+    --recursionDepth;
+  }
+
+  public void readMessage(final MessageMicro msg)
+      throws IOException {
+    final int length = readRawVarint32();
+    if (recursionDepth >= recursionLimit) {
+      throw InvalidProtocolBufferMicroException.recursionLimitExceeded();
+    }
+    final int oldLimit = pushLimit(length);
+    ++recursionDepth;
+    msg.mergeFrom(this);
+    checkLastTagWas(0);
+    --recursionDepth;
+    popLimit(oldLimit);
+  }
+
+  /** Read a {@code bytes} field value from the stream. */
+  public ByteStringMicro readBytes() throws IOException {
+    final int size = readRawVarint32();
+    if (size <= (bufferSize - bufferPos) && size > 0) {
+      // Fast path:  We already have the bytes in a contiguous buffer, so
+      //   just copy directly from it.
+      final ByteStringMicro result = ByteStringMicro.copyFrom(buffer, bufferPos, size);
+      bufferPos += size;
+      return result;
+    } else {
+      // Slow path:  Build a byte array first then copy it.
+      return ByteStringMicro.copyFrom(readRawBytes(size));
+    }
+  }
+
+  /** Read a {@code uint32} field value from the stream. */
+  public int readUInt32() throws IOException {
+    return readRawVarint32();
+  }
+
+  /**
+   * Read an enum field value from the stream.  Caller is responsible
+   * for converting the numeric value to an actual enum.
+   */
+  public int readEnum() throws IOException {
+    return readRawVarint32();
+  }
+
+  /** Read an {@code sfixed32} field value from the stream. */
+  public int readSFixed32() throws IOException {
+    return readRawLittleEndian32();
+  }
+
+  /** Read an {@code sfixed64} field value from the stream. */
+  public long readSFixed64() throws IOException {
+    return readRawLittleEndian64();
+  }
+
+  /** Read an {@code sint32} field value from the stream. */
+  public int readSInt32() throws IOException {
+    return decodeZigZag32(readRawVarint32());
+  }
+
+  /** Read an {@code sint64} field value from the stream. */
+  public long readSInt64() throws IOException {
+    return decodeZigZag64(readRawVarint64());
+  }
+
+  // =================================================================
+
+  /**
+   * Read a raw Varint from the stream.  If larger than 32 bits, discard the
+   * upper bits.
+   */
+  public int readRawVarint32() throws IOException {
+    byte tmp = readRawByte();
+    if (tmp >= 0) {
+      return tmp;
+    }
+    int result = tmp & 0x7f;
+    if ((tmp = readRawByte()) >= 0) {
+      result |= tmp << 7;
+    } else {
+      result |= (tmp & 0x7f) << 7;
+      if ((tmp = readRawByte()) >= 0) {
+        result |= tmp << 14;
+      } else {
+        result |= (tmp & 0x7f) << 14;
+        if ((tmp = readRawByte()) >= 0) {
+          result |= tmp << 21;
+        } else {
+          result |= (tmp & 0x7f) << 21;
+          result |= (tmp = readRawByte()) << 28;
+          if (tmp < 0) {
+            // Discard upper 32 bits.
+            for (int i = 0; i < 5; i++) {
+              if (readRawByte() >= 0) {
+                return result;
+              }
+            }
+            throw InvalidProtocolBufferMicroException.malformedVarint();
+          }
+        }
+      }
+    }
+    return result;
+  }
+
+  /**
+   * Reads a varint from the input one byte at a time, so that it does not
+   * read any bytes after the end of the varint.  If you simply wrapped the
+   * stream in a CodedInputStream and used {@link #readRawVarint32(InputStream)}
+   * then you would probably end up reading past the end of the varint since
+   * CodedInputStream buffers its input.
+   */
+  static int readRawVarint32(final InputStream input) throws IOException {
+    int result = 0;
+    int offset = 0;
+    for (; offset < 32; offset += 7) {
+      final int b = input.read();
+      if (b == -1) {
+        throw InvalidProtocolBufferMicroException.truncatedMessage();
+      }
+      result |= (b & 0x7f) << offset;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+    }
+    // Keep reading up to 64 bits.
+    for (; offset < 64; offset += 7) {
+      final int b = input.read();
+      if (b == -1) {
+        throw InvalidProtocolBufferMicroException.truncatedMessage();
+      }
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+    }
+    throw InvalidProtocolBufferMicroException.malformedVarint();
+  }
+
+  /** Read a raw Varint from the stream. */
+  public long readRawVarint64() throws IOException {
+    int shift = 0;
+    long result = 0;
+    while (shift < 64) {
+      final byte b = readRawByte();
+      result |= (long)(b & 0x7F) << shift;
+      if ((b & 0x80) == 0) {
+        return result;
+      }
+      shift += 7;
+    }
+    throw InvalidProtocolBufferMicroException.malformedVarint();
+  }
+
+  /** Read a 32-bit little-endian integer from the stream. */
+  public int readRawLittleEndian32() throws IOException {
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
+    return ((b1 & 0xff)      ) |
+           ((b2 & 0xff) <<  8) |
+           ((b3 & 0xff) << 16) |
+           ((b4 & 0xff) << 24);
+  }
+
+  /** Read a 64-bit little-endian integer from the stream. */
+  public long readRawLittleEndian64() throws IOException {
+    final byte b1 = readRawByte();
+    final byte b2 = readRawByte();
+    final byte b3 = readRawByte();
+    final byte b4 = readRawByte();
+    final byte b5 = readRawByte();
+    final byte b6 = readRawByte();
+    final byte b7 = readRawByte();
+    final byte b8 = readRawByte();
+    return (((long)b1 & 0xff)      ) |
+           (((long)b2 & 0xff) <<  8) |
+           (((long)b3 & 0xff) << 16) |
+           (((long)b4 & 0xff) << 24) |
+           (((long)b5 & 0xff) << 32) |
+           (((long)b6 & 0xff) << 40) |
+           (((long)b7 & 0xff) << 48) |
+           (((long)b8 & 0xff) << 56);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 32-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 32-bit integer.
+   */
+  public static int decodeZigZag32(final int n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  /**
+   * Decode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n An unsigned 64-bit integer, stored in a signed int because
+   *          Java has no explicit unsigned support.
+   * @return A signed 64-bit integer.
+   */
+  public static long decodeZigZag64(final long n) {
+    return (n >>> 1) ^ -(n & 1);
+  }
+
+  // -----------------------------------------------------------------
+
+  private final byte[] buffer;
+  private int bufferSize;
+  private int bufferSizeAfterLimit;
+  private int bufferPos;
+  private final InputStream input;
+  private int lastTag;
+
+  /**
+   * The total number of bytes read before the current buffer.  The total
+   * bytes read up to the current position can be computed as
+   * {@code totalBytesRetired + bufferPos}.
+   */
+  private int totalBytesRetired;
+
+  /** The absolute position of the end of the current message. */
+  private int currentLimit = Integer.MAX_VALUE;
+
+  /** See setRecursionLimit() */
+  private int recursionDepth;
+  private int recursionLimit = DEFAULT_RECURSION_LIMIT;
+
+  /** See setSizeLimit() */
+  private int sizeLimit = DEFAULT_SIZE_LIMIT;
+
+  private static final int DEFAULT_RECURSION_LIMIT = 64;
+  private static final int DEFAULT_SIZE_LIMIT = 64 << 20;  // 64MB
+  private static final int BUFFER_SIZE = 4096;
+
+  private CodedInputStreamMicro(final byte[] buffer, final int off, final int len) {
+    this.buffer = buffer;
+    bufferSize = off + len;
+    bufferPos = off;
+    input = null;
+  }
+
+  private CodedInputStreamMicro(final InputStream input) {
+    buffer = new byte[BUFFER_SIZE];
+    bufferSize = 0;
+    bufferPos = 0;
+    this.input = input;
+  }
+
+  /**
+   * Set the maximum message recursion depth.  In order to prevent malicious
+   * messages from causing stack overflows, {@code CodedInputStream} limits
+   * how deeply messages may be nested.  The default limit is 64.
+   *
+   * @return the old limit.
+   */
+  public int setRecursionLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Recursion limit cannot be negative: " + limit);
+    }
+    final int oldLimit = recursionLimit;
+    recursionLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Set the maximum message size.  In order to prevent malicious
+   * messages from exhausting memory or causing integer overflows,
+   * {@code CodedInputStream} limits how large a message may be.
+   * The default limit is 64MB.  You should set this limit as small
+   * as you can without harming your app's functionality.  Note that
+   * size limits only apply when reading from an {@code InputStream}, not
+   * when constructed around a raw byte array (nor with
+   * {@link ByteStringMicro#newCodedInput}).
+   * <p>
+   * If you want to read several messages from a single CodedInputStream, you
+   * could call {@link #resetSizeCounter()} after each one to avoid hitting the
+   * size limit.
+   *
+   * @return the old limit.
+   */
+  public int setSizeLimit(final int limit) {
+    if (limit < 0) {
+      throw new IllegalArgumentException(
+        "Size limit cannot be negative: " + limit);
+    }
+    final int oldLimit = sizeLimit;
+    sizeLimit = limit;
+    return oldLimit;
+  }
+
+  /**
+   * Resets the current size counter to zero (see {@link #setSizeLimit(int)}).
+   */
+  public void resetSizeCounter() {
+    totalBytesRetired = 0;
+  }
+
+  /**
+   * Sets {@code currentLimit} to (current position) + {@code byteLimit}.  This
+   * is called when descending into a length-delimited embedded message.
+   *
+   * @return the old limit.
+   */
+  public int pushLimit(int byteLimit) throws InvalidProtocolBufferMicroException {
+    if (byteLimit < 0) {
+      throw InvalidProtocolBufferMicroException.negativeSize();
+    }
+    byteLimit += totalBytesRetired + bufferPos;
+    final int oldLimit = currentLimit;
+    if (byteLimit > oldLimit) {
+      throw InvalidProtocolBufferMicroException.truncatedMessage();
+    }
+    currentLimit = byteLimit;
+
+    recomputeBufferSizeAfterLimit();
+
+    return oldLimit;
+  }
+
+  private void recomputeBufferSizeAfterLimit() {
+    bufferSize += bufferSizeAfterLimit;
+    final int bufferEnd = totalBytesRetired + bufferSize;
+    if (bufferEnd > currentLimit) {
+      // Limit is in current buffer.
+      bufferSizeAfterLimit = bufferEnd - currentLimit;
+      bufferSize -= bufferSizeAfterLimit;
+    } else {
+      bufferSizeAfterLimit = 0;
+    }
+  }
+
+  /**
+   * Discards the current limit, returning to the previous limit.
+   *
+   * @param oldLimit The old limit, as returned by {@code pushLimit}.
+   */
+  public void popLimit(final int oldLimit) {
+    currentLimit = oldLimit;
+    recomputeBufferSizeAfterLimit();
+  }
+
+  /**
+   * Returns the number of bytes to be read before the current limit.
+   * If no limit is set, returns -1.
+   */
+  public int getBytesUntilLimit() {
+    if (currentLimit == Integer.MAX_VALUE) {
+      return -1;
+    }
+
+    final int currentAbsolutePosition = totalBytesRetired + bufferPos;
+    return currentLimit - currentAbsolutePosition;
+  }
+
+  /**
+   * Returns true if the stream has reached the end of the input.  This is the
+   * case if either the end of the underlying input source has been reached or
+   * if the stream has reached a limit created using {@link #pushLimit(int)}.
+   */
+  public boolean isAtEnd() throws IOException {
+    return bufferPos == bufferSize && !refillBuffer(false);
+  }
+
+  /**
+   * Called with {@code this.buffer} is empty to read more bytes from the
+   * input.  If {@code mustSucceed} is true, refillBuffer() gurantees that
+   * either there will be at least one byte in the buffer when it returns
+   * or it will throw an exception.  If {@code mustSucceed} is false,
+   * refillBuffer() returns false if no more bytes were available.
+   */
+  private boolean refillBuffer(final boolean mustSucceed) throws IOException {
+    if (bufferPos < bufferSize) {
+      throw new IllegalStateException(
+        "refillBuffer() called when buffer wasn't empty.");
+    }
+
+    if (totalBytesRetired + bufferSize == currentLimit) {
+      // Oops, we hit a limit.
+      if (mustSucceed) {
+        throw InvalidProtocolBufferMicroException.truncatedMessage();
+      } else {
+        return false;
+      }
+    }
+
+    totalBytesRetired += bufferSize;
+
+    bufferPos = 0;
+    bufferSize = (input == null) ? -1 : input.read(buffer);
+    if (bufferSize == 0 || bufferSize < -1) {
+      throw new IllegalStateException(
+          "InputStream#read(byte[]) returned invalid result: " + bufferSize +
+          "\nThe InputStream implementation is buggy.");
+    }
+    if (bufferSize == -1) {
+      bufferSize = 0;
+      if (mustSucceed) {
+        throw InvalidProtocolBufferMicroException.truncatedMessage();
+      } else {
+        return false;
+      }
+    } else {
+      recomputeBufferSizeAfterLimit();
+      final int totalBytesRead =
+        totalBytesRetired + bufferSize + bufferSizeAfterLimit;
+      if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
+        throw InvalidProtocolBufferMicroException.sizeLimitExceeded();
+      }
+      return true;
+    }
+  }
+
+  /**
+   * Read one byte from the input.
+   *
+   * @throws InvalidProtocolBufferMicroException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte readRawByte() throws IOException {
+    if (bufferPos == bufferSize) {
+      refillBuffer(true);
+    }
+    return buffer[bufferPos++];
+  }
+
+  /**
+   * Read a fixed size of bytes from the input.
+   *
+   * @throws InvalidProtocolBufferMicroException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public byte[] readRawBytes(final int size) throws IOException {
+    if (size < 0) {
+      throw InvalidProtocolBufferMicroException.negativeSize();
+    }
+
+    if (totalBytesRetired + bufferPos + size > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+      // Then fail.
+      throw InvalidProtocolBufferMicroException.truncatedMessage();
+    }
+
+    if (size <= bufferSize - bufferPos) {
+      // We have all the bytes we need already.
+      final byte[] bytes = new byte[size];
+      System.arraycopy(buffer, bufferPos, bytes, 0, size);
+      bufferPos += size;
+      return bytes;
+    } else if (size < BUFFER_SIZE) {
+      // Reading more bytes than are in the buffer, but not an excessive number
+      // of bytes.  We can safely allocate the resulting array ahead of time.
+
+      // First copy what we have.
+      final byte[] bytes = new byte[size];
+      int pos = bufferSize - bufferPos;
+      System.arraycopy(buffer, bufferPos, bytes, 0, pos);
+      bufferPos = bufferSize;
+
+      // We want to use refillBuffer() and then copy from the buffer into our
+      // byte array rather than reading directly into our byte array because
+      // the input may be unbuffered.
+      refillBuffer(true);
+
+      while (size - pos > bufferSize) {
+        System.arraycopy(buffer, 0, bytes, pos, bufferSize);
+        pos += bufferSize;
+        bufferPos = bufferSize;
+        refillBuffer(true);
+      }
+
+      System.arraycopy(buffer, 0, bytes, pos, size - pos);
+      bufferPos = size - pos;
+
+      return bytes;
+    } else {
+      // The size is very large.  For security reasons, we can't allocate the
+      // entire byte array yet.  The size comes directly from the input, so a
+      // maliciously-crafted message could provide a bogus very large size in
+      // order to trick the app into allocating a lot of memory.  We avoid this
+      // by allocating and reading only a small chunk at a time, so that the
+      // malicious message must actually *be* extremely large to cause
+      // problems.  Meanwhile, we limit the allowed size of a message elsewhere.
+
+      // Remember the buffer markers since we'll have to copy the bytes out of
+      // it later.
+      final int originalBufferPos = bufferPos;
+      final int originalBufferSize = bufferSize;
+
+      // Mark the current buffer consumed.
+      totalBytesRetired += bufferSize;
+      bufferPos = 0;
+      bufferSize = 0;
+
+      // Read all the rest of the bytes we need.
+      int sizeLeft = size - (originalBufferSize - originalBufferPos);
+
+      // For compatibility with Java 1.3 use Vector
+      final java.util.Vector chunks = new java.util.Vector();
+
+      while (sizeLeft > 0) {
+        final byte[] chunk = new byte[Math.min(sizeLeft, BUFFER_SIZE)];
+        int pos = 0;
+        while (pos < chunk.length) {
+          final int n = (input == null) ? -1 :
+            input.read(chunk, pos, chunk.length - pos);
+          if (n == -1) {
+            throw InvalidProtocolBufferMicroException.truncatedMessage();
+          }
+          totalBytesRetired += n;
+          pos += n;
+        }
+        sizeLeft -= chunk.length;
+        chunks.addElement(chunk);
+      }
+
+      // OK, got everything.  Now concatenate it all into one buffer.
+      final byte[] bytes = new byte[size];
+
+      // Start by copying the leftover bytes from this.buffer.
+      int pos = originalBufferSize - originalBufferPos;
+      System.arraycopy(buffer, originalBufferPos, bytes, 0, pos);
+
+      // And now all the chunks.
+      for (int i = 0; i < chunks.size(); i++) {
+        byte [] chunk = (byte [])chunks.elementAt(i);
+        System.arraycopy(chunk, 0, bytes, pos, chunk.length);
+        pos += chunk.length;
+      }
+
+      // Done.
+      return bytes;
+    }
+  }
+
+  /**
+   * Reads and discards {@code size} bytes.
+   *
+   * @throws InvalidProtocolBufferMicroException The end of the stream or the current
+   *                                        limit was reached.
+   */
+  public void skipRawBytes(final int size) throws IOException {
+    if (size < 0) {
+      throw InvalidProtocolBufferMicroException.negativeSize();
+    }
+
+    if (totalBytesRetired + bufferPos + size > currentLimit) {
+      // Read to the end of the stream anyway.
+      skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+      // Then fail.
+      throw InvalidProtocolBufferMicroException.truncatedMessage();
+    }
+
+    if (size <= bufferSize - bufferPos) {
+      // We have all the bytes we need already.
+      bufferPos += size;
+    } else {
+      // Skipping more bytes than are in the buffer.  First skip what we have.
+      int pos = bufferSize - bufferPos;
+      totalBytesRetired += pos;
+      bufferPos = 0;
+      bufferSize = 0;
+
+      // Then skip directly from the InputStream for the rest.
+      while (pos < size) {
+        final int n = (input == null) ? -1 : (int) input.skip(size - pos);
+        if (n <= 0) {
+          throw InvalidProtocolBufferMicroException.truncatedMessage();
+        }
+        pos += n;
+        totalBytesRetired += n;
+      }
+    }
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java b/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java
new file mode 100644
index 0000000..68b6e97
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/CodedOutputStreamMicro.java
@@ -0,0 +1,996 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Encodes and writes protocol message fields.
+ *
+ * <p>This class contains two kinds of methods:  methods that write specific
+ * protocol message constructs and field types (e.g. {@link #writeTag} and
+ * {@link #writeInt32}) and methods that write low-level values (e.g.
+ * {@link #writeRawVarint32} and {@link #writeRawBytes}).  If you are
+ * writing encoded protocol messages, you should use the former methods, but if
+ * you are writing some other format of your own design, use the latter.
+ *
+ * <p>This class is totally unsynchronized.
+ *
+ * @author kneton@google.com Kenton Varda
+ */
+public final class CodedOutputStreamMicro {
+  private final byte[] buffer;
+  private final int limit;
+  private int position;
+
+  private final OutputStream output;
+
+  /**
+   * The buffer size used in {@link #newInstance(OutputStream)}.
+   */
+  public static final int DEFAULT_BUFFER_SIZE = 4096;
+
+  private CodedOutputStreamMicro(final byte[] buffer, final int offset,
+                            final int length) {
+    output = null;
+    this.buffer = buffer;
+    position = offset;
+    limit = offset + length;
+  }
+
+  private CodedOutputStreamMicro(final OutputStream output, final byte[] buffer) {
+    this.output = output;
+    this.buffer = buffer;
+    position = 0;
+    limit = buffer.length;
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} wrapping the given
+   * {@code OutputStream}.
+   */
+  public static CodedOutputStreamMicro newInstance(final OutputStream output) {
+    return newInstance(output, DEFAULT_BUFFER_SIZE);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} wrapping the given
+   * {@code OutputStream} with a given buffer size.
+   */
+  public static CodedOutputStreamMicro newInstance(final OutputStream output,
+      final int bufferSize) {
+    return new CodedOutputStreamMicro(output, new byte[bufferSize]);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array.  If more bytes are written than fit in the array,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.
+   */
+  public static CodedOutputStreamMicro newInstance(final byte[] flatArray) {
+    return newInstance(flatArray, 0, flatArray.length);
+  }
+
+  /**
+   * Create a new {@code CodedOutputStream} that writes directly to the given
+   * byte array slice.  If more bytes are written than fit in the slice,
+   * {@link OutOfSpaceException} will be thrown.  Writing directly to a flat
+   * array is faster than writing to an {@code OutputStream}.
+   */
+  public static CodedOutputStreamMicro newInstance(final byte[] flatArray,
+                                              final int offset,
+                                              final int length) {
+    return new CodedOutputStreamMicro(flatArray, offset, length);
+  }
+
+  // -----------------------------------------------------------------
+
+  /** Write a {@code double} field, including tag, to the stream. */
+  public void writeDouble(final int fieldNumber, final double value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64);
+    writeDoubleNoTag(value);
+  }
+
+  /** Write a {@code float} field, including tag, to the stream. */
+  public void writeFloat(final int fieldNumber, final float value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32);
+    writeFloatNoTag(value);
+  }
+
+  /** Write a {@code uint64} field, including tag, to the stream. */
+  public void writeUInt64(final int fieldNumber, final long value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeUInt64NoTag(value);
+  }
+
+  /** Write an {@code int64} field, including tag, to the stream. */
+  public void writeInt64(final int fieldNumber, final long value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeInt64NoTag(value);
+  }
+
+  /** Write an {@code int32} field, including tag, to the stream. */
+  public void writeInt32(final int fieldNumber, final int value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeInt32NoTag(value);
+  }
+
+  /** Write a {@code fixed64} field, including tag, to the stream. */
+  public void writeFixed64(final int fieldNumber, final long value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64);
+    writeFixed64NoTag(value);
+  }
+
+  /** Write a {@code fixed32} field, including tag, to the stream. */
+  public void writeFixed32(final int fieldNumber, final int value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32);
+    writeFixed32NoTag(value);
+  }
+
+  /** Write a {@code bool} field, including tag, to the stream. */
+  public void writeBool(final int fieldNumber, final boolean value)
+                        throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeBoolNoTag(value);
+  }
+
+  /** Write a {@code string} field, including tag, to the stream. */
+  public void writeString(final int fieldNumber, final String value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED);
+    writeStringNoTag(value);
+  }
+
+  /** Write a {@code StringUtf8Micro} field, including tag, to the stream. */
+  public void writeStringUtf8(final int fieldNumber, final StringUtf8Micro value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED);
+    writeStringUtf8NoTag(value);
+  }
+
+  /** Write a {@code group} field, including tag, to the stream. */
+  public void writeGroup(final int fieldNumber, final MessageMicro value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_START_GROUP);
+    writeGroupNoTag(value);
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_END_GROUP);
+  }
+
+  /** Write an embedded message field, including tag, to the stream. */
+  public void writeMessage(final int fieldNumber, final MessageMicro value)
+                           throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED);
+    writeMessageNoTag(value);
+  }
+
+  /** Write a {@code bytes} field, including tag, to the stream. */
+  public void writeBytes(final int fieldNumber, final ByteStringMicro value)
+                         throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_LENGTH_DELIMITED);
+    writeBytesNoTag(value);
+  }
+
+  /** Write a {@code uint32} field, including tag, to the stream. */
+  public void writeUInt32(final int fieldNumber, final int value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeUInt32NoTag(value);
+  }
+
+  /**
+   * Write an enum field, including tag, to the stream.  Caller is responsible
+   * for converting the enum value to its numeric value.
+   */
+  public void writeEnum(final int fieldNumber, final int value)
+                        throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeEnumNoTag(value);
+  }
+
+  /** Write an {@code sfixed32} field, including tag, to the stream. */
+  public void writeSFixed32(final int fieldNumber, final int value)
+                            throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED32);
+    writeSFixed32NoTag(value);
+  }
+
+  /** Write an {@code sfixed64} field, including tag, to the stream. */
+  public void writeSFixed64(final int fieldNumber, final long value)
+                            throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_FIXED64);
+    writeSFixed64NoTag(value);
+  }
+
+  /** Write an {@code sint32} field, including tag, to the stream. */
+  public void writeSInt32(final int fieldNumber, final int value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeSInt32NoTag(value);
+  }
+
+  /** Write an {@code sint64} field, including tag, to the stream. */
+  public void writeSInt64(final int fieldNumber, final long value)
+                          throws IOException {
+    writeTag(fieldNumber, WireFormatMicro.WIRETYPE_VARINT);
+    writeSInt64NoTag(value);
+  }
+
+  /**
+   * Write a MessageSet extension field to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+//  public void writeMessageSetExtension(final int fieldNumber,
+//                                       final MessageMicro value)
+//                                       throws IOException {
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+//    writeMessage(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+//  }
+
+  /**
+   * Write an unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+//  public void writeRawMessageSetExtension(final int fieldNumber,
+//                                          final ByteStringMicro value)
+//                                          throws IOException {
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_START_GROUP);
+//    writeUInt32(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber);
+//    writeBytes(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//    writeTag(WireFormatMicro.MESSAGE_SET_ITEM, WireFormatMicro.WIRETYPE_END_GROUP);
+//  }
+
+  // -----------------------------------------------------------------
+
+  /** Write a {@code double} field to the stream. */
+  public void writeDoubleNoTag(final double value) throws IOException {
+    writeRawLittleEndian64(Double.doubleToLongBits(value));
+  }
+
+  /** Write a {@code float} field to the stream. */
+  public void writeFloatNoTag(final float value) throws IOException {
+    writeRawLittleEndian32(Float.floatToIntBits(value));
+  }
+
+  /** Write a {@code uint64} field to the stream. */
+  public void writeUInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(value);
+  }
+
+  /** Write an {@code int64} field to the stream. */
+  public void writeInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(value);
+  }
+
+  /** Write an {@code int32} field to the stream. */
+  public void writeInt32NoTag(final int value) throws IOException {
+    if (value >= 0) {
+      writeRawVarint32(value);
+    } else {
+      // Must sign-extend.
+      writeRawVarint64(value);
+    }
+  }
+
+  /** Write a {@code fixed64} field to the stream. */
+  public void writeFixed64NoTag(final long value) throws IOException {
+    writeRawLittleEndian64(value);
+  }
+
+  /** Write a {@code fixed32} field to the stream. */
+  public void writeFixed32NoTag(final int value) throws IOException {
+    writeRawLittleEndian32(value);
+  }
+
+  /** Write a {@code bool} field to the stream. */
+  public void writeBoolNoTag(final boolean value) throws IOException {
+    writeRawByte(value ? 1 : 0);
+  }
+
+  /** Write a {@code string} field to the stream. */
+  public void writeStringNoTag(final String value) throws IOException {
+    // Unfortunately there does not appear to be any way to tell Java to encode
+    // UTF-8 directly into our buffer, so we have to let it create its own byte
+    // array and then copy.
+    final byte[] bytes = value.getBytes("UTF-8");
+    writeRawVarint32(bytes.length);
+    writeRawBytes(bytes);
+  }
+
+  /** Write a {@code StringUtf8Micro} field to the stream. */
+  public void writeStringUtf8NoTag(final StringUtf8Micro value) throws IOException {
+    final byte[] bytes = value.getBytes();
+    writeRawVarint32(bytes.length);
+    writeRawBytes(bytes);
+  }
+
+  /** Write a {@code group} field to the stream. */
+  public void writeGroupNoTag(final MessageMicro value) throws IOException {
+    value.writeTo(this);
+  }
+
+  /** Write an embedded message field to the stream. */
+  public void writeMessageNoTag(final MessageMicro value) throws IOException {
+    writeRawVarint32(value.getCachedSize());
+    value.writeTo(this);
+  }
+
+  /** Write a {@code bytes} field to the stream. */
+  public void writeBytesNoTag(final ByteStringMicro value) throws IOException {
+    final byte[] bytes = value.toByteArray();
+    writeRawVarint32(bytes.length);
+    writeRawBytes(bytes);
+  }
+
+  /** Write a {@code uint32} field to the stream. */
+  public void writeUInt32NoTag(final int value) throws IOException {
+    writeRawVarint32(value);
+  }
+
+  /**
+   * Write an enum field to the stream.  Caller is responsible
+   * for converting the enum value to its numeric value.
+   */
+  public void writeEnumNoTag(final int value) throws IOException {
+    writeRawVarint32(value);
+  }
+
+  /** Write an {@code sfixed32} field to the stream. */
+  public void writeSFixed32NoTag(final int value) throws IOException {
+    writeRawLittleEndian32(value);
+  }
+
+  /** Write an {@code sfixed64} field to the stream. */
+  public void writeSFixed64NoTag(final long value) throws IOException {
+    writeRawLittleEndian64(value);
+  }
+
+  /** Write an {@code sint32} field to the stream. */
+  public void writeSInt32NoTag(final int value) throws IOException {
+    writeRawVarint32(encodeZigZag32(value));
+  }
+
+  /** Write an {@code sint64} field to the stream. */
+  public void writeSInt64NoTag(final long value) throws IOException {
+    writeRawVarint64(encodeZigZag64(value));
+  }
+
+  // =================================================================
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSize(final int fieldNumber,
+                                      final double value) {
+    return computeTagSize(fieldNumber) + computeDoubleSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSize(final int fieldNumber, final float value) {
+    return computeTagSize(fieldNumber) + computeFloatSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeUInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field, including tag.
+   */
+  public static int computeFixed64Size(final int fieldNumber,
+                                       final long value) {
+    return computeTagSize(fieldNumber) + computeFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field, including tag.
+   */
+  public static int computeFixed32Size(final int fieldNumber,
+                                       final int value) {
+    return computeTagSize(fieldNumber) + computeFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field, including tag.
+   */
+  public static int computeBoolSize(final int fieldNumber,
+                                    final boolean value) {
+    return computeTagSize(fieldNumber) + computeBoolSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field, including tag.
+   */
+  public static int computeStringSize(final int fieldNumber,
+                                      final String value) {
+    return computeTagSize(fieldNumber) + computeStringSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code StringUtf8Micro} field, including tag.
+   */
+  public static int computeStringUtf8Size(final int fieldNumber,
+                                      final StringUtf8Micro value) {
+    return computeTagSize(fieldNumber) + computeStringUtf8SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field, including tag.
+   */
+  public static int computeGroupSize(final int fieldNumber,
+                                     final MessageMicro value) {
+    return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * embedded message field, including tag.
+   */
+  public static int computeMessageSize(final int fieldNumber,
+                                       final MessageMicro value) {
+    return computeTagSize(fieldNumber) + computeMessageSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field, including tag.
+   */
+  public static int computeBytesSize(final int fieldNumber,
+                                     final ByteStringMicro value) {
+    return computeTagSize(fieldNumber) + computeBytesSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field, including tag.
+   */
+  public static int computeUInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeUInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * enum field, including tag.  Caller is responsible for converting the
+   * enum value to its numeric value.
+   */
+  public static int computeEnumSize(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeEnumSizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field, including tag.
+   */
+  public static int computeSFixed32Size(final int fieldNumber,
+                                        final int value) {
+    return computeTagSize(fieldNumber) + computeSFixed32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field, including tag.
+   */
+  public static int computeSFixed64Size(final int fieldNumber,
+                                        final long value) {
+    return computeTagSize(fieldNumber) + computeSFixed64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field, including tag.
+   */
+  public static int computeSInt32Size(final int fieldNumber, final int value) {
+    return computeTagSize(fieldNumber) + computeSInt32SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field, including tag.
+   */
+  public static int computeSInt64Size(final int fieldNumber, final long value) {
+    return computeTagSize(fieldNumber) + computeSInt64SizeNoTag(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * MessageSet extension to the stream.  For historical reasons,
+   * the wire format differs from normal fields.
+   */
+//  public static int computeMessageSetExtensionSize(
+//      final int fieldNumber, final MessageMicro value) {
+//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+//           computeMessageSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * unparsed MessageSet extension field to the stream.  For
+   * historical reasons, the wire format differs from normal fields.
+   */
+//  public static int computeRawMessageSetExtensionSize(
+//      final int fieldNumber, final ByteStringMicro value) {
+//    return computeTagSize(WireFormatMicro.MESSAGE_SET_ITEM) * 2 +
+//           computeUInt32Size(WireFormatMicro.MESSAGE_SET_TYPE_ID, fieldNumber) +
+//           computeBytesSize(WireFormatMicro.MESSAGE_SET_MESSAGE, value);
+//  }
+
+  // -----------------------------------------------------------------
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code double} field, including tag.
+   */
+  public static int computeDoubleSizeNoTag(final double value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code float} field, including tag.
+   */
+  public static int computeFloatSizeNoTag(final float value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint64} field, including tag.
+   */
+  public static int computeUInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int64} field, including tag.
+   */
+  public static int computeInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code int32} field, including tag.
+   */
+  public static int computeInt32SizeNoTag(final int value) {
+    if (value >= 0) {
+      return computeRawVarint32Size(value);
+    } else {
+      // Must sign-extend.
+      return 10;
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed64} field.
+   */
+  public static int computeFixed64SizeNoTag(final long value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code fixed32} field.
+   */
+  public static int computeFixed32SizeNoTag(final int value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bool} field.
+   */
+  public static int computeBoolSizeNoTag(final boolean value) {
+    return 1;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code string} field.
+   */
+  public static int computeStringSizeNoTag(final String value) {
+    try {
+      final byte[] bytes = value.getBytes("UTF-8");
+      return computeRawVarint32Size(bytes.length) +
+             bytes.length;
+    } catch (UnsupportedEncodingException e) {
+      throw new RuntimeException("UTF-8 not supported.");
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code StringUtf8Micro} field.
+   */
+  public static int computeStringUtf8SizeNoTag(final StringUtf8Micro value) {
+    final byte[] bytes = value.getBytes();
+    return computeRawVarint32Size(bytes.length) +
+             bytes.length;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code group} field.
+   */
+  public static int computeGroupSizeNoTag(final MessageMicro value) {
+    return value.getCachedSize();
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an embedded
+   * message field.
+   */
+  public static int computeMessageSizeNoTag(final MessageMicro value) {
+    final int size = value.getCachedSize();
+    return computeRawVarint32Size(size) + size;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code bytes} field.
+   */
+  public static int computeBytesSizeNoTag(final ByteStringMicro value) {
+    return computeRawVarint32Size(value.size()) +
+           value.size();
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a
+   * {@code uint32} field.
+   */
+  public static int computeUInt32SizeNoTag(final int value) {
+    return computeRawVarint32Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an enum field.
+   * Caller is responsible for converting the enum value to its numeric value.
+   */
+  public static int computeEnumSizeNoTag(final int value) {
+    return computeRawVarint32Size(value);
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed32} field.
+   */
+  public static int computeSFixed32SizeNoTag(final int value) {
+    return LITTLE_ENDIAN_32_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sfixed64} field.
+   */
+  public static int computeSFixed64SizeNoTag(final long value) {
+    return LITTLE_ENDIAN_64_SIZE;
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint32} field.
+   */
+  public static int computeSInt32SizeNoTag(final int value) {
+    return computeRawVarint32Size(encodeZigZag32(value));
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode an
+   * {@code sint64} field.
+   */
+  public static int computeSInt64SizeNoTag(final long value) {
+    return computeRawVarint64Size(encodeZigZag64(value));
+  }
+
+  // =================================================================
+
+  /**
+   * Internal helper that writes the current buffer to the output. The
+   * buffer position is reset to its initial value when this returns.
+   */
+  private void refreshBuffer() throws IOException {
+    if (output == null) {
+      // We're writing to a single buffer.
+      throw new OutOfSpaceException();
+    }
+
+    // Since we have an output stream, this is our buffer
+    // and buffer offset == 0
+    output.write(buffer, 0, position);
+    position = 0;
+  }
+
+  /**
+   * Flushes the stream and forces any buffered bytes to be written.  This
+   * does not flush the underlying OutputStream.
+   */
+  public void flush() throws IOException {
+    if (output != null) {
+      refreshBuffer();
+    }
+  }
+
+  /**
+   * If writing to a flat array, return the space left in the array.
+   * Otherwise, throws {@code UnsupportedOperationException}.
+   */
+  public int spaceLeft() {
+    if (output == null) {
+      return limit - position;
+    } else {
+      throw new UnsupportedOperationException(
+        "spaceLeft() can only be called on CodedOutputStreams that are " +
+        "writing to a flat array.");
+    }
+  }
+
+  /**
+   * Verifies that {@link #spaceLeft()} returns zero.  It's common to create
+   * a byte array that is exactly big enough to hold a message, then write to
+   * it with a {@code CodedOutputStream}.  Calling {@code checkNoSpaceLeft()}
+   * after writing verifies that the message was actually as big as expected,
+   * which can help catch bugs.
+   */
+  public void checkNoSpaceLeft() {
+    if (spaceLeft() != 0) {
+      throw new IllegalStateException(
+        "Did not write as much data as expected.");
+    }
+  }
+
+  /**
+   * If you create a CodedOutputStream around a simple flat array, you must
+   * not attempt to write more bytes than the array has space.  Otherwise,
+   * this exception will be thrown.
+   */
+  public static class OutOfSpaceException extends IOException {
+    private static final long serialVersionUID = -6947486886997889499L;
+
+    OutOfSpaceException() {
+      super("CodedOutputStream was writing to a flat byte array and ran " +
+            "out of space.");
+    }
+  }
+
+  /** Write a single byte. */
+  public void writeRawByte(final byte value) throws IOException {
+    if (position == limit) {
+      refreshBuffer();
+    }
+
+    buffer[position++] = value;
+  }
+
+  /** Write a single byte, represented by an integer value. */
+  public void writeRawByte(final int value) throws IOException {
+    writeRawByte((byte) value);
+  }
+
+  /** Write an array of bytes. */
+  public void writeRawBytes(final byte[] value) throws IOException {
+    writeRawBytes(value, 0, value.length);
+  }
+
+  /** Write part of an array of bytes. */
+  public void writeRawBytes(final byte[] value, int offset, int length)
+                            throws IOException {
+    if (limit - position >= length) {
+      // We have room in the current buffer.
+      System.arraycopy(value, offset, buffer, position, length);
+      position += length;
+    } else {
+      // Write extends past current buffer.  Fill the rest of this buffer and
+      // flush.
+      final int bytesWritten = limit - position;
+      System.arraycopy(value, offset, buffer, position, bytesWritten);
+      offset += bytesWritten;
+      length -= bytesWritten;
+      position = limit;
+      refreshBuffer();
+
+      // Now deal with the rest.
+      // Since we have an output stream, this is our buffer
+      // and buffer offset == 0
+      if (length <= limit) {
+        // Fits in new buffer.
+        System.arraycopy(value, offset, buffer, 0, length);
+        position = length;
+      } else {
+        // Write is very big.  Let's do it all at once.
+        output.write(value, offset, length);
+      }
+    }
+  }
+
+  /** Encode and write a tag. */
+  public void writeTag(final int fieldNumber, final int wireType)
+                       throws IOException {
+    writeRawVarint32(WireFormatMicro.makeTag(fieldNumber, wireType));
+  }
+
+  /** Compute the number of bytes that would be needed to encode a tag. */
+  public static int computeTagSize(final int fieldNumber) {
+    return computeRawVarint32Size(WireFormatMicro.makeTag(fieldNumber, 0));
+  }
+
+  /**
+   * Encode and write a varint.  {@code value} is treated as
+   * unsigned, so it won't be sign-extended if negative.
+   */
+  public void writeRawVarint32(int value) throws IOException {
+    while (true) {
+      if ((value & ~0x7F) == 0) {
+        writeRawByte(value);
+        return;
+      } else {
+        writeRawByte((value & 0x7F) | 0x80);
+        value >>>= 7;
+      }
+    }
+  }
+
+  /**
+   * Compute the number of bytes that would be needed to encode a varint.
+   * {@code value} is treated as unsigned, so it won't be sign-extended if
+   * negative.
+   */
+  public static int computeRawVarint32Size(final int value) {
+    if ((value & (0xffffffff <<  7)) == 0) return 1;
+    if ((value & (0xffffffff << 14)) == 0) return 2;
+    if ((value & (0xffffffff << 21)) == 0) return 3;
+    if ((value & (0xffffffff << 28)) == 0) return 4;
+    return 5;
+  }
+
+  /** Encode and write a varint. */
+  public void writeRawVarint64(long value) throws IOException {
+    while (true) {
+      if ((value & ~0x7FL) == 0) {
+        writeRawByte((int)value);
+        return;
+      } else {
+        writeRawByte(((int)value & 0x7F) | 0x80);
+        value >>>= 7;
+      }
+    }
+  }
+
+  /** Compute the number of bytes that would be needed to encode a varint. */
+  public static int computeRawVarint64Size(final long value) {
+    if ((value & (0xffffffffffffffffL <<  7)) == 0) return 1;
+    if ((value & (0xffffffffffffffffL << 14)) == 0) return 2;
+    if ((value & (0xffffffffffffffffL << 21)) == 0) return 3;
+    if ((value & (0xffffffffffffffffL << 28)) == 0) return 4;
+    if ((value & (0xffffffffffffffffL << 35)) == 0) return 5;
+    if ((value & (0xffffffffffffffffL << 42)) == 0) return 6;
+    if ((value & (0xffffffffffffffffL << 49)) == 0) return 7;
+    if ((value & (0xffffffffffffffffL << 56)) == 0) return 8;
+    if ((value & (0xffffffffffffffffL << 63)) == 0) return 9;
+    return 10;
+  }
+
+  /** Write a little-endian 32-bit integer. */
+  public void writeRawLittleEndian32(final int value) throws IOException {
+    writeRawByte((value      ) & 0xFF);
+    writeRawByte((value >>  8) & 0xFF);
+    writeRawByte((value >> 16) & 0xFF);
+    writeRawByte((value >> 24) & 0xFF);
+  }
+
+  public static final int LITTLE_ENDIAN_32_SIZE = 4;
+
+  /** Write a little-endian 64-bit integer. */
+  public void writeRawLittleEndian64(final long value) throws IOException {
+    writeRawByte((int)(value      ) & 0xFF);
+    writeRawByte((int)(value >>  8) & 0xFF);
+    writeRawByte((int)(value >> 16) & 0xFF);
+    writeRawByte((int)(value >> 24) & 0xFF);
+    writeRawByte((int)(value >> 32) & 0xFF);
+    writeRawByte((int)(value >> 40) & 0xFF);
+    writeRawByte((int)(value >> 48) & 0xFF);
+    writeRawByte((int)(value >> 56) & 0xFF);
+  }
+
+  public static final int LITTLE_ENDIAN_64_SIZE = 8;
+
+  /**
+   * Encode a ZigZag-encoded 32-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 32-bit integer.
+   * @return An unsigned 32-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static int encodeZigZag32(final int n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 31);
+  }
+
+  /**
+   * Encode a ZigZag-encoded 64-bit value.  ZigZag encodes signed integers
+   * into values that can be efficiently encoded with varint.  (Otherwise,
+   * negative values must be sign-extended to 64 bits to be varint encoded,
+   * thus always taking 10 bytes on the wire.)
+   *
+   * @param n A signed 64-bit integer.
+   * @return An unsigned 64-bit integer, stored in a signed int because
+   *         Java has no explicit unsigned support.
+   */
+  public static long encodeZigZag64(final long n) {
+    // Note:  the right-shift must be arithmetic
+    return (n << 1) ^ (n >> 63);
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java b/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java
new file mode 100644
index 0000000..050f99b
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/InvalidProtocolBufferMicroException.java
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+import java.io.IOException;
+
+/**
+ * Thrown when a protocol message being parsed is invalid in some way,
+ * e.g. it contains a malformed varint or a negative byte length.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class InvalidProtocolBufferMicroException extends IOException {
+  private static final long serialVersionUID = -1616151763072450476L;
+
+  public InvalidProtocolBufferMicroException(final String description) {
+    super(description);
+  }
+
+  static InvalidProtocolBufferMicroException truncatedMessage() {
+    return new InvalidProtocolBufferMicroException(
+      "While parsing a protocol message, the input ended unexpectedly " +
+      "in the middle of a field.  This could mean either than the " +
+      "input has been truncated or that an embedded message " +
+      "misreported its own length.");
+  }
+
+  static InvalidProtocolBufferMicroException negativeSize() {
+    return new InvalidProtocolBufferMicroException(
+      "CodedInputStream encountered an embedded string or message " +
+      "which claimed to have negative size.");
+  }
+
+  static InvalidProtocolBufferMicroException malformedVarint() {
+    return new InvalidProtocolBufferMicroException(
+      "CodedInputStream encountered a malformed varint.");
+  }
+
+  static InvalidProtocolBufferMicroException invalidTag() {
+    return new InvalidProtocolBufferMicroException(
+      "Protocol message contained an invalid tag (zero).");
+  }
+
+  static InvalidProtocolBufferMicroException invalidEndTag() {
+    return new InvalidProtocolBufferMicroException(
+      "Protocol message end-group tag did not match expected tag.");
+  }
+
+  static InvalidProtocolBufferMicroException invalidWireType() {
+    return new InvalidProtocolBufferMicroException(
+      "Protocol message tag had invalid wire type.");
+  }
+
+  static InvalidProtocolBufferMicroException recursionLimitExceeded() {
+    return new InvalidProtocolBufferMicroException(
+      "Protocol message had too many levels of nesting.  May be malicious.  " +
+      "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+  }
+
+  static InvalidProtocolBufferMicroException sizeLimitExceeded() {
+    return new InvalidProtocolBufferMicroException(
+      "Protocol message was too large.  May be malicious.  " +
+      "Use CodedInputStream.setSizeLimit() to increase the size limit.");
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/MessageMicro.java b/java/src/main/java/com/google/protobuf/micro/MessageMicro.java
new file mode 100644
index 0000000..0c02793
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/MessageMicro.java
@@ -0,0 +1,136 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+import com.google.protobuf.micro.CodedOutputStreamMicro;
+import java.io.IOException;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public abstract class MessageMicro {
+    /**
+     * Get the number of bytes required to encode this message.
+     * Returns the cached size or calls getSerializedSize which
+     * sets the cached size. This is used internally when serializing
+     * so the size is only computed once. If a member is modified
+     * then this could be stale call getSerializedSize if in doubt.
+     */
+    abstract public int getCachedSize();
+
+    /**
+     * Computes the number of bytes required to encode this message.
+     * The size is cached and the cached result can be retrieved
+     * using getCachedSize().
+     */
+    abstract public int getSerializedSize();
+
+    /**
+     * Serializes the message and writes it to {@code output}.  This does not
+     * flush or close the stream.
+     */
+    abstract public void writeTo(CodedOutputStreamMicro output) throws java.io.IOException;
+
+    /**
+     * Parse {@code input} as a message of this type and merge it with the
+     * message being built.
+     */
+    abstract public MessageMicro mergeFrom(final CodedInputStreamMicro input) throws IOException;
+
+    /**
+     * Serialize to a byte array.
+     * @return byte array with the serialized data.
+     */
+    public byte[] toByteArray() {
+        final byte[] result = new byte[getSerializedSize()];
+        toByteArray(result, 0, result.length);
+        return result;
+    }
+
+    /**
+     * Serialize to a byte array starting at offset through length. The
+     * method getSerializedSize must have been called prior to calling
+     * this method so the proper length is know.  If an attempt to
+     * write more than length bytes OutOfSpaceException will be thrown
+     * and if length bytes are not written then IllegalStateException
+     * is thrown.
+     * @return byte array with the serialized data.
+     */
+    public void toByteArray(byte [] data, int offset, int length) {
+        try {
+            final CodedOutputStreamMicro output = CodedOutputStreamMicro.newInstance(data, offset, length);
+            writeTo(output);
+            output.checkNoSpaceLeft();
+        } catch (IOException e) {
+            throw new RuntimeException("Serializing to a byte array threw an IOException "
+                    + "(should never happen).");
+        }
+    }
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.
+     */
+    public MessageMicro mergeFrom(final byte[] data) throws InvalidProtocolBufferMicroException {
+        return mergeFrom(data, 0, data.length);
+    }
+
+    /**
+     * Parse {@code data} as a message of this type and merge it with the
+     * message being built.
+     */
+    public MessageMicro mergeFrom(final byte[] data, final int off, final int len)
+            throws InvalidProtocolBufferMicroException {
+        try {
+            final CodedInputStreamMicro input = CodedInputStreamMicro.newInstance(data, off, len);
+            mergeFrom(input);
+            input.checkLastTagWas(0);
+            return this;
+        } catch (InvalidProtocolBufferMicroException e) {
+            throw e;
+        } catch (IOException e) {
+            throw new RuntimeException("Reading from a byte array threw an IOException (should "
+                    + "never happen).");
+        }
+    }
+
+    /**
+     * Called by subclasses to parse an unknown field.
+     * @return {@code true} unless the tag is an end-group tag.
+     */
+    protected boolean parseUnknownField(
+        final CodedInputStreamMicro input,
+        final int tag) throws IOException {
+      return input.skipField(tag);
+    }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java b/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java
new file mode 100644
index 0000000..0c43e54
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/StringUtf8Micro.java
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+/**
+ * A surogate for a String with a UTF8 representation.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public final class StringUtf8Micro {
+  private String string;
+  private byte[] bytes;
+
+  public StringUtf8Micro(String string) {
+    setString(string);
+  }
+
+  public static final StringUtf8Micro EMPTY = new StringUtf8Micro("");
+
+  public String getString() {
+    return string;
+  }
+
+  public void setString(String string) {
+    this.string = string;
+    bytes = null;
+  }
+
+  public byte [] getBytes() {
+    if (bytes == null) {
+      try {
+        bytes = string.getBytes("UTF-8");
+      } catch (java.io.UnsupportedEncodingException e) {
+        throw new RuntimeException("UTF-8 not supported.");
+      }
+    }
+    return bytes;
+  }
+}
diff --git a/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java b/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java
new file mode 100644
index 0000000..d8a88bd
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/micro/WireFormatMicro.java
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.micro;
+
+/**
+ * This class is used internally by the Protocol Buffer library and generated
+ * message implementations.  It is public only because those generated messages
+ * do not reside in the {@code protobuf} package.  Others should not use this
+ * class directly.
+ *
+ * This class contains constants and helper functions useful for dealing with
+ * the Protocol Buffer wire format.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class WireFormatMicro {
+  // Do not allow instantiation.
+  private WireFormatMicro() {}
+
+  static final int WIRETYPE_VARINT           = 0;
+  static final int WIRETYPE_FIXED64          = 1;
+  static final int WIRETYPE_LENGTH_DELIMITED = 2;
+  static final int WIRETYPE_START_GROUP      = 3;
+  static final int WIRETYPE_END_GROUP        = 4;
+  static final int WIRETYPE_FIXED32          = 5;
+
+  static final int TAG_TYPE_BITS = 3;
+  static final int TAG_TYPE_MASK = (1 << TAG_TYPE_BITS) - 1;
+
+  /** Given a tag value, determines the wire type (the lower 3 bits). */
+  static int getTagWireType(final int tag) {
+    return tag & TAG_TYPE_MASK;
+  }
+
+  /** Given a tag value, determines the field number (the upper 29 bits). */
+  public static int getTagFieldNumber(final int tag) {
+    return tag >>> TAG_TYPE_BITS;
+  }
+
+  /** Makes a tag value given a field number and wire type. */
+  static int makeTag(final int fieldNumber, final int wireType) {
+    return (fieldNumber << TAG_TYPE_BITS) | wireType;
+  }
+
+  // Field numbers for feilds in MessageSet wire format.
+  static final int MESSAGE_SET_ITEM    = 1;
+  static final int MESSAGE_SET_TYPE_ID = 2;
+  static final int MESSAGE_SET_MESSAGE = 3;
+
+  // Tag numbers.
+  static final int MESSAGE_SET_ITEM_TAG =
+    makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
+  static final int MESSAGE_SET_ITEM_END_TAG =
+    makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
+  static final int MESSAGE_SET_TYPE_ID_TAG =
+    makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
+  static final int MESSAGE_SET_MESSAGE_TAG =
+    makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
+}
diff --git a/java/src/test/java/com/google/protobuf/MicroTest.java b/java/src/test/java/com/google/protobuf/MicroTest.java
new file mode 100644
index 0000000..ebfccc2
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/MicroTest.java
@@ -0,0 +1,2138 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.micro.MicroOuterClass;
+import com.google.protobuf.micro.MicroOuterClass.TestAllTypesMicro;
+import com.google.protobuf.micro.RecursiveMessageMicro;
+import com.google.protobuf.micro.SimpleMessageMicro;
+import com.google.protobuf.micro.StringUtf8;
+import com.google.protobuf.micro.StringUtf8Micro;
+import com.google.protobuf.micro.UnittestImportMicro;
+import com.google.protobuf.micro.ByteStringMicro;
+
+import junit.framework.TestCase;
+
+/**
+ * Test micro runtime.
+ *
+ * @author wink@google.com Wink Saville
+ */
+public class MicroTest extends TestCase {
+  public void setUp() throws Exception {
+  }
+
+  public void testSimpleMessageMicro() throws Exception {
+    SimpleMessageMicro msg = new SimpleMessageMicro();
+    assertFalse(msg.hasD());
+    assertEquals(123, msg.getD());
+    assertFalse(msg.hasNestedMsg());
+    assertEquals(null, msg.getNestedMsg());
+    assertFalse(msg.hasDefaultNestedEnum());
+    assertEquals(SimpleMessageMicro.BAZ, msg.getDefaultNestedEnum());
+
+    msg.setD(456);
+    assertTrue(msg.hasD());
+    assertEquals(456, msg.getD());
+    msg.clearD()
+       .setD(456);
+    assertTrue(msg.hasD());
+
+    SimpleMessageMicro.NestedMessage nestedMsg = new SimpleMessageMicro.NestedMessage()
+      .setBb(2);
+    assertTrue(nestedMsg.hasBb());
+    assertEquals(2, nestedMsg.getBb());
+    msg.setNestedMsg(nestedMsg);
+    assertTrue(msg.hasNestedMsg());
+    assertEquals(2, msg.getNestedMsg().getBb());
+
+    msg.setDefaultNestedEnum(SimpleMessageMicro.BAR);
+    assertTrue(msg.hasDefaultNestedEnum());
+    assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum());
+
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    SimpleMessageMicro newMsg = SimpleMessageMicro.parseFrom(result);
+    assertTrue(newMsg.hasD());
+    assertTrue(newMsg.hasNestedMsg());
+    assertTrue(newMsg.hasDefaultNestedEnum());
+    assertEquals(456, newMsg.getD());
+    assertEquals(2, msg.getNestedMsg().getBb());
+    assertEquals(SimpleMessageMicro.BAR, msg.getDefaultNestedEnum());
+  }
+
+  public void testRecursiveMessageMicro() throws Exception {
+    RecursiveMessageMicro msg = new RecursiveMessageMicro();
+    assertFalse(msg.hasId());
+    assertFalse(msg.hasNestedMessage());
+    assertFalse(msg.hasOptionalRecursiveMessageMicro());
+    assertEquals(0, msg.getRepeatedRecursiveMessageMicroCount());
+
+    RecursiveMessageMicro msg1 = new RecursiveMessageMicro();
+    msg1.setId(1);
+    assertEquals(1, msg1.getId());
+    RecursiveMessageMicro msg2 = new RecursiveMessageMicro();
+    msg2.setId(2);
+    RecursiveMessageMicro msg3 = new RecursiveMessageMicro();
+    msg3.setId(3);
+
+    RecursiveMessageMicro.NestedMessage nestedMsg = new RecursiveMessageMicro.NestedMessage();
+    nestedMsg.setA(msg1);
+    assertEquals(1, nestedMsg.getA().getId());
+
+    msg.setId(0);
+    msg.setNestedMessage(nestedMsg);
+    msg.setOptionalRecursiveMessageMicro(msg2);
+    msg.addRepeatedRecursiveMessageMicro(msg3);
+
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    RecursiveMessageMicro newMsg = RecursiveMessageMicro.parseFrom(result);
+    assertTrue(newMsg.hasId());
+    assertTrue(newMsg.hasNestedMessage());
+    assertTrue(newMsg.hasOptionalRecursiveMessageMicro());
+    assertEquals(1, newMsg.getRepeatedRecursiveMessageMicroCount());
+
+    assertEquals(0, newMsg.getId());
+    assertEquals(1, newMsg.getNestedMessage().getA().getId());
+    assertEquals(2, newMsg.getOptionalRecursiveMessageMicro().getId());
+    assertEquals(3, newMsg.getRepeatedRecursiveMessageMicro(0).getId());
+  }
+
+  public void testMicroRequiredInt32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasId());
+    assertFalse(msg.isInitialized());
+    msg.setId(123);
+    assertTrue(msg.hasId());
+    assertTrue(msg.isInitialized());
+    assertEquals(123, msg.getId());
+    msg.clearId();
+    assertFalse(msg.hasId());
+    assertFalse(msg.isInitialized());
+    msg.clearId()
+       .setId(456);
+    assertTrue(msg.hasId());
+    msg.clear();
+    assertFalse(msg.hasId());
+    assertFalse(msg.isInitialized());
+
+    msg.setId(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasId());
+    assertTrue(newMsg.isInitialized());
+    assertEquals(123, newMsg.getId());
+  }
+
+  public void testMicroOptionalInt32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalInt32());
+    msg.setOptionalInt32(123);
+    assertTrue(msg.hasOptionalInt32());
+    assertEquals(123, msg.getOptionalInt32());
+    msg.clearOptionalInt32();
+    assertFalse(msg.hasOptionalInt32());
+    msg.clearOptionalInt32()
+       .setOptionalInt32(456);
+    assertTrue(msg.hasOptionalInt32());
+    msg.clear();
+    assertFalse(msg.hasOptionalInt32());
+
+    msg.setOptionalInt32(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 2);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalInt32());
+    assertEquals(123, newMsg.getOptionalInt32());
+  }
+
+  public void testMicroOptionalInt64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalInt64());
+    msg.setOptionalInt64(123);
+    assertTrue(msg.hasOptionalInt64());
+    assertEquals(123, msg.getOptionalInt64());
+    msg.clearOptionalInt64();
+    assertFalse(msg.hasOptionalInt64());
+    msg.clearOptionalInt64()
+       .setOptionalInt64(456);
+    assertTrue(msg.hasOptionalInt64());
+    msg.clear();
+    assertFalse(msg.hasOptionalInt64());
+
+    msg.setOptionalInt64(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 2);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalInt64());
+    assertEquals(123, newMsg.getOptionalInt64());
+  }
+
+  public void testMicroOptionalUint32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalUint32());
+    msg.setOptionalUint32(123);
+    assertTrue(msg.hasOptionalUint32());
+    assertEquals(123, msg.getOptionalUint32());
+    msg.clearOptionalUint32();
+    assertFalse(msg.hasOptionalUint32());
+    msg.clearOptionalUint32()
+       .setOptionalUint32(456);
+    assertTrue(msg.hasOptionalUint32());
+    msg.clear();
+    assertFalse(msg.hasOptionalUint32());
+
+    msg.setOptionalUint32(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 2);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalUint32());
+    assertEquals(123, newMsg.getOptionalUint32());
+  }
+
+  public void testMicroOptionalUint64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalUint64());
+    msg.setOptionalUint64(123);
+    assertTrue(msg.hasOptionalUint64());
+    assertEquals(123, msg.getOptionalUint64());
+    msg.clearOptionalUint64();
+    assertFalse(msg.hasOptionalUint64());
+    msg.clearOptionalUint64()
+       .setOptionalUint64(456);
+    assertTrue(msg.hasOptionalUint64());
+    msg.clear();
+    assertFalse(msg.hasOptionalUint64());
+
+    msg.setOptionalUint64(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 2);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalUint64());
+    assertEquals(123, newMsg.getOptionalUint64());
+  }
+
+  public void testMicroOptionalSint32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalSint32());
+    msg.setOptionalSint32(123);
+    assertTrue(msg.hasOptionalSint32());
+    assertEquals(123, msg.getOptionalSint32());
+    msg.clearOptionalSint32();
+    assertFalse(msg.hasOptionalSint32());
+    msg.clearOptionalSint32()
+       .setOptionalSint32(456);
+    assertTrue(msg.hasOptionalSint32());
+    msg.clear();
+    assertFalse(msg.hasOptionalSint32());
+
+    msg.setOptionalSint32(-123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalSint32());
+    assertEquals(-123, newMsg.getOptionalSint32());
+  }
+
+  public void testMicroOptionalSint64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalSint64());
+    msg.setOptionalSint64(123);
+    assertTrue(msg.hasOptionalSint64());
+    assertEquals(123, msg.getOptionalSint64());
+    msg.clearOptionalSint64();
+    assertFalse(msg.hasOptionalSint64());
+    msg.clearOptionalSint64()
+       .setOptionalSint64(456);
+    assertTrue(msg.hasOptionalSint64());
+    msg.clear();
+    assertFalse(msg.hasOptionalSint64());
+
+    msg.setOptionalSint64(-123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalSint64());
+    assertEquals(-123, newMsg.getOptionalSint64());
+  }
+
+  public void testMicroOptionalFixed32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalFixed32());
+    msg.setOptionalFixed32(123);
+    assertTrue(msg.hasOptionalFixed32());
+    assertEquals(123, msg.getOptionalFixed32());
+    msg.clearOptionalFixed32();
+    assertFalse(msg.hasOptionalFixed32());
+    msg.clearOptionalFixed32()
+       .setOptionalFixed32(456);
+    assertTrue(msg.hasOptionalFixed32());
+    msg.clear();
+    assertFalse(msg.hasOptionalFixed32());
+
+    msg.setOptionalFixed32(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalFixed32());
+    assertEquals(123, newMsg.getOptionalFixed32());
+  }
+
+  public void testMicroOptionalFixed64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalFixed64());
+    msg.setOptionalFixed64(123);
+    assertTrue(msg.hasOptionalFixed64());
+    assertEquals(123, msg.getOptionalFixed64());
+    msg.clearOptionalFixed64();
+    assertFalse(msg.hasOptionalFixed64());
+    msg.clearOptionalFixed64()
+       .setOptionalFixed64(456);
+    assertTrue(msg.hasOptionalFixed64());
+    msg.clear();
+    assertFalse(msg.hasOptionalFixed64());
+
+    msg.setOptionalFixed64(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalFixed64());
+    assertEquals(123, newMsg.getOptionalFixed64());
+  }
+  public void testMicroOptionalSfixed32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalSfixed32());
+    msg.setOptionalSfixed32(123);
+    assertTrue(msg.hasOptionalSfixed32());
+    assertEquals(123, msg.getOptionalSfixed32());
+    msg.clearOptionalSfixed32();
+    assertFalse(msg.hasOptionalSfixed32());
+    msg.clearOptionalSfixed32()
+       .setOptionalSfixed32(456);
+    assertTrue(msg.hasOptionalSfixed32());
+    msg.clear();
+    assertFalse(msg.hasOptionalSfixed32());
+
+    msg.setOptionalSfixed32(123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalSfixed32());
+    assertEquals(123, newMsg.getOptionalSfixed32());
+  }
+
+  public void testMicroOptionalSfixed64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalSfixed64());
+    msg.setOptionalSfixed64(123);
+    assertTrue(msg.hasOptionalSfixed64());
+    assertEquals(123, msg.getOptionalSfixed64());
+    msg.clearOptionalSfixed64();
+    assertFalse(msg.hasOptionalSfixed64());
+    msg.clearOptionalSfixed64()
+       .setOptionalSfixed64(456);
+    assertTrue(msg.hasOptionalSfixed64());
+    msg.clear();
+    assertFalse(msg.hasOptionalSfixed64());
+
+    msg.setOptionalSfixed64(-123);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalSfixed64());
+    assertEquals(-123, newMsg.getOptionalSfixed64());
+  }
+
+  public void testMicroOptionalFloat() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalFloat());
+    msg.setOptionalFloat(123f);
+    assertTrue(msg.hasOptionalFloat());
+    assertTrue(123.0f == msg.getOptionalFloat());
+    msg.clearOptionalFloat();
+    assertFalse(msg.hasOptionalFloat());
+    msg.clearOptionalFloat()
+       .setOptionalFloat(456.0f);
+    assertTrue(msg.hasOptionalFloat());
+    msg.clear();
+    assertFalse(msg.hasOptionalFloat());
+
+    msg.setOptionalFloat(-123.456f);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalFloat());
+    assertTrue(-123.456f == newMsg.getOptionalFloat());
+  }
+
+  public void testMicroOptionalDouble() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalDouble());
+    msg.setOptionalDouble(123);
+    assertTrue(msg.hasOptionalDouble());
+    assertTrue(123.0 == msg.getOptionalDouble());
+    msg.clearOptionalDouble();
+    assertFalse(msg.hasOptionalDouble());
+    msg.clearOptionalDouble()
+       .setOptionalDouble(456.0);
+    assertTrue(msg.hasOptionalDouble());
+    msg.clear();
+    assertFalse(msg.hasOptionalDouble());
+
+    msg.setOptionalDouble(-123.456);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 9);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalDouble());
+    assertTrue(-123.456 == newMsg.getOptionalDouble());
+  }
+
+  public void testMicroOptionalBool() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalBool());
+    msg.setOptionalBool(true);
+    assertTrue(msg.hasOptionalBool());
+    assertEquals(true, msg.getOptionalBool());
+    msg.clearOptionalBool();
+    assertFalse(msg.hasOptionalBool());
+    msg.clearOptionalBool()
+       .setOptionalBool(true);
+    assertTrue(msg.hasOptionalBool());
+    msg.clear();
+    assertFalse(msg.hasOptionalBool());
+
+    msg.setOptionalBool(false);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 2);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalBool());
+    assertEquals(false, newMsg.getOptionalBool());
+  }
+
+  public void testMicroOptionalString() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalString());
+    msg.setOptionalString("hello");
+    assertTrue(msg.hasOptionalString());
+    assertEquals("hello", msg.getOptionalString());
+    msg.clearOptionalString();
+    assertFalse(msg.hasOptionalString());
+    msg.clearOptionalString()
+       .setOptionalString("hello");
+    assertTrue(msg.hasOptionalString());
+    msg.clear();
+    assertFalse(msg.hasOptionalString());
+
+    msg.setOptionalString("bye");
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalString());
+    assertEquals("bye", newMsg.getOptionalString());
+  }
+
+  public void testMicroOptionalBytes() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalBytes());
+    msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("hello"));
+    assertTrue(msg.hasOptionalBytes());
+    assertEquals("hello", msg.getOptionalBytes().toStringUtf8());
+    msg.clearOptionalBytes();
+    assertFalse(msg.hasOptionalBytes());
+    msg.clearOptionalBytes()
+       .setOptionalBytes(ByteStringMicro.copyFromUtf8("hello"));
+    assertTrue(msg.hasOptionalBytes());
+    msg.clear();
+    assertFalse(msg.hasOptionalBytes());
+
+    msg.setOptionalBytes(ByteStringMicro.copyFromUtf8("bye"));
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalBytes());
+    assertEquals("bye", newMsg.getOptionalBytes().toStringUtf8());
+  }
+
+  public void testMicroOptionalGroup() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    TestAllTypesMicro.OptionalGroup grp = new TestAllTypesMicro.OptionalGroup();
+    grp.setA(1);
+    assertFalse(msg.hasOptionalGroup());
+    msg.setOptionalGroup(grp);
+    assertTrue(msg.hasOptionalGroup());
+    assertEquals(1, msg.getOptionalGroup().getA());
+    msg.clearOptionalGroup();
+    assertFalse(msg.hasOptionalGroup());
+    msg.clearOptionalGroup()
+       .setOptionalGroup(new TestAllTypesMicro.OptionalGroup().setA(2));
+    assertTrue(msg.hasOptionalGroup());
+    msg.clear();
+    assertFalse(msg.hasOptionalGroup());
+
+    msg.setOptionalGroup(grp);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalGroup());
+    assertEquals(1, newMsg.getOptionalGroup().getA());
+  }
+
+  public void testMicroOptionalNestedMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    TestAllTypesMicro.NestedMessage nestedMsg = new TestAllTypesMicro.NestedMessage();
+    nestedMsg.setBb(1);
+    assertFalse(msg.hasOptionalNestedMessage());
+    msg.setOptionalNestedMessage(nestedMsg);
+    assertTrue(msg.hasOptionalNestedMessage());
+    assertEquals(1, msg.getOptionalNestedMessage().getBb());
+    msg.clearOptionalNestedMessage();
+    assertFalse(msg.hasOptionalNestedMessage());
+    msg.clearOptionalNestedMessage()
+       .setOptionalNestedMessage(new TestAllTypesMicro.NestedMessage().setBb(2));
+    assertTrue(msg.hasOptionalNestedMessage());
+    msg.clear();
+    assertFalse(msg.hasOptionalNestedMessage());
+
+    msg.setOptionalNestedMessage(nestedMsg);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalNestedMessage());
+    assertEquals(1, newMsg.getOptionalNestedMessage().getBb());
+  }
+
+  public void testMicroOptionalForeignMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    MicroOuterClass.ForeignMessageMicro foreignMsg =
+        new MicroOuterClass.ForeignMessageMicro();
+    assertFalse(foreignMsg.hasC());
+    foreignMsg.setC(1);
+    assertTrue(foreignMsg.hasC());
+    assertFalse(msg.hasOptionalForeignMessage());
+    msg.setOptionalForeignMessage(foreignMsg);
+    assertTrue(msg.hasOptionalForeignMessage());
+    assertEquals(1, msg.getOptionalForeignMessage().getC());
+    msg.clearOptionalForeignMessage();
+    assertFalse(msg.hasOptionalForeignMessage());
+    msg.clearOptionalForeignMessage()
+       .setOptionalForeignMessage(new MicroOuterClass.ForeignMessageMicro().setC(2));
+    assertTrue(msg.hasOptionalForeignMessage());
+    msg.clear();
+    assertFalse(msg.hasOptionalForeignMessage());
+
+    msg.setOptionalForeignMessage(foreignMsg);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalForeignMessage());
+    assertEquals(1, newMsg.getOptionalForeignMessage().getC());
+  }
+
+  public void testMicroOptionalImportMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    UnittestImportMicro.ImportMessageMicro importMsg =
+        new UnittestImportMicro.ImportMessageMicro();
+    assertFalse(importMsg.hasD());
+    importMsg.setD(1);
+    assertTrue(importMsg.hasD());
+    assertFalse(msg.hasOptionalImportMessage());
+    msg.setOptionalImportMessage(importMsg);
+    assertTrue(msg.hasOptionalImportMessage());
+    assertEquals(1, msg.getOptionalImportMessage().getD());
+    msg.clearOptionalImportMessage();
+    assertFalse(msg.hasOptionalImportMessage());
+    msg.clearOptionalImportMessage()
+       .setOptionalImportMessage(new UnittestImportMicro.ImportMessageMicro().setD(2));
+    assertTrue(msg.hasOptionalImportMessage());
+    msg.clear();
+    assertFalse(msg.hasOptionalImportMessage());
+
+    msg.setOptionalImportMessage(importMsg);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalImportMessage());
+    assertEquals(1, newMsg.getOptionalImportMessage().getD());
+  }
+
+  public void testMicroOptionalNestedEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.setOptionalNestedEnum(TestAllTypesMicro.BAR);
+    assertTrue(msg.hasOptionalNestedEnum());
+    assertEquals(TestAllTypesMicro.BAR, msg.getOptionalNestedEnum());
+    msg.clearOptionalNestedEnum();
+    assertFalse(msg.hasOptionalNestedEnum());
+    msg.clearOptionalNestedEnum()
+       .setOptionalNestedEnum(TestAllTypesMicro.BAZ);
+    assertTrue(msg.hasOptionalNestedEnum());
+    msg.clear();
+    assertFalse(msg.hasOptionalNestedEnum());
+
+    msg.setOptionalNestedEnum(TestAllTypesMicro.BAR);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalNestedEnum());
+    assertEquals(TestAllTypesMicro.BAR, newMsg.getOptionalNestedEnum());
+  }
+
+  public void testMicroOptionalForeignEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
+    assertTrue(msg.hasOptionalForeignEnum());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR,
+        msg.getOptionalForeignEnum());
+    msg.clearOptionalForeignEnum();
+    assertFalse(msg.hasOptionalForeignEnum());
+    msg.clearOptionalForeignEnum()
+       .setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAZ);
+    assertTrue(msg.hasOptionalForeignEnum());
+    msg.clear();
+    assertFalse(msg.hasOptionalForeignEnum());
+
+    msg.setOptionalForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalForeignEnum());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR,
+        newMsg.getOptionalForeignEnum());
+  }
+
+  public void testMicroOptionalImportEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
+    assertTrue(msg.hasOptionalImportEnum());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR,
+        msg.getOptionalImportEnum());
+    msg.clearOptionalImportEnum();
+    assertFalse(msg.hasOptionalImportEnum());
+    msg.clearOptionalImportEnum()
+       .setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAZ);
+    assertTrue(msg.hasOptionalImportEnum());
+    msg.clear();
+    assertFalse(msg.hasOptionalImportEnum());
+
+    msg.setOptionalImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalImportEnum());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR,
+        newMsg.getOptionalImportEnum());
+  }
+
+  public void testMicroOptionalStringPiece() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalStringPiece());
+    msg.setOptionalStringPiece("hello");
+    assertTrue(msg.hasOptionalStringPiece());
+    assertEquals("hello", msg.getOptionalStringPiece());
+    msg.clearOptionalStringPiece();
+    assertFalse(msg.hasOptionalStringPiece());
+    msg.clearOptionalStringPiece()
+       .setOptionalStringPiece("hello");
+    assertTrue(msg.hasOptionalStringPiece());
+    msg.clear();
+    assertFalse(msg.hasOptionalStringPiece());
+
+    msg.setOptionalStringPiece("bye");
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalStringPiece());
+    assertEquals("bye", newMsg.getOptionalStringPiece());
+  }
+
+  public void testMicroOptionalCord() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasOptionalCord());
+    msg.setOptionalCord("hello");
+    assertTrue(msg.hasOptionalCord());
+    assertEquals("hello", msg.getOptionalCord());
+    msg.clearOptionalCord();
+    assertFalse(msg.hasOptionalCord());
+    msg.clearOptionalCord()
+      .setOptionalCord("hello");
+    assertTrue(msg.hasOptionalCord());
+    msg.clear();
+    assertFalse(msg.hasOptionalCord());
+
+    msg.setOptionalCord("bye");
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertTrue(newMsg.hasOptionalCord());
+    assertEquals("bye", newMsg.getOptionalCord());
+  }
+
+  public void testMicroRepeatedInt32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedInt32Count());
+    msg.addRepeatedInt32(123);
+    assertEquals(1, msg.getRepeatedInt32Count());
+    assertEquals(123, msg.getRepeatedInt32(0));
+    msg.addRepeatedInt32(456);
+    assertEquals(2, msg.getRepeatedInt32Count());
+    assertEquals(123, msg.getRepeatedInt32(0));
+    assertEquals(456, msg.getRepeatedInt32(1));
+    msg.setRepeatedInt32(0, 789);
+    assertEquals(2, msg.getRepeatedInt32Count());
+    assertEquals(789, msg.getRepeatedInt32(0));
+    assertEquals(456, msg.getRepeatedInt32(1));
+    msg.clearRepeatedInt32();
+    assertEquals(0, msg.getRepeatedInt32Count());
+    msg.clearRepeatedInt32()
+       .addRepeatedInt32(456);
+    assertEquals(1, msg.getRepeatedInt32Count());
+    assertEquals(456, msg.getRepeatedInt32(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedInt32Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedInt32(123);
+    assertEquals(1, msg.getRepeatedInt32Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedInt32Count());
+    assertEquals(123, newMsg.getRepeatedInt32(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedInt32(123)
+       .addRepeatedInt32(456);
+    assertEquals(2, msg.getRepeatedInt32Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedInt32Count());
+    assertEquals(123, newMsg.getRepeatedInt32(0));
+    assertEquals(456, newMsg.getRepeatedInt32(1));
+  }
+
+  public void testMicroRepeatedInt64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedInt64Count());
+    msg.addRepeatedInt64(123);
+    assertEquals(1, msg.getRepeatedInt64Count());
+    assertEquals(123, msg.getRepeatedInt64(0));
+    msg.addRepeatedInt64(456);
+    assertEquals(2, msg.getRepeatedInt64Count());
+    assertEquals(123, msg.getRepeatedInt64(0));
+    assertEquals(456, msg.getRepeatedInt64(1));
+    msg.setRepeatedInt64(0, 789);
+    assertEquals(2, msg.getRepeatedInt64Count());
+    assertEquals(789, msg.getRepeatedInt64(0));
+    assertEquals(456, msg.getRepeatedInt64(1));
+    msg.clearRepeatedInt64();
+    assertEquals(0, msg.getRepeatedInt64Count());
+    msg.clearRepeatedInt64()
+       .addRepeatedInt64(456);
+    assertEquals(1, msg.getRepeatedInt64Count());
+    assertEquals(456, msg.getRepeatedInt64(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedInt64Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedInt64(123);
+    assertEquals(1, msg.getRepeatedInt64Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedInt64Count());
+    assertEquals(123, newMsg.getRepeatedInt64(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedInt64(123)
+       .addRepeatedInt64(456);
+    assertEquals(2, msg.getRepeatedInt64Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedInt64Count());
+    assertEquals(123, newMsg.getRepeatedInt64(0));
+    assertEquals(456, newMsg.getRepeatedInt64(1));
+  }
+
+  public void testMicroRepeatedUint32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedUint32Count());
+    msg.addRepeatedUint32(123);
+    assertEquals(1, msg.getRepeatedUint32Count());
+    assertEquals(123, msg.getRepeatedUint32(0));
+    msg.addRepeatedUint32(456);
+    assertEquals(2, msg.getRepeatedUint32Count());
+    assertEquals(123, msg.getRepeatedUint32(0));
+    assertEquals(456, msg.getRepeatedUint32(1));
+    msg.setRepeatedUint32(0, 789);
+    assertEquals(2, msg.getRepeatedUint32Count());
+    assertEquals(789, msg.getRepeatedUint32(0));
+    assertEquals(456, msg.getRepeatedUint32(1));
+    msg.clearRepeatedUint32();
+    assertEquals(0, msg.getRepeatedUint32Count());
+    msg.clearRepeatedUint32()
+       .addRepeatedUint32(456);
+    assertEquals(1, msg.getRepeatedUint32Count());
+    assertEquals(456, msg.getRepeatedUint32(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedUint32Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedUint32(123);
+    assertEquals(1, msg.getRepeatedUint32Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedUint32Count());
+    assertEquals(123, newMsg.getRepeatedUint32(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedUint32(123)
+       .addRepeatedUint32(456);
+    assertEquals(2, msg.getRepeatedUint32Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedUint32Count());
+    assertEquals(123, newMsg.getRepeatedUint32(0));
+    assertEquals(456, newMsg.getRepeatedUint32(1));
+  }
+
+  public void testMicroRepeatedUint64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedUint64Count());
+    msg.addRepeatedUint64(123);
+    assertEquals(1, msg.getRepeatedUint64Count());
+    assertEquals(123, msg.getRepeatedUint64(0));
+    msg.addRepeatedUint64(456);
+    assertEquals(2, msg.getRepeatedUint64Count());
+    assertEquals(123, msg.getRepeatedUint64(0));
+    assertEquals(456, msg.getRepeatedUint64(1));
+    msg.setRepeatedUint64(0, 789);
+    assertEquals(2, msg.getRepeatedUint64Count());
+    assertEquals(789, msg.getRepeatedUint64(0));
+    assertEquals(456, msg.getRepeatedUint64(1));
+    msg.clearRepeatedUint64();
+    assertEquals(0, msg.getRepeatedUint64Count());
+    msg.clearRepeatedUint64()
+       .addRepeatedUint64(456);
+    assertEquals(1, msg.getRepeatedUint64Count());
+    assertEquals(456, msg.getRepeatedUint64(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedUint64Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedUint64(123);
+    assertEquals(1, msg.getRepeatedUint64Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedUint64Count());
+    assertEquals(123, newMsg.getRepeatedUint64(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedUint64(123)
+       .addRepeatedUint64(456);
+    assertEquals(2, msg.getRepeatedUint64Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedUint64Count());
+    assertEquals(123, newMsg.getRepeatedUint64(0));
+    assertEquals(456, newMsg.getRepeatedUint64(1));
+  }
+
+  public void testMicroRepeatedSint32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedSint32Count());
+    msg.addRepeatedSint32(123);
+    assertEquals(1, msg.getRepeatedSint32Count());
+    assertEquals(123, msg.getRepeatedSint32(0));
+    msg.addRepeatedSint32(456);
+    assertEquals(2, msg.getRepeatedSint32Count());
+    assertEquals(123, msg.getRepeatedSint32(0));
+    assertEquals(456, msg.getRepeatedSint32(1));
+    msg.setRepeatedSint32(0, 789);
+    assertEquals(2, msg.getRepeatedSint32Count());
+    assertEquals(789, msg.getRepeatedSint32(0));
+    assertEquals(456, msg.getRepeatedSint32(1));
+    msg.clearRepeatedSint32();
+    assertEquals(0, msg.getRepeatedSint32Count());
+    msg.clearRepeatedSint32()
+       .addRepeatedSint32(456);
+    assertEquals(1, msg.getRepeatedSint32Count());
+    assertEquals(456, msg.getRepeatedSint32(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedSint32Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedSint32(123);
+    assertEquals(1, msg.getRepeatedSint32Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 4);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedSint32Count());
+    assertEquals(123, newMsg.getRepeatedSint32(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedSint32(123)
+       .addRepeatedSint32(456);
+    assertEquals(2, msg.getRepeatedSint32Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedSint32Count());
+    assertEquals(123, newMsg.getRepeatedSint32(0));
+    assertEquals(456, newMsg.getRepeatedSint32(1));
+  }
+
+  public void testMicroRepeatedSint64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedSint64Count());
+    msg.addRepeatedSint64(123);
+    assertEquals(1, msg.getRepeatedSint64Count());
+    assertEquals(123, msg.getRepeatedSint64(0));
+    msg.addRepeatedSint64(456);
+    assertEquals(2, msg.getRepeatedSint64Count());
+    assertEquals(123, msg.getRepeatedSint64(0));
+    assertEquals(456, msg.getRepeatedSint64(1));
+    msg.setRepeatedSint64(0, 789);
+    assertEquals(2, msg.getRepeatedSint64Count());
+    assertEquals(789, msg.getRepeatedSint64(0));
+    assertEquals(456, msg.getRepeatedSint64(1));
+    msg.clearRepeatedSint64();
+    assertEquals(0, msg.getRepeatedSint64Count());
+    msg.clearRepeatedSint64()
+       .addRepeatedSint64(456);
+    assertEquals(1, msg.getRepeatedSint64Count());
+    assertEquals(456, msg.getRepeatedSint64(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedSint64Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedSint64(123);
+    assertEquals(1, msg.getRepeatedSint64Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 4);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedSint64Count());
+    assertEquals(123, newMsg.getRepeatedSint64(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedSint64(123)
+       .addRepeatedSint64(456);
+    assertEquals(2, msg.getRepeatedSint64Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 8);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedSint64Count());
+    assertEquals(123, newMsg.getRepeatedSint64(0));
+    assertEquals(456, newMsg.getRepeatedSint64(1));
+  }
+
+  public void testMicroRepeatedFixed32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedFixed32Count());
+    msg.addRepeatedFixed32(123);
+    assertEquals(1, msg.getRepeatedFixed32Count());
+    assertEquals(123, msg.getRepeatedFixed32(0));
+    msg.addRepeatedFixed32(456);
+    assertEquals(2, msg.getRepeatedFixed32Count());
+    assertEquals(123, msg.getRepeatedFixed32(0));
+    assertEquals(456, msg.getRepeatedFixed32(1));
+    msg.setRepeatedFixed32(0, 789);
+    assertEquals(2, msg.getRepeatedFixed32Count());
+    assertEquals(789, msg.getRepeatedFixed32(0));
+    assertEquals(456, msg.getRepeatedFixed32(1));
+    msg.clearRepeatedFixed32();
+    assertEquals(0, msg.getRepeatedFixed32Count());
+    msg.clearRepeatedFixed32()
+       .addRepeatedFixed32(456);
+    assertEquals(1, msg.getRepeatedFixed32Count());
+    assertEquals(456, msg.getRepeatedFixed32(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedFixed32Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedFixed32(123);
+    assertEquals(1, msg.getRepeatedFixed32Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedFixed32Count());
+    assertEquals(123, newMsg.getRepeatedFixed32(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedFixed32(123)
+       .addRepeatedFixed32(456);
+    assertEquals(2, msg.getRepeatedFixed32Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedFixed32Count());
+    assertEquals(123, newMsg.getRepeatedFixed32(0));
+    assertEquals(456, newMsg.getRepeatedFixed32(1));
+  }
+
+  public void testMicroRepeatedFixed64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedFixed64Count());
+    msg.addRepeatedFixed64(123);
+    assertEquals(1, msg.getRepeatedFixed64Count());
+    assertEquals(123, msg.getRepeatedFixed64(0));
+    msg.addRepeatedFixed64(456);
+    assertEquals(2, msg.getRepeatedFixed64Count());
+    assertEquals(123, msg.getRepeatedFixed64(0));
+    assertEquals(456, msg.getRepeatedFixed64(1));
+    msg.setRepeatedFixed64(0, 789);
+    assertEquals(2, msg.getRepeatedFixed64Count());
+    assertEquals(789, msg.getRepeatedFixed64(0));
+    assertEquals(456, msg.getRepeatedFixed64(1));
+    msg.clearRepeatedFixed64();
+    assertEquals(0, msg.getRepeatedFixed64Count());
+    msg.clearRepeatedFixed64()
+       .addRepeatedFixed64(456);
+    assertEquals(1, msg.getRepeatedFixed64Count());
+    assertEquals(456, msg.getRepeatedFixed64(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedFixed64Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedFixed64(123);
+    assertEquals(1, msg.getRepeatedFixed64Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedFixed64Count());
+    assertEquals(123, newMsg.getRepeatedFixed64(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedFixed64(123)
+       .addRepeatedFixed64(456);
+    assertEquals(2, msg.getRepeatedFixed64Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 20);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedFixed64Count());
+    assertEquals(123, newMsg.getRepeatedFixed64(0));
+    assertEquals(456, newMsg.getRepeatedFixed64(1));
+  }
+
+  public void testMicroRepeatedSfixed32() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedSfixed32Count());
+    msg.addRepeatedSfixed32(123);
+    assertEquals(1, msg.getRepeatedSfixed32Count());
+    assertEquals(123, msg.getRepeatedSfixed32(0));
+    msg.addRepeatedSfixed32(456);
+    assertEquals(2, msg.getRepeatedSfixed32Count());
+    assertEquals(123, msg.getRepeatedSfixed32(0));
+    assertEquals(456, msg.getRepeatedSfixed32(1));
+    msg.setRepeatedSfixed32(0, 789);
+    assertEquals(2, msg.getRepeatedSfixed32Count());
+    assertEquals(789, msg.getRepeatedSfixed32(0));
+    assertEquals(456, msg.getRepeatedSfixed32(1));
+    msg.clearRepeatedSfixed32();
+    assertEquals(0, msg.getRepeatedSfixed32Count());
+    msg.clearRepeatedSfixed32()
+       .addRepeatedSfixed32(456);
+    assertEquals(1, msg.getRepeatedSfixed32Count());
+    assertEquals(456, msg.getRepeatedSfixed32(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedSfixed32Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedSfixed32(123);
+    assertEquals(1, msg.getRepeatedSfixed32Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedSfixed32Count());
+    assertEquals(123, newMsg.getRepeatedSfixed32(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedSfixed32(123)
+       .addRepeatedSfixed32(456);
+    assertEquals(2, msg.getRepeatedSfixed32Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedSfixed32Count());
+    assertEquals(123, newMsg.getRepeatedSfixed32(0));
+    assertEquals(456, newMsg.getRepeatedSfixed32(1));
+  }
+
+  public void testMicroRepeatedSfixed64() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedSfixed64Count());
+    msg.addRepeatedSfixed64(123);
+    assertEquals(1, msg.getRepeatedSfixed64Count());
+    assertEquals(123, msg.getRepeatedSfixed64(0));
+    msg.addRepeatedSfixed64(456);
+    assertEquals(2, msg.getRepeatedSfixed64Count());
+    assertEquals(123, msg.getRepeatedSfixed64(0));
+    assertEquals(456, msg.getRepeatedSfixed64(1));
+    msg.setRepeatedSfixed64(0, 789);
+    assertEquals(2, msg.getRepeatedSfixed64Count());
+    assertEquals(789, msg.getRepeatedSfixed64(0));
+    assertEquals(456, msg.getRepeatedSfixed64(1));
+    msg.clearRepeatedSfixed64();
+    assertEquals(0, msg.getRepeatedSfixed64Count());
+    msg.clearRepeatedSfixed64()
+       .addRepeatedSfixed64(456);
+    assertEquals(1, msg.getRepeatedSfixed64Count());
+    assertEquals(456, msg.getRepeatedSfixed64(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedSfixed64Count());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedSfixed64(123);
+    assertEquals(1, msg.getRepeatedSfixed64Count());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedSfixed64Count());
+    assertEquals(123, newMsg.getRepeatedSfixed64(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedSfixed64(123)
+       .addRepeatedSfixed64(456);
+    assertEquals(2, msg.getRepeatedSfixed64Count());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 20);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedSfixed64Count());
+    assertEquals(123, newMsg.getRepeatedSfixed64(0));
+    assertEquals(456, newMsg.getRepeatedSfixed64(1));
+  }
+
+  public void testMicroRepeatedFloat() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedFloatCount());
+    msg.addRepeatedFloat(123f);
+    assertEquals(1, msg.getRepeatedFloatCount());
+    assertTrue(123f == msg.getRepeatedFloat(0));
+    msg.addRepeatedFloat(456f);
+    assertEquals(2, msg.getRepeatedFloatCount());
+    assertTrue(123f == msg.getRepeatedFloat(0));
+    assertTrue(456f == msg.getRepeatedFloat(1));
+    msg.setRepeatedFloat(0, 789f);
+    assertEquals(2, msg.getRepeatedFloatCount());
+    assertTrue(789f == msg.getRepeatedFloat(0));
+    assertTrue(456f == msg.getRepeatedFloat(1));
+    msg.clearRepeatedFloat();
+    assertEquals(0, msg.getRepeatedFloatCount());
+    msg.clearRepeatedFloat()
+       .addRepeatedFloat(456f);
+    assertEquals(1, msg.getRepeatedFloatCount());
+    assertTrue(456f == msg.getRepeatedFloat(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedFloatCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedFloat(123f);
+    assertEquals(1, msg.getRepeatedFloatCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedFloatCount());
+    assertTrue(123f == newMsg.getRepeatedFloat(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedFloat(123f)
+       .addRepeatedFloat(456f);
+    assertEquals(2, msg.getRepeatedFloatCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 12);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedFloatCount());
+    assertTrue(123f == newMsg.getRepeatedFloat(0));
+    assertTrue(456f == newMsg.getRepeatedFloat(1));
+  }
+
+  public void testMicroRepeatedDouble() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedDoubleCount());
+    msg.addRepeatedDouble(123.0);
+    assertEquals(1, msg.getRepeatedDoubleCount());
+    assertTrue(123.0 == msg.getRepeatedDouble(0));
+    msg.addRepeatedDouble(456.0);
+    assertEquals(2, msg.getRepeatedDoubleCount());
+    assertTrue(123.0 == msg.getRepeatedDouble(0));
+    assertTrue(456.0 == msg.getRepeatedDouble(1));
+    msg.setRepeatedDouble(0, 789.0);
+    assertEquals(2, msg.getRepeatedDoubleCount());
+    assertTrue(789.0 == msg.getRepeatedDouble(0));
+    assertTrue(456.0 == msg.getRepeatedDouble(1));
+    msg.clearRepeatedDouble();
+    assertEquals(0, msg.getRepeatedDoubleCount());
+    msg.clearRepeatedDouble()
+       .addRepeatedDouble(456.0);
+    assertEquals(1, msg.getRepeatedDoubleCount());
+    assertTrue(456.0 == msg.getRepeatedDouble(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedDoubleCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedDouble(123.0);
+    assertEquals(1, msg.getRepeatedDoubleCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedDoubleCount());
+    assertTrue(123.0 == newMsg.getRepeatedDouble(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedDouble(123.0)
+       .addRepeatedDouble(456.0);
+    assertEquals(2, msg.getRepeatedDoubleCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 20);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedDoubleCount());
+    assertTrue(123.0 == newMsg.getRepeatedDouble(0));
+    assertTrue(456.0 == newMsg.getRepeatedDouble(1));
+  }
+
+  public void testMicroRepeatedBool() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedBoolCount());
+    msg.addRepeatedBool(true);
+    assertEquals(1, msg.getRepeatedBoolCount());
+    assertEquals(true, msg.getRepeatedBool(0));
+    msg.addRepeatedBool(false);
+    assertEquals(2, msg.getRepeatedBoolCount());
+    assertEquals(true, msg.getRepeatedBool(0));
+    assertEquals(false, msg.getRepeatedBool(1));
+    msg.setRepeatedBool(0, false);
+    assertEquals(2, msg.getRepeatedBoolCount());
+    assertEquals(false, msg.getRepeatedBool(0));
+    assertEquals(false, msg.getRepeatedBool(1));
+    msg.clearRepeatedBool();
+    assertEquals(0, msg.getRepeatedBoolCount());
+    msg.clearRepeatedBool()
+       .addRepeatedBool(true);
+    assertEquals(1, msg.getRepeatedBoolCount());
+    assertEquals(true, msg.getRepeatedBool(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedBoolCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedBool(false);
+    assertEquals(1, msg.getRepeatedBoolCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedBoolCount());
+    assertEquals(false, newMsg.getRepeatedBool(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedBool(true)
+       .addRepeatedBool(false);
+    assertEquals(2, msg.getRepeatedBoolCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedBoolCount());
+    assertEquals(true, newMsg.getRepeatedBool(0));
+    assertEquals(false, newMsg.getRepeatedBool(1));
+  }
+
+  public void testMicroRepeatedString() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedStringCount());
+    msg.addRepeatedString("hello");
+    assertEquals(1, msg.getRepeatedStringCount());
+    assertEquals("hello", msg.getRepeatedString(0));
+    msg.addRepeatedString("bye");
+    assertEquals(2, msg.getRepeatedStringCount());
+    assertEquals("hello", msg.getRepeatedString(0));
+    assertEquals("bye", msg.getRepeatedString(1));
+    msg.setRepeatedString(0, "boo");
+    assertEquals(2, msg.getRepeatedStringCount());
+    assertEquals("boo", msg.getRepeatedString(0));
+    assertEquals("bye", msg.getRepeatedString(1));
+    msg.clearRepeatedString();
+    assertEquals(0, msg.getRepeatedStringCount());
+    msg.clearRepeatedString()
+       .addRepeatedString("hello");
+    assertEquals(1, msg.getRepeatedStringCount());
+    assertEquals("hello", msg.getRepeatedString(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedStringCount());
+
+    // Test 1 entry and an empty string
+    msg.clear()
+       .addRepeatedString("");
+    assertEquals(1, msg.getRepeatedStringCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedStringCount());
+    assertEquals("", newMsg.getRepeatedString(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedString("hello")
+       .addRepeatedString("world");
+    assertEquals(2, msg.getRepeatedStringCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedStringCount());
+    assertEquals("hello", newMsg.getRepeatedString(0));
+    assertEquals("world", newMsg.getRepeatedString(1));
+  }
+
+  public void testMicroRepeatedBytes() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedBytesCount());
+    msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"));
+    assertEquals(1, msg.getRepeatedBytesCount());
+    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
+    msg.addRepeatedBytes(ByteStringMicro.copyFromUtf8("bye"));
+    assertEquals(2, msg.getRepeatedBytesCount());
+    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
+    assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8());
+    msg.setRepeatedBytes(0, ByteStringMicro.copyFromUtf8("boo"));
+    assertEquals(2, msg.getRepeatedBytesCount());
+    assertEquals("boo", msg.getRepeatedBytes(0).toStringUtf8());
+    assertEquals("bye", msg.getRepeatedBytes(1).toStringUtf8());
+    msg.clearRepeatedBytes();
+    assertEquals(0, msg.getRepeatedBytesCount());
+    msg.clearRepeatedBytes()
+       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"));
+    assertEquals(1, msg.getRepeatedBytesCount());
+    assertEquals("hello", msg.getRepeatedBytes(0).toStringUtf8());
+    msg.clear();
+    assertEquals(0, msg.getRepeatedBytesCount());
+
+    // Test 1 entry and an empty byte array can be serialized
+    msg.clear()
+       .addRepeatedBytes(ByteStringMicro.copyFromUtf8(""));
+    assertEquals(1, msg.getRepeatedBytesCount());
+    assertEquals("", msg.getRepeatedBytes(0).toStringUtf8());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedBytesCount());
+    assertEquals("", newMsg.getRepeatedBytes(0).toStringUtf8());
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("hello"))
+       .addRepeatedBytes(ByteStringMicro.copyFromUtf8("world"));
+    assertEquals(2, msg.getRepeatedBytesCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedBytesCount());
+    assertEquals("hello", newMsg.getRepeatedBytes(0).toStringUtf8());
+    assertEquals("world", newMsg.getRepeatedBytes(1).toStringUtf8());
+  }
+
+  public void testMicroRepeatedGroup() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    TestAllTypesMicro.RepeatedGroup group0 =
+      new TestAllTypesMicro.RepeatedGroup().setA(0);
+    TestAllTypesMicro.RepeatedGroup group1 =
+      new TestAllTypesMicro.RepeatedGroup().setA(1);
+    TestAllTypesMicro.RepeatedGroup group2 =
+      new TestAllTypesMicro.RepeatedGroup().setA(2);
+
+    msg.addRepeatedGroup(group0);
+    assertEquals(1, msg.getRepeatedGroupCount());
+    assertEquals(0, msg.getRepeatedGroup(0).getA());
+    msg.addRepeatedGroup(group1);
+    assertEquals(2, msg.getRepeatedGroupCount());
+    assertEquals(0, msg.getRepeatedGroup(0).getA());
+    assertEquals(1, msg.getRepeatedGroup(1).getA());
+    msg.setRepeatedGroup(0, group2);
+    assertEquals(2, msg.getRepeatedGroupCount());
+    assertEquals(2, msg.getRepeatedGroup(0).getA());
+    assertEquals(1, msg.getRepeatedGroup(1).getA());
+    msg.clearRepeatedGroup();
+    assertEquals(0, msg.getRepeatedGroupCount());
+    msg.clearRepeatedGroup()
+       .addRepeatedGroup(group1);
+    assertEquals(1, msg.getRepeatedGroupCount());
+    assertEquals(1, msg.getRepeatedGroup(0).getA());
+    msg.clear();
+    assertEquals(0, msg.getRepeatedGroupCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedGroup(group0);
+    assertEquals(1, msg.getRepeatedGroupCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 7);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedGroupCount());
+    assertEquals(0, newMsg.getRepeatedGroup(0).getA());
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedGroup(group0)
+       .addRepeatedGroup(group1);
+    assertEquals(2, msg.getRepeatedGroupCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 14);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedGroupCount());
+    assertEquals(0, newMsg.getRepeatedGroup(0).getA());
+    assertEquals(1, newMsg.getRepeatedGroup(1).getA());
+  }
+
+
+  public void testMicroRepeatedNestedMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    TestAllTypesMicro.NestedMessage nestedMsg0 =
+      new TestAllTypesMicro.NestedMessage().setBb(0);
+    TestAllTypesMicro.NestedMessage nestedMsg1 =
+      new TestAllTypesMicro.NestedMessage().setBb(1);
+    TestAllTypesMicro.NestedMessage nestedMsg2 =
+      new TestAllTypesMicro.NestedMessage().setBb(2);
+
+    msg.addRepeatedNestedMessage(nestedMsg0);
+    assertEquals(1, msg.getRepeatedNestedMessageCount());
+    assertEquals(0, msg.getRepeatedNestedMessage(0).getBb());
+    msg.addRepeatedNestedMessage(nestedMsg1);
+    assertEquals(2, msg.getRepeatedNestedMessageCount());
+    assertEquals(0, msg.getRepeatedNestedMessage(0).getBb());
+    assertEquals(1, msg.getRepeatedNestedMessage(1).getBb());
+    msg.setRepeatedNestedMessage(0, nestedMsg2);
+    assertEquals(2, msg.getRepeatedNestedMessageCount());
+    assertEquals(2, msg.getRepeatedNestedMessage(0).getBb());
+    assertEquals(1, msg.getRepeatedNestedMessage(1).getBb());
+    msg.clearRepeatedNestedMessage();
+    assertEquals(0, msg.getRepeatedNestedMessageCount());
+    msg.clearRepeatedNestedMessage()
+       .addRepeatedNestedMessage(nestedMsg1);
+    assertEquals(1, msg.getRepeatedNestedMessageCount());
+    assertEquals(1, msg.getRepeatedNestedMessage(0).getBb());
+    msg.clear();
+    assertEquals(0, msg.getRepeatedNestedMessageCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedNestedMessage(nestedMsg0);
+    assertEquals(1, msg.getRepeatedNestedMessageCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedNestedMessageCount());
+    assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb());
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedNestedMessage(nestedMsg0)
+       .addRepeatedNestedMessage(nestedMsg1);
+    assertEquals(2, msg.getRepeatedNestedMessageCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedNestedMessageCount());
+    assertEquals(0, newMsg.getRepeatedNestedMessage(0).getBb());
+    assertEquals(1, newMsg.getRepeatedNestedMessage(1).getBb());
+  }
+
+  public void testMicroRepeatedForeignMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    MicroOuterClass.ForeignMessageMicro foreignMsg0 =
+      new MicroOuterClass.ForeignMessageMicro().setC(0);
+    MicroOuterClass.ForeignMessageMicro foreignMsg1 =
+      new MicroOuterClass.ForeignMessageMicro().setC(1);
+    MicroOuterClass.ForeignMessageMicro foreignMsg2 =
+      new MicroOuterClass.ForeignMessageMicro().setC(2);
+
+    msg.addRepeatedForeignMessage(foreignMsg0);
+    assertEquals(1, msg.getRepeatedForeignMessageCount());
+    assertEquals(0, msg.getRepeatedForeignMessage(0).getC());
+    msg.addRepeatedForeignMessage(foreignMsg1);
+    assertEquals(2, msg.getRepeatedForeignMessageCount());
+    assertEquals(0, msg.getRepeatedForeignMessage(0).getC());
+    assertEquals(1, msg.getRepeatedForeignMessage(1).getC());
+    msg.setRepeatedForeignMessage(0, foreignMsg2);
+    assertEquals(2, msg.getRepeatedForeignMessageCount());
+    assertEquals(2, msg.getRepeatedForeignMessage(0).getC());
+    assertEquals(1, msg.getRepeatedForeignMessage(1).getC());
+    msg.clearRepeatedForeignMessage();
+    assertEquals(0, msg.getRepeatedForeignMessageCount());
+    msg.clearRepeatedForeignMessage()
+       .addRepeatedForeignMessage(foreignMsg1);
+    assertEquals(1, msg.getRepeatedForeignMessageCount());
+    assertEquals(1, msg.getRepeatedForeignMessage(0).getC());
+    msg.clear();
+    assertEquals(0, msg.getRepeatedForeignMessageCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedForeignMessage(foreignMsg0);
+    assertEquals(1, msg.getRepeatedForeignMessageCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedForeignMessageCount());
+    assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC());
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedForeignMessage(foreignMsg0)
+       .addRepeatedForeignMessage(foreignMsg1);
+    assertEquals(2, msg.getRepeatedForeignMessageCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedForeignMessageCount());
+    assertEquals(0, newMsg.getRepeatedForeignMessage(0).getC());
+    assertEquals(1, newMsg.getRepeatedForeignMessage(1).getC());
+  }
+
+  public void testMicroRepeatedImportMessage() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    UnittestImportMicro.ImportMessageMicro importMsg0 =
+      new UnittestImportMicro.ImportMessageMicro().setD(0);
+    UnittestImportMicro.ImportMessageMicro importMsg1 =
+      new UnittestImportMicro.ImportMessageMicro().setD(1);
+    UnittestImportMicro.ImportMessageMicro importMsg2 =
+      new UnittestImportMicro.ImportMessageMicro().setD(2);
+
+    msg.addRepeatedImportMessage(importMsg0);
+    assertEquals(1, msg.getRepeatedImportMessageCount());
+    assertEquals(0, msg.getRepeatedImportMessage(0).getD());
+    msg.addRepeatedImportMessage(importMsg1);
+    assertEquals(2, msg.getRepeatedImportMessageCount());
+    assertEquals(0, msg.getRepeatedImportMessage(0).getD());
+    assertEquals(1, msg.getRepeatedImportMessage(1).getD());
+    msg.setRepeatedImportMessage(0, importMsg2);
+    assertEquals(2, msg.getRepeatedImportMessageCount());
+    assertEquals(2, msg.getRepeatedImportMessage(0).getD());
+    assertEquals(1, msg.getRepeatedImportMessage(1).getD());
+    msg.clearRepeatedImportMessage();
+    assertEquals(0, msg.getRepeatedImportMessageCount());
+    msg.clearRepeatedImportMessage()
+       .addRepeatedImportMessage(importMsg1);
+    assertEquals(1, msg.getRepeatedImportMessageCount());
+    assertEquals(1, msg.getRepeatedImportMessage(0).getD());
+    msg.clear();
+    assertEquals(0, msg.getRepeatedImportMessageCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedImportMessage(importMsg0);
+    assertEquals(1, msg.getRepeatedImportMessageCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 5);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedImportMessageCount());
+    assertEquals(0, newMsg.getRepeatedImportMessage(0).getD());
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedImportMessage(importMsg0)
+       .addRepeatedImportMessage(importMsg1);
+    assertEquals(2, msg.getRepeatedImportMessageCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 10);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedImportMessageCount());
+    assertEquals(0, newMsg.getRepeatedImportMessage(0).getD());
+    assertEquals(1, newMsg.getRepeatedImportMessage(1).getD());
+  }
+
+  public void testMicroRepeatedNestedEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.addRepeatedNestedEnum(TestAllTypesMicro.FOO);
+    assertEquals(1, msg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
+    msg.addRepeatedNestedEnum(TestAllTypesMicro.BAR);
+    assertEquals(2, msg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
+    msg.setRepeatedNestedEnum(0, TestAllTypesMicro.BAZ);
+    assertEquals(2, msg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.BAZ, msg.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
+    msg.clearRepeatedNestedEnum();
+    assertEquals(0, msg.getRepeatedNestedEnumCount());
+    msg.clearRepeatedNestedEnum()
+       .addRepeatedNestedEnum(TestAllTypesMicro.BAR);
+    assertEquals(1, msg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedNestedEnumCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedNestedEnum(TestAllTypesMicro.FOO);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedNestedEnum(TestAllTypesMicro.FOO)
+       .addRepeatedNestedEnum(TestAllTypesMicro.BAR);
+    assertEquals(2, msg.getRepeatedNestedEnumCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedNestedEnumCount());
+    assertEquals(TestAllTypesMicro.FOO, msg.getRepeatedNestedEnum(0));
+    assertEquals(TestAllTypesMicro.BAR, msg.getRepeatedNestedEnum(1));
+  }
+
+  public void testMicroRepeatedForeignEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO);
+    assertEquals(1, msg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
+    msg.addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
+    assertEquals(2, msg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
+    msg.setRepeatedForeignEnum(0, MicroOuterClass.FOREIGN_MICRO_BAZ);
+    assertEquals(2, msg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAZ, msg.getRepeatedForeignEnum(0));
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
+    msg.clearRepeatedForeignEnum();
+    assertEquals(0, msg.getRepeatedForeignEnumCount());
+    msg.clearRepeatedForeignEnum()
+       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
+    assertEquals(1, msg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedForeignEnumCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_FOO)
+       .addRepeatedForeignEnum(MicroOuterClass.FOREIGN_MICRO_BAR);
+    assertEquals(2, msg.getRepeatedForeignEnumCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedForeignEnumCount());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_FOO, msg.getRepeatedForeignEnum(0));
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getRepeatedForeignEnum(1));
+  }
+
+  public void testMicroRepeatedImportEnum() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO);
+    assertEquals(1, msg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
+    msg.addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
+    assertEquals(2, msg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
+    msg.setRepeatedImportEnum(0, UnittestImportMicro.IMPORT_MICRO_BAZ);
+    assertEquals(2, msg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAZ, msg.getRepeatedImportEnum(0));
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
+    msg.clearRepeatedImportEnum();
+    assertEquals(0, msg.getRepeatedImportEnumCount());
+    msg.clearRepeatedImportEnum()
+       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
+    assertEquals(1, msg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedImportEnumCount());
+
+    // Test 1 entry
+    msg.clear()
+       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO);
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_FOO)
+       .addRepeatedImportEnum(UnittestImportMicro.IMPORT_MICRO_BAR);
+    assertEquals(2, msg.getRepeatedImportEnumCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 6);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedImportEnumCount());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_FOO, msg.getRepeatedImportEnum(0));
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getRepeatedImportEnum(1));
+  }
+
+  public void testMicroRepeatedStringPiece() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedStringPieceCount());
+    msg.addRepeatedStringPiece("hello");
+    assertEquals(1, msg.getRepeatedStringPieceCount());
+    assertEquals("hello", msg.getRepeatedStringPiece(0));
+    msg.addRepeatedStringPiece("bye");
+    assertEquals(2, msg.getRepeatedStringPieceCount());
+    assertEquals("hello", msg.getRepeatedStringPiece(0));
+    assertEquals("bye", msg.getRepeatedStringPiece(1));
+    msg.setRepeatedStringPiece(0, "boo");
+    assertEquals(2, msg.getRepeatedStringPieceCount());
+    assertEquals("boo", msg.getRepeatedStringPiece(0));
+    assertEquals("bye", msg.getRepeatedStringPiece(1));
+    msg.clearRepeatedStringPiece();
+    assertEquals(0, msg.getRepeatedStringPieceCount());
+    msg.clearRepeatedStringPiece()
+       .addRepeatedStringPiece("hello");
+    assertEquals(1, msg.getRepeatedStringPieceCount());
+    assertEquals("hello", msg.getRepeatedStringPiece(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedStringPieceCount());
+
+    // Test 1 entry and an empty string
+    msg.clear()
+       .addRepeatedStringPiece("");
+    assertEquals(1, msg.getRepeatedStringPieceCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedStringPieceCount());
+    assertEquals("", newMsg.getRepeatedStringPiece(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedStringPiece("hello")
+       .addRepeatedStringPiece("world");
+    assertEquals(2, msg.getRepeatedStringPieceCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedStringPieceCount());
+    assertEquals("hello", newMsg.getRepeatedStringPiece(0));
+    assertEquals("world", newMsg.getRepeatedStringPiece(1));
+  }
+
+  public void testMicroRepeatedCord() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertEquals(0, msg.getRepeatedCordCount());
+    msg.addRepeatedCord("hello");
+    assertEquals(1, msg.getRepeatedCordCount());
+    assertEquals("hello", msg.getRepeatedCord(0));
+    msg.addRepeatedCord("bye");
+    assertEquals(2, msg.getRepeatedCordCount());
+    assertEquals("hello", msg.getRepeatedCord(0));
+    assertEquals("bye", msg.getRepeatedCord(1));
+    msg.setRepeatedCord(0, "boo");
+    assertEquals(2, msg.getRepeatedCordCount());
+    assertEquals("boo", msg.getRepeatedCord(0));
+    assertEquals("bye", msg.getRepeatedCord(1));
+    msg.clearRepeatedCord();
+    assertEquals(0, msg.getRepeatedCordCount());
+    msg.clearRepeatedCord()
+       .addRepeatedCord("hello");
+    assertEquals(1, msg.getRepeatedCordCount());
+    assertEquals("hello", msg.getRepeatedCord(0));
+    msg.clear();
+    assertEquals(0, msg.getRepeatedCordCount());
+
+    // Test 1 entry and an empty string
+    msg.clear()
+       .addRepeatedCord("");
+    assertEquals(1, msg.getRepeatedCordCount());
+    byte [] result = msg.toByteArray();
+    int msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 3);
+    assertEquals(result.length, msgSerializedSize);
+    TestAllTypesMicro newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(1, newMsg.getRepeatedCordCount());
+    assertEquals("", newMsg.getRepeatedCord(0));
+
+    // Test 2 entries
+    msg.clear()
+       .addRepeatedCord("hello")
+       .addRepeatedCord("world");
+    assertEquals(2, msg.getRepeatedCordCount());
+    result = msg.toByteArray();
+    msgSerializedSize = msg.getSerializedSize();
+    //System.out.printf("mss=%d result.length=%d\n", msgSerializedSize, result.length);
+    assertTrue(msgSerializedSize == 16);
+    assertEquals(result.length, msgSerializedSize);
+
+    newMsg = TestAllTypesMicro.parseFrom(result);
+    assertEquals(2, newMsg.getRepeatedCordCount());
+    assertEquals("hello", newMsg.getRepeatedCord(0));
+    assertEquals("world", newMsg.getRepeatedCord(1));
+  }
+
+  public void testMicroDefaults() throws Exception {
+    TestAllTypesMicro msg = new TestAllTypesMicro();
+    assertFalse(msg.hasDefaultInt32());
+    assertEquals(41, msg.getDefaultInt32());
+    assertFalse(msg.hasDefaultInt64());
+    assertEquals(42, msg.getDefaultInt64());
+    assertFalse(msg.hasDefaultUint32());
+    assertEquals(43, msg.getDefaultUint32());
+    assertFalse(msg.hasDefaultUint64());
+    assertEquals(44, msg.getDefaultUint64());
+    assertFalse(msg.hasDefaultSint32());
+    assertEquals(-45, msg.getDefaultSint32());
+    assertFalse(msg.hasDefaultSint64());
+    assertEquals(46, msg.getDefaultSint64());
+    assertFalse(msg.hasDefaultFixed32());
+    assertEquals(47, msg.getDefaultFixed32());
+    assertFalse(msg.hasDefaultFixed64());
+    assertEquals(48, msg.getDefaultFixed64());
+    assertFalse(msg.hasDefaultSfixed32());
+    assertEquals(49, msg.getDefaultSfixed32());
+    assertFalse(msg.hasDefaultSfixed64());
+    assertEquals(-50, msg.getDefaultSfixed64());
+    assertFalse(msg.hasDefaultFloat());
+    assertTrue(51.5f == msg.getDefaultFloat());
+    assertFalse(msg.hasDefaultDouble());
+    assertTrue(52.0e3 == msg.getDefaultDouble());
+    assertFalse(msg.hasDefaultBool());
+    assertEquals(true, msg.getDefaultBool());
+    assertFalse(msg.hasDefaultString());
+    assertEquals("hello", msg.getDefaultString());
+    assertFalse(msg.hasDefaultBytes());
+    assertEquals("world", msg.getDefaultBytes().toStringUtf8());
+    assertFalse(msg.hasDefaultNestedEnum());
+    assertEquals(TestAllTypesMicro.BAR, msg.getDefaultNestedEnum());
+    assertFalse(msg.hasDefaultForeignEnum());
+    assertEquals(MicroOuterClass.FOREIGN_MICRO_BAR, msg.getDefaultForeignEnum());
+    assertFalse(msg.hasDefaultImportEnum());
+    assertEquals(UnittestImportMicro.IMPORT_MICRO_BAR, msg.getDefaultImportEnum());
+  }
+}
diff --git a/java/src/test/java/com/google/protobuf/PerfTimer.java b/java/src/test/java/com/google/protobuf/PerfTimer.java
new file mode 100644
index 0000000..d6df4ff
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/PerfTimer.java
@@ -0,0 +1,832 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.protobuf;
+
+import java.util.Arrays;
+
+/**
+ * A Performance Timing class that can be used to estimate the amount of time a
+ * sequence of code takes. The typical code sequence would be as follows:</p>
+ * <code>
+ PerfTimer pt = new PerfTimer();
+ pt.calibrate();
+ pt.timeEachAutomatically(new Runnable() = {
+    public void run() {
+        // Add code to time
+    }
+ });
+ System.out.printf("time per loop=" + pt);
+
+ * The calibrate method determines the overhead of timing the run() method and
+ * the number of times to call the run() method to have approximately 1% precision
+ * for timing. The method pt.stats() method will return a string containing some
+ * statistics tpl, il, ol, min, max, mean, median, stddev and total.
+ *
+ * tpl    ::= Timer per loop
+ * min    ::= minimum time one call to run() took
+ * stddev ::= Standard deviation of the collected times
+ * mean   ::= the average time to call run()
+ * median ::= 1/2 the times were > than this time and 1/2 were less.
+ * total  ::= Sum of the times collected.
+ * il     ::= innerLoops; the number of times run() between each call to start/stop
+ * ol     ::= outerLoops, the number of times start/stop was called
+ *
+ * You can also use start/stop/restart to do simple timing:
+ *
+ * pt.start();
+ * a += 1;
+ * pt.stop();
+ * pt.log("time=" + pt);
+ * pt.restart();
+ * doSomething();
+ * pt.stop();
+ * System.out.printf("time=" + pt);
+ * </code>
+ *
+ * @author wink@google.com (Wink Saville)
+ */
+public class PerfTimer {
+    /** No debug */
+    public static final int DEBUG_LEVEL_NONE = 0;
+
+    /** Some debug */
+    public static final int DEBUG_LEVEL_SOME = 1;
+
+    /** All debug */
+    public static final int DEBUG_LEVEL_ALL = 2;
+
+    /** Timer ticks per microsecond */
+    private static final double TICKS_PER_MICROSECOND = 1000.0;
+
+    /** Random number generator */
+    java.util.Random rng = new java.util.Random();
+
+    /** get ticks */
+    private static long getTicks() {
+        return System.nanoTime();
+    }
+
+    /** Debug logging */
+    private static void log(String s) {
+        System.out.printf(String.format("[PerfTimer] %s\n", s));
+    }
+
+    /** Outer loops for timeEachAutomatically */
+    private static final int OUTER_LOOPS = 100;
+
+    /** Thrown if an error occurs while timing */
+    public static class PerfTimerException extends RuntimeException {
+    }
+
+    /**
+     * Calibration record
+     */
+    public static class CalibrationRec {
+        /** Runnable overhead */
+        public double mRunnableOverheadInMicros = 0.0;
+
+        /** Minimum Threshold value for timeEachAutomaticaly */
+        public double mMinThresholdInMicros = 3000.0;
+
+        /** Maximum Threshold value for timeEachAutomaticaly */
+        public double mMaxThresholdInMicros = 6000.0;
+
+        /** Desired precision in decimal digits */
+        public double mPrecisionInDecimalDigits = 2.0;
+
+        /**
+         * Default number of retries if the standard deviation ratio is too
+         * large
+         */
+        public final int mStdDevRetrys = 5;
+
+        /** Default maximum standard deviation radio */
+        public final double mMaxStdDevRatio = 0.15;
+
+        /** Number of votes looking for smallest time per loop */
+        public final int mVotes = 3;
+
+        /** Convert to string */
+        @Override
+        public String toString() {
+            return String
+                    .format(
+                            "oh=%.6fus minT=%.6fus maxT=%.6fus prc=%,.3f stdDevRetrys=%d maxStdDevRatio=%.2f votes=%d",
+                            mRunnableOverheadInMicros, mMinThresholdInMicros,
+                            mMaxThresholdInMicros, mPrecisionInDecimalDigits, mStdDevRetrys,
+                            mMaxStdDevRatio, mVotes);
+        }
+    }
+
+    /**
+     * Calibration record
+     */
+    private CalibrationRec mCr;
+
+    /**
+     * Statistics calculated on the timing data.
+     */
+    public static class Stats {
+        /** Number of outer loops */
+        private int mOuterLoops;
+
+        /** Number of inner loops */
+        private int mInnerLoops;
+
+        /** Minimum time in times array */
+        private long mMin;
+
+        /** Maximum time in times array */
+        private long mMax;
+
+        /** Median value in times array */
+        private double mMedian;
+
+        /** The mean (average) of the values in times array */
+        private double mMean;
+
+        /** The standard deviation of the values in times array */
+        private double mStdDev;
+
+        private int mStdDevTooLargeCount;
+
+        /** Sum of the times in the times array */
+        private double mTotal;
+
+        /** Initialize */
+        public void init() {
+            mInnerLoops = 1;
+            mOuterLoops = 1;
+            mMin = 0;
+            mMax = 0;
+            mMedian = 0;
+            mMean = 0;
+            mStdDev = 0;
+            mStdDevTooLargeCount = 0;
+            mTotal = 0;
+        }
+
+        /** Constructor */
+        public Stats() {
+            init();
+        }
+
+        /** Set number of inner loops */
+        public void setInnerLoops(int loops) {
+            mInnerLoops = loops;
+        }
+
+        /** Get number of inner loops */
+        public int getInnerLoops() {
+            return mInnerLoops;
+        }
+
+        /** Set number of inner loops */
+        public void setOuterLoops(int loops) {
+            mOuterLoops = loops;
+        }
+
+        /** Get number of inner loops */
+        public int getOuterLoops() {
+            return mOuterLoops;
+        }
+
+        /**
+         * Minimum value of collected data in microseconds, valid after analyze.
+         */
+        public double getMinInMicros() {
+            return mMin / TICKS_PER_MICROSECOND;
+        }
+
+        /**
+         * Maximum value of collected data in microseconds, valid after analyze.
+         */
+        public double getMaxInMicros() {
+            return mMax / TICKS_PER_MICROSECOND;
+        }
+
+        /**
+         * Sum of the values of collected data in microseconds, valid after
+         * analyze.
+         */
+        public double getTotalInMicros() {
+            return mTotal / TICKS_PER_MICROSECOND;
+        }
+
+        /** Sum of the values of collected data in seconds, valid after analyze. */
+        public double getTotalInSecs() {
+            return mTotal / (TICKS_PER_MICROSECOND * 1000000.0);
+        }
+
+        /** Sum of the values of collected data in seconds, valid after analyze. */
+        public double getMeanInMicros() {
+            return mMean / TICKS_PER_MICROSECOND;
+        }
+
+        /** Median value of collected data in microseconds, valid after analyze. */
+        public double getMedianInMicros() {
+            return mMedian / TICKS_PER_MICROSECOND;
+        }
+
+        /**
+         * Standard deviation of collected data in microseconds, valid after
+         * analyze.
+         */
+        public double getStdDevInMicros() {
+            return mStdDev / TICKS_PER_MICROSECOND;
+        }
+
+        public double getStdDevRatio() {
+            return mStdDev / mMin;
+        }
+
+        /** Return true if (mStdDev / mMin) <= maxStdDevRation */
+        public boolean stdDevOk(double maxStdDevRatio) {
+            return getStdDevRatio() <= maxStdDevRatio;
+        }
+
+        /** Increment StdDevTooLargeCount */
+        public void incStdDevTooLargeCount() {
+            mStdDevTooLargeCount += 1;
+        }
+
+        /** Return number of times stdDev was not ok */
+        public int getStdDevTooLargeCount() {
+            return mStdDevTooLargeCount;
+        }
+
+        /** Return time per loop */
+        public double getTimePerLoop() {
+                return mMin / TICKS_PER_MICROSECOND / mInnerLoops;
+        }
+
+        /**
+         * Calculate the stats for the data. Note the data in the range will be
+         * sorted.
+         *
+         * @param data
+         * @param count
+         */
+        public Stats calculate(long data[], int count) {
+            if (count == 1) {
+                mMin = mMax = data[0];
+                mTotal = mMedian = mMean = data[0];
+                mStdDev = 0;
+            } else if (count > 1) {
+                Arrays.sort(data, 0, count);
+                mMin = data[0];
+                mMax = data[count - 1];
+                if ((count & 1) == 1) {
+                    mMedian = data[((count + 1) / 2) - 1];
+                } else {
+                    mMedian = (data[count / 2] + data[(count / 2) - 1]) / 2;
+                }
+                mTotal = 0;
+                double sumSquares = 0;
+                for (int i = 0; i < count; i++) {
+                    long t = data[i];
+                    mTotal += t;
+                    sumSquares += t * t;
+                }
+                mMean = mTotal / count;
+                double variance = (sumSquares / count) - (mMean * mMean);
+                mStdDev = Math.pow(variance, 0.5);
+            } else {
+                init();
+            }
+            return this;
+        }
+
+        /** Convert to string */
+        @Override
+            public String toString() {
+                double timePerLoop = getTimePerLoop();
+                double stdDevPerLoop = mStdDev / TICKS_PER_MICROSECOND / mInnerLoops;
+                return String.format(
+                        "tpl=%,.6fus stdDev=%,.6fus tpl/stdDev=%.2fpercent min=%,.6fus median=%,.6fus mean=%,.6fus max=%,.6fus total=%,.6fs il=%d, ol=%d tlc=%d",
+                        timePerLoop, stdDevPerLoop, (stdDevPerLoop / timePerLoop) * 100, mMin
+                        / TICKS_PER_MICROSECOND, mMedian / TICKS_PER_MICROSECOND, mMean
+                        / TICKS_PER_MICROSECOND, mMax / TICKS_PER_MICROSECOND, mTotal
+                        / (TICKS_PER_MICROSECOND * 1000000.0), mInnerLoops, mOuterLoops, mStdDevTooLargeCount);
+            }
+    }
+
+    /** Statistics */
+    private Stats mStats = new Stats();
+
+    /** Statistics of the clock precision */
+    private Stats mClockStats;
+
+    /** Number of items in times array */
+    private int mCount;
+
+    /** Array of stop - start times */
+    private long mTimes[];
+
+    /** Time of last started */
+    private long mStart;
+
+    /** Sleep a little so we don't look like a hog */
+    private void sleep() {
+        try {
+            Thread.sleep(0);
+        } catch (InterruptedException e) {
+            // Ignore exception
+        }
+    }
+
+    /** Empty Runnable used for determining overhead */
+    private Runnable mEmptyRunnable = new Runnable() {
+        public void run() {
+        }
+    };
+
+    /** Initialize */
+    private void init(int maxCount, CalibrationRec cr) {
+        mTimes = new long[maxCount];
+        mCr = cr;
+        reset();
+    }
+
+    /** Construct the stop watch */
+    public PerfTimer() {
+        init(10, new CalibrationRec());
+    }
+
+    /** Construct setting size of times array */
+    public PerfTimer(int maxCount) {
+        init(maxCount, new CalibrationRec());
+    }
+
+    /** Construct the stop watch */
+    public PerfTimer(CalibrationRec cr) {
+        init(10, cr);
+    }
+
+    /** Construct the stop watch */
+    public PerfTimer(int maxCount, CalibrationRec cr) {
+        init(maxCount, cr);
+    }
+
+    /** Reset the contents of the times array */
+    public PerfTimer reset() {
+        mCount = 0;
+        mStats.init();
+        return this;
+    }
+
+    /** Reset and then start the timer */
+    public PerfTimer restart() {
+        reset();
+        mStart = getTicks();
+        return this;
+    }
+
+    /** Start timing */
+    public PerfTimer start() {
+        mStart = getTicks();
+        return this;
+    }
+
+    /**
+     * Record the difference between start and now in the times array
+     * incrementing count. The time will be stored in the times array if the
+     * array is not full.
+     */
+    public PerfTimer stop() {
+        long stop = getTicks();
+        if (mCount < mTimes.length) {
+            mTimes[mCount++] = stop - mStart;
+        }
+        return this;
+    }
+
+    /**
+     * Time how long it takes to execute runnable.run() innerLoop number of
+     * times outerLoops number of times.
+     *
+     * @param outerLoops
+     * @param innerLoops
+     * @param runnable
+     * @return PerfTimer
+     */
+    public PerfTimer timeEach(Stats stats, int outerLoops, int innerLoops, Runnable runnable) {
+        reset();
+        resize(outerLoops);
+        stats.setOuterLoops(outerLoops);
+        stats.setInnerLoops(innerLoops);
+        for (int i = 0; i < outerLoops; i++) {
+            start();
+            for (int j = 0; j < innerLoops; j++) {
+                runnable.run();
+            }
+            stop();
+            sleep();
+        }
+        return this;
+    }
+
+    /**
+     * Time how long it takes to execute runnable.run(). Runs runnable votes
+     * times and returns the Stats of the fastest run. The actual number times
+     * that runnable.run() is executes is enough times so that it runs at least
+     * minThreadholeInMicros but not greater than maxThreadholdInMicro. This
+     * minimizes the chance that long context switches influence the result.
+     *
+     * @param votes is the number of runnable will be executed to determine
+     *            fastest run
+     * @param outerLoops is the number of of times the inner loop is run
+     * @param initialInnerLoops is the initial inner loop
+     * @param maxStdDevRetrys if the maxStdDevRatio is exceeded this number of
+     *            time the PerfTimerException is thrown.
+     * @param maxStdDevRatio the ratio of the standard deviation of the run and
+     *            the time to run.
+     * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL
+     * @param runnable is the code to test.
+     * @return Stats of the fastest run.
+     */
+    public Stats timeEachAutomatically(int votes, int outerLoops, int initialInnerLoops,
+            double minThresholdInMicros, double maxThresholdInMicros, int maxStdDevRetrys,
+            double maxStdDevRatio, int debugLevel, Runnable runnable) throws PerfTimerException {
+        Stats minStats = null;
+
+        for (int v = 0; v < votes; v++) {
+            boolean successful = false;
+            Stats stats = new Stats();
+            int innerLoops = initialInnerLoops;
+
+            /* Warm up cache */
+            timeEach(stats, outerLoops, initialInnerLoops, runnable);
+
+            for (int stdDevRetrys = 0; stdDevRetrys < maxStdDevRetrys; stdDevRetrys++) {
+                /**
+                 * First time may be long enough
+                 */
+                timeEach(stats, outerLoops, innerLoops, runnable);
+                analyze(stats, mTimes, outerLoops, debugLevel);
+                double innerLoopTime = stats.getMinInMicros();
+                if ((innerLoopTime >= minThresholdInMicros
+                        - ((maxThresholdInMicros - minThresholdInMicros) / 2))) {
+                    if (stats.stdDevOk(maxStdDevRatio)) {
+                        successful = true;
+                        break;
+                    } else {
+                        stats.incStdDevTooLargeCount();
+                        if (debugLevel >= DEBUG_LEVEL_SOME) {
+                            log(String.format(
+                                    "tea: tlc=%d StdDevRatio=%.2f > maxStdDevRatio=%.2f",
+                                    stats.getStdDevTooLargeCount(), stats.getStdDevRatio(),
+                                    maxStdDevRatio));
+                        }
+                    }
+                } else {
+                    /**
+                     * The initial number of loops is too short find the number
+                     * of loops that exceeds maxThresholdInMicros. Then use a
+                     * binary search to find the approriate innerLoop value that
+                     * is between min/maxThreshold.
+                     */
+                    innerLoops *= 10;
+                    int maxInnerLoops = innerLoops;
+                    int minInnerLoops = 1;
+                    boolean binarySearch = false;
+                    for (int i = 0; i < 10; i++) {
+                        timeEach(stats, outerLoops, innerLoops, runnable);
+                        analyze(stats, mTimes, outerLoops, debugLevel);
+                        innerLoopTime = stats.getMedianInMicros();
+                        if ((innerLoopTime >= minThresholdInMicros)
+                                && (innerLoopTime <= maxThresholdInMicros)) {
+                            if (stats.stdDevOk(maxStdDevRatio)) {
+                                successful = true;
+                                break;
+                            } else {
+                                stats.incStdDevTooLargeCount();
+                                if (debugLevel >= DEBUG_LEVEL_SOME) {
+                                    log(String.format(
+                                         "tea: tlc=%d StdDevRatio=%.2f > maxStdDevRatio=%.2f",
+                                         stats.getStdDevTooLargeCount(), stats.getStdDevRatio(),
+                                         maxStdDevRatio));
+                                }
+                            }
+                        } else if (binarySearch) {
+                            if ((innerLoopTime < minThresholdInMicros)) {
+                                minInnerLoops = innerLoops;
+                            } else {
+                                maxInnerLoops = innerLoops;
+                            }
+                            innerLoops = (maxInnerLoops + minInnerLoops) / 2;
+                        } else if (innerLoopTime >= maxThresholdInMicros) {
+                            /* Found a too large value, change to binary search */
+                            binarySearch = true;
+                            maxInnerLoops = innerLoops;
+                            innerLoops = (maxInnerLoops + minInnerLoops) / 2;
+                        } else {
+                            innerLoops *= 10;
+                        }
+                    }
+                    if (successful) {
+                        break;
+                    }
+                }
+            }
+            if (!successful) {
+                /* Couldn't find the number of loops to execute */
+                throw new PerfTimerException();
+            }
+
+            /** Looking for minimum */
+            if ((minStats == null) || (minStats.getTimePerLoop() > stats.getTimePerLoop())) {
+                minStats = stats;
+            }
+            if (debugLevel >= DEBUG_LEVEL_SOME) {
+                log(String.format("minStats.getTimePerLoop=%f minStats: %s", minStats.getTimePerLoop(), minStats));
+            }
+        }
+
+        return minStats;
+    }
+
+    /**
+     * Time how long it takes to execute runnable.run() with a threshold of 1 to
+     * 10ms.
+     *
+     * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL
+     * @param runnable
+     * @throws PerfTimerException
+     */
+    public Stats timeEachAutomatically(int debugLevel, Runnable runnable)
+            throws PerfTimerException {
+        mStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, 1, mCr.mMinThresholdInMicros,
+                mCr.mMaxThresholdInMicros, mCr.mStdDevRetrys, mCr.mMaxStdDevRatio, debugLevel,
+                runnable);
+        return mStats;
+    }
+
+    /**
+     * Time how long it takes to execute runnable.run() with a threshold of 1 to
+     * 10ms.
+     *
+     * @param runnable
+     * @throws PerfTimerException
+     */
+    public Stats timeEachAutomatically(Runnable runnable) throws PerfTimerException {
+        mStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, 1, mCr.mMinThresholdInMicros,
+                mCr.mMaxThresholdInMicros, mCr.mStdDevRetrys, mCr.mMaxStdDevRatio,
+                DEBUG_LEVEL_NONE, runnable);
+        return mStats;
+    }
+
+    /** Resize the times array */
+    public void resize(int maxCount) {
+        if (maxCount > mTimes.length) {
+            mTimes = new long[maxCount];
+        }
+    }
+
+    /**
+     * Analyze the data calculating the min, max, total, median, mean and
+     * stdDev. The standard deviation is calculated as sqrt(((sum of the squares
+     * of each time) / count) - mean^2)
+     * {@link "http://www.sciencebuddies.org/mentoring/project_data_analysis_variance_std_deviation.shtml"}
+     *
+     * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL
+     * @return StopWatch
+     */
+    public Stats analyze(Stats stats, long data[], int count, int debugLevel) {
+        if (count > 0) {
+            if (debugLevel >= DEBUG_LEVEL_ALL) {
+                for (int j = 0; j < count; j++) {
+                    log(String.format("data[%d]=%,dns", j, data[j]));
+                }
+            }
+            stats.calculate(data, count);
+        } else {
+            stats.init();
+        }
+        if (debugLevel >= DEBUG_LEVEL_SOME) {
+            log("stats: " + stats);
+        }
+        return stats;
+    }
+
+    /**
+     * Calibrate the system and set it for this PerfTimer instance
+     *
+     * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL
+     * @param precisionInDecimalDigits the precision in number of decimal digits
+     */
+    public CalibrationRec calibrate(int debugLevel, double precisionInDecimalDigits)
+            throws PerfTimerException {
+        int nonZeroCount = 0;
+        Stats stats = new Stats();
+        CalibrationRec cr = new CalibrationRec();
+
+        /* initialize the precision */
+        cr.mPrecisionInDecimalDigits = precisionInDecimalDigits;
+
+        /* Warm up the cache */
+        timeEach(stats, OUTER_LOOPS, 10, mEmptyRunnable);
+
+        /*
+         * Determine the clock stats with at least 20% non-zero unique values.
+         */
+        for (int clockStatsTries = 1; clockStatsTries < 100; clockStatsTries++) {
+            int j;
+            int i;
+            long cur;
+            long prev;
+            long min;
+
+            int innerLoops = clockStatsTries * 10;
+            timeEach(stats, OUTER_LOOPS, innerLoops, mEmptyRunnable);
+            long nonZeroValues[] = new long[mCount];
+            prev = 0;
+            for (nonZeroCount = 0, i = 0; i < mCount; i++) {
+                cur = mTimes[i];
+                if (cur > 0) {
+                    nonZeroValues[nonZeroCount++] = cur;
+                }
+            }
+            if (nonZeroCount > (mCount * 0.20)) {
+                // Calculate thresholds
+                analyze(stats, nonZeroValues, nonZeroCount, debugLevel);
+                stats.calculate(nonZeroValues, nonZeroCount);
+                cr.mMinThresholdInMicros = stats.getMeanInMicros()
+                        * Math.pow(10, cr.mPrecisionInDecimalDigits);
+                cr.mMaxThresholdInMicros = cr.mMinThresholdInMicros * 2;
+
+                // Set overhead to 0 and time the empty loop then set overhead.
+                cr.mRunnableOverheadInMicros = 0;
+                mClockStats = timeEachAutomatically(mCr.mVotes, OUTER_LOOPS, innerLoops,
+                        cr.mMinThresholdInMicros, cr.mMaxThresholdInMicros, mCr.mStdDevRetrys,
+                        mCr.mMaxStdDevRatio, debugLevel, mEmptyRunnable);
+                cr.mRunnableOverheadInMicros = mClockStats.getMinInMicros()
+                        / mClockStats.getInnerLoops();
+                break;
+            }
+            nonZeroCount = 0;
+        }
+        if (nonZeroCount == 0) {
+            throw new PerfTimerException();
+        }
+        if (debugLevel >= DEBUG_LEVEL_SOME) {
+            log(String.format("calibrate X oh=%.6fus minT=%,.6fus maxT=%,.6fus stats: %s",
+                    cr.mRunnableOverheadInMicros, cr.mMinThresholdInMicros,
+                    cr.mMaxThresholdInMicros, stats));
+        }
+        mCr = cr;
+        return mCr;
+    }
+
+    /** Calibrate the system and set it for this PerfTimer instance */
+    public CalibrationRec calibrate(double precisionInDecimalDigits) throws PerfTimerException {
+        return calibrate(DEBUG_LEVEL_NONE, precisionInDecimalDigits);
+    }
+
+    /** Calibrate the system and set it for this PerfTimer instance */
+    public CalibrationRec calibrate() throws PerfTimerException {
+        return calibrate(DEBUG_LEVEL_NONE, mCr.mPrecisionInDecimalDigits);
+    }
+
+    /*
+     * Accessors for the private data
+     */
+
+    /** Set calibration record */
+    public void setCalibrationRec(CalibrationRec cr) {
+        mCr = cr;
+    }
+
+    /** Get calibration record */
+    public CalibrationRec getCalibrationRec() {
+        return mCr;
+    }
+
+    /** Number of samples in times array. */
+    public int getCount() {
+        return mCount;
+    }
+
+    /** Minimum value of collected data in microseconds, valid after analyze. */
+    public double getMinInMicros() {
+        return mStats.getMinInMicros();
+    }
+
+    /** Maximum value of collected data in microseconds, valid after analyze. */
+    public double getMaxInMicros() {
+        return mStats.getMaxInMicros();
+    }
+
+    /**
+     * Sum of the values of collected data in microseconds, valid after analyze.
+     */
+    public double getTotalInMicros() {
+        return mStats.getTotalInMicros();
+    }
+
+    /** Sum of the values of collected data in seconds, valid after analyze. */
+    public double getTotalInSecs() {
+        return mStats.getTotalInSecs();
+    }
+
+    /** Sum of the values of collected data in seconds, valid after analyze. */
+    public double getMeanInMicros() {
+        return mStats.getMeanInMicros();
+    }
+
+    /** Median value of collected data in microseconds, valid after analyze. */
+    public double getMedianInMicros() {
+        return mStats.getMedianInMicros();
+    }
+
+    /**
+     * Standard deviation of collected data in microseconds, valid after
+     * analyze.
+     */
+    public double getStdDevInMicros() {
+        return mStats.getStdDevInMicros();
+    }
+
+    /** The mTimes[index] value */
+    public long getTime(int index) {
+        return mTimes[index];
+    }
+
+    /** The mTimes */
+    public long[] getTimes() {
+        return mTimes;
+    }
+
+    /** @return the clock stats as measured in calibrate */
+    public Stats getClockStats() {
+        return mClockStats;
+    }
+
+    /** @return the stats */
+    public Stats getStats() {
+        return mStats;
+    }
+
+    /**
+     * Convert stats to string
+     *
+     * @param debugLevel DEBUG_LEVEL_NONE, DEBUG_LEVEL_SOME, DEBUG_LEVEL_ALL
+     */
+    public String stats(int debugLevel) {
+        int innerLoops = mStats.getInnerLoops();
+        if (mCount == 0) {
+            return String.format("%,.3fus", (getTicks() - mStart) / TICKS_PER_MICROSECOND);
+        } else {
+            if (mCount == 1) {
+                return String.format("%,.3fus", getTime());
+            } else {
+                analyze(mStats, mTimes, mCount, debugLevel);
+                return mStats.toString();
+            }
+        }
+    }
+
+    /**
+     * Convert string
+     */
+    public String stats() {
+        return stats(0);
+    }
+
+    /**
+     * Get time
+     */
+    public double getTime() {
+        int innerLoops = mStats.getInnerLoops();
+        if (mCount == 0) {
+            return (getTicks() - mStart) / TICKS_PER_MICROSECOND;
+        } else {
+            if (mCount == 1) {
+                return mStats.getTotalInMicros();
+            } else {
+                analyze(mStats, mTimes, mCount, DEBUG_LEVEL_NONE);
+                return (mStats.getMinInMicros() / innerLoops) - mCr.mRunnableOverheadInMicros;
+            }
+        }
+    }
+
+    /** Convert to string */
+    @Override
+    public String toString() {
+        return String.format("%,.3fus", getTime());
+    }
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 35f5c0c..de83a4e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -72,6 +72,7 @@
   google/protobuf/compiler/plugin.pb.h                         \
   google/protobuf/compiler/cpp/cpp_generator.h                 \
   google/protobuf/compiler/java/java_generator.h               \
+  google/protobuf/compiler/javamicro/javamicro_generator.h     \
   google/protobuf/compiler/python/python_generator.h
 
 lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
@@ -178,6 +179,23 @@
   google/protobuf/compiler/java/java_primitive_field.h         \
   google/protobuf/compiler/java/java_service.cc                \
   google/protobuf/compiler/java/java_service.h                 \
+  google/protobuf/compiler/javamicro/javamicro_enum.cc         \
+  google/protobuf/compiler/javamicro/javamicro_enum.h          \
+  google/protobuf/compiler/javamicro/javamicro_enum_field.cc   \
+  google/protobuf/compiler/javamicro/javamicro_enum_field.h    \
+  google/protobuf/compiler/javamicro/javamicro_field.cc        \
+  google/protobuf/compiler/javamicro/javamicro_field.h         \
+  google/protobuf/compiler/javamicro/javamicro_file.cc         \
+  google/protobuf/compiler/javamicro/javamicro_file.h          \
+  google/protobuf/compiler/javamicro/javamicro_generator.cc    \
+  google/protobuf/compiler/javamicro/javamicro_helpers.cc      \
+  google/protobuf/compiler/javamicro/javamicro_helpers.h       \
+  google/protobuf/compiler/javamicro/javamicro_message.cc      \
+  google/protobuf/compiler/javamicro/javamicro_message.h       \
+  google/protobuf/compiler/javamicro/javamicro_message_field.cc\
+  google/protobuf/compiler/javamicro/javamicro_message_field.h \
+  google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\
+  google/protobuf/compiler/javamicro/javamicro_primitive_field.h\
   google/protobuf/compiler/python/python_generator.cc
 
 bin_PROGRAMS = protoc
diff --git a/src/Makefile.in b/src/Makefile.in
index daf81af..b48721f 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -106,7 +106,11 @@
 	cpp_string_field.lo java_enum.lo java_enum_field.lo \
 	java_extension.lo java_field.lo java_file.lo java_generator.lo \
 	java_helpers.lo java_message.lo java_message_field.lo \
-	java_primitive_field.lo java_service.lo python_generator.lo
+	java_primitive_field.lo java_service.lo javamicro_enum.lo \
+	javamicro_enum_field.lo javamicro_field.lo javamicro_file.lo \
+	javamicro_generator.lo javamicro_helpers.lo \
+	javamicro_message.lo javamicro_message_field.lo \
+	javamicro_primitive_field.lo python_generator.lo
 libprotoc_la_OBJECTS = $(am_libprotoc_la_OBJECTS)
 libprotoc_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
 	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
@@ -298,6 +302,7 @@
 	google/protobuf/compiler/plugin.pb.h \
 	google/protobuf/compiler/cpp/cpp_generator.h \
 	google/protobuf/compiler/java/java_generator.h \
+	google/protobuf/compiler/javamicro/javamicro_generator.h \
 	google/protobuf/compiler/python/python_generator.h
 nobase_includeHEADERS_INSTALL = $(install_sh_DATA)
 HEADERS = $(nobase_include_HEADERS)
@@ -491,6 +496,7 @@
   google/protobuf/compiler/plugin.pb.h                         \
   google/protobuf/compiler/cpp/cpp_generator.h                 \
   google/protobuf/compiler/java/java_generator.h               \
+  google/protobuf/compiler/javamicro/javamicro_generator.h     \
   google/protobuf/compiler/python/python_generator.h
 
 lib_LTLIBRARIES = libprotobuf-lite.la libprotobuf.la libprotoc.la
@@ -596,6 +602,23 @@
   google/protobuf/compiler/java/java_primitive_field.h         \
   google/protobuf/compiler/java/java_service.cc                \
   google/protobuf/compiler/java/java_service.h                 \
+  google/protobuf/compiler/javamicro/javamicro_enum.cc         \
+  google/protobuf/compiler/javamicro/javamicro_enum.h          \
+  google/protobuf/compiler/javamicro/javamicro_enum_field.cc   \
+  google/protobuf/compiler/javamicro/javamicro_enum_field.h    \
+  google/protobuf/compiler/javamicro/javamicro_field.cc        \
+  google/protobuf/compiler/javamicro/javamicro_field.h         \
+  google/protobuf/compiler/javamicro/javamicro_file.cc         \
+  google/protobuf/compiler/javamicro/javamicro_file.h          \
+  google/protobuf/compiler/javamicro/javamicro_generator.cc    \
+  google/protobuf/compiler/javamicro/javamicro_helpers.cc      \
+  google/protobuf/compiler/javamicro/javamicro_helpers.h       \
+  google/protobuf/compiler/javamicro/javamicro_message.cc      \
+  google/protobuf/compiler/javamicro/javamicro_message.h       \
+  google/protobuf/compiler/javamicro/javamicro_message_field.cc\
+  google/protobuf/compiler/javamicro/javamicro_message_field.h \
+  google/protobuf/compiler/javamicro/javamicro_primitive_field.cc\
+  google/protobuf/compiler/javamicro/javamicro_primitive_field.h\
   google/protobuf/compiler/python/python_generator.cc
 
 protoc_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la
@@ -925,6 +948,15 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_message_field.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_primitive_field.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/java_service.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_enum.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_enum_field.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_field.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_file.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_generator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_helpers.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_message.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_message_field.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/javamicro_primitive_field.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/message_lite.Plo@am__quote@
@@ -1467,6 +1499,69 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o java_service.lo `test -f 'google/protobuf/compiler/java/java_service.cc' || echo '$(srcdir)/'`google/protobuf/compiler/java/java_service.cc
 
+javamicro_enum.lo: google/protobuf/compiler/javamicro/javamicro_enum.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_enum.lo -MD -MP -MF $(DEPDIR)/javamicro_enum.Tpo -c -o javamicro_enum.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_enum.Tpo $(DEPDIR)/javamicro_enum.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_enum.cc' object='javamicro_enum.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_enum.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum.cc
+
+javamicro_enum_field.lo: google/protobuf/compiler/javamicro/javamicro_enum_field.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_enum_field.lo -MD -MP -MF $(DEPDIR)/javamicro_enum_field.Tpo -c -o javamicro_enum_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum_field.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_enum_field.Tpo $(DEPDIR)/javamicro_enum_field.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_enum_field.cc' object='javamicro_enum_field.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_enum_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_enum_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_enum_field.cc
+
+javamicro_field.lo: google/protobuf/compiler/javamicro/javamicro_field.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_field.lo -MD -MP -MF $(DEPDIR)/javamicro_field.Tpo -c -o javamicro_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_field.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_field.Tpo $(DEPDIR)/javamicro_field.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_field.cc' object='javamicro_field.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_field.cc
+
+javamicro_file.lo: google/protobuf/compiler/javamicro/javamicro_file.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_file.lo -MD -MP -MF $(DEPDIR)/javamicro_file.Tpo -c -o javamicro_file.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_file.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_file.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_file.Tpo $(DEPDIR)/javamicro_file.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_file.cc' object='javamicro_file.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_file.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_file.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_file.cc
+
+javamicro_generator.lo: google/protobuf/compiler/javamicro/javamicro_generator.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_generator.lo -MD -MP -MF $(DEPDIR)/javamicro_generator.Tpo -c -o javamicro_generator.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_generator.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_generator.Tpo $(DEPDIR)/javamicro_generator.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_generator.cc' object='javamicro_generator.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_generator.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_generator.cc
+
+javamicro_helpers.lo: google/protobuf/compiler/javamicro/javamicro_helpers.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_helpers.lo -MD -MP -MF $(DEPDIR)/javamicro_helpers.Tpo -c -o javamicro_helpers.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_helpers.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_helpers.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_helpers.Tpo $(DEPDIR)/javamicro_helpers.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_helpers.cc' object='javamicro_helpers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_helpers.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_helpers.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_helpers.cc
+
+javamicro_message.lo: google/protobuf/compiler/javamicro/javamicro_message.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_message.lo -MD -MP -MF $(DEPDIR)/javamicro_message.Tpo -c -o javamicro_message.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_message.Tpo $(DEPDIR)/javamicro_message.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_message.cc' object='javamicro_message.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_message.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message.cc
+
+javamicro_message_field.lo: google/protobuf/compiler/javamicro/javamicro_message_field.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_message_field.lo -MD -MP -MF $(DEPDIR)/javamicro_message_field.Tpo -c -o javamicro_message_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message_field.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_message_field.Tpo $(DEPDIR)/javamicro_message_field.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_message_field.cc' object='javamicro_message_field.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_message_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_message_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_message_field.cc
+
+javamicro_primitive_field.lo: google/protobuf/compiler/javamicro/javamicro_primitive_field.cc
+@am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT javamicro_primitive_field.lo -MD -MP -MF $(DEPDIR)/javamicro_primitive_field.Tpo -c -o javamicro_primitive_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_primitive_field.cc
+@am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/javamicro_primitive_field.Tpo $(DEPDIR)/javamicro_primitive_field.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' object='javamicro_primitive_field.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o javamicro_primitive_field.lo `test -f 'google/protobuf/compiler/javamicro/javamicro_primitive_field.cc' || echo '$(srcdir)/'`google/protobuf/compiler/javamicro/javamicro_primitive_field.cc
+
 python_generator.lo: google/protobuf/compiler/python/python_generator.cc
 @am__fastdepCXX_TRUE@	$(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT python_generator.lo -MD -MP -MF $(DEPDIR)/python_generator.Tpo -c -o python_generator.lo `test -f 'google/protobuf/compiler/python/python_generator.cc' || echo '$(srcdir)/'`google/protobuf/compiler/python/python_generator.cc
 @am__fastdepCXX_TRUE@	mv -f $(DEPDIR)/python_generator.Tpo $(DEPDIR)/python_generator.Plo
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum.cc
new file mode 100644
index 0000000..d74a149
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_enum.cc
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/compiler/javamicro/javamicro_enum.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& params)
+  : params_(params), descriptor_(descriptor) {
+  for (int i = 0; i < descriptor_->value_count(); i++) {
+    const EnumValueDescriptor* value = descriptor_->value(i);
+    const EnumValueDescriptor* canonical_value =
+      descriptor_->FindValueByNumber(value->number());
+
+    if (value == canonical_value) {
+      canonical_values_.push_back(value);
+    } else {
+      Alias alias;
+      alias.value = value;
+      alias.canonical_value = canonical_value;
+      aliases_.push_back(alias);
+    }
+  }
+}
+
+EnumGenerator::~EnumGenerator() {}
+
+void EnumGenerator::Generate(io::Printer* printer) {
+  printer->Print("// enum $classname$\n", "classname", descriptor_->name());
+  for (int i = 0; i < canonical_values_.size(); i++) {
+    map<string, string> vars;
+    vars["name"] = canonical_values_[i]->name();
+    vars["canonical_value"] = SimpleItoa(canonical_values_[i]->number());
+    printer->Print(vars,
+      "public static final int $name$ = $canonical_value$;\n");
+  }
+
+  // -----------------------------------------------------------------
+
+  for (int i = 0; i < aliases_.size(); i++) {
+    map<string, string> vars;
+    vars["name"] = aliases_[i].value->name();
+    vars["canonical_name"] = aliases_[i].canonical_value->name();
+    printer->Print(vars,
+      "public static final int $name$ = $canonical_name$;\n");
+  }
+
+  printer->Print("\n");
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum.h b/src/google/protobuf/compiler/javamicro/javamicro_enum.h
new file mode 100644
index 0000000..9cf226f
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_enum.h
@@ -0,0 +1,87 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
+
+#include <string>
+#include <vector>
+
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class EnumGenerator {
+ public:
+  explicit EnumGenerator(const EnumDescriptor* descriptor, const Params& params);
+  ~EnumGenerator();
+
+  void Generate(io::Printer* printer);
+
+ private:
+  const Params& params_;
+  const EnumDescriptor* descriptor_;
+
+  // The proto language allows multiple enum constants to have the same numeric
+  // value.  Java, however, does not allow multiple enum constants to be
+  // considered equivalent.  We treat the first defined constant for any
+  // given numeric value as "canonical" and the rest as aliases of that
+  // canonical value.
+  vector<const EnumValueDescriptor*> canonical_values_;
+
+  struct Alias {
+    const EnumValueDescriptor* value;
+    const EnumValueDescriptor* canonical_value;
+  };
+  vector<Alias> aliases_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc
new file mode 100644
index 0000000..0ff49a3
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.cc
@@ -0,0 +1,333 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+namespace {
+
+// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
+//   repeat code between this and the other field types.
+void SetEnumVariables(const Params& params,
+    const FieldDescriptor* descriptor, map<string, string>* variables) {
+  (*variables)["name"] =
+    UnderscoresToCamelCase(descriptor);
+  (*variables)["capitalized_name"] =
+    UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["type"] = "int";
+  (*variables)["default"] = DefaultValue(params, descriptor);
+  (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
+  (*variables)["message_name"] = descriptor->containing_type()->name();
+}
+
+}  // namespace
+
+// ===================================================================
+
+EnumFieldGenerator::
+EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetEnumVariables(params, descriptor, &variables_);
+}
+
+EnumFieldGenerator::~EnumFieldGenerator() {}
+
+void EnumFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private boolean has$capitalized_name$;\n"
+    "private int $name$_ = $default$;\n"
+    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+    "public int get$capitalized_name$() { return $name$_; }\n"
+    "public $message_name$ set$capitalized_name$(int value) {\n"
+    "  has$capitalized_name$ = true;\n"
+    "  $name$_ = value;\n"
+    "  return this;\n"
+    "}\n"
+    "public $message_name$ clear$capitalized_name$() {\n"
+    "  has$capitalized_name$ = false;\n"
+    "  $name$_ = $default$;\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "what is other??"
+    "if (other.has$capitalized_name$()) {\n"
+    "  set$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "  set$capitalized_name$(input.readInt32());\n");
+}
+
+void EnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  output.writeInt32($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void EnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+    "    .computeInt32Size($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+string EnumFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->enum_type());
+}
+
+// ===================================================================
+
+RepeatedEnumFieldGenerator::
+RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetEnumVariables(params, descriptor, &variables_);
+  if (descriptor_->options().packed()) {
+    GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed";
+  }
+}
+
+RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
+
+void RepeatedEnumFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "private java.util.Vector $name$_ = new java.util.Vector();\n"
+      "public java.util.Vector get$capitalized_name$List() {\n"
+      "  return $name$_;\n"
+      "}\n"
+      "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+      "public int get$capitalized_name$(int index) {\n"
+      "  return ((Integer)$name$_.elementAt(index)).intValue();\n"
+      "}\n"
+      "public $message_name$ set$capitalized_name$(int index, int value) {\n"
+      "  $name$_.setElementAt(new Integer(value), index);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ add$capitalized_name$(int value) {\n"
+      "  $name$_.addElement(new Integer(value));\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  $name$_.removeAllElements();\n"
+      "  return this;\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "private java.util.List<Integer> $name$_ =\n"
+      "  java.util.Collections.emptyList();\n"
+      "public java.util.List<Integer> get$capitalized_name$List() {\n"
+      "  return $name$_;\n"   // note:  unmodifiable list
+      "}\n"
+      "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+      "public int get$capitalized_name$(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n"
+      "public $message_name$ set$capitalized_name$(int index, int value) {\n"
+      "  $name$_.set(index, value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ add$capitalized_name$(int value) {\n"
+      "  if ($name$_.isEmpty()) {\n"
+      "    $name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+      "  }\n"
+      "  $name$_.add(value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  $name$_ = java.util.Collections.emptyList();\n"
+      "  return this;\n"
+      "}\n");
+  }
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize;\n");
+  }
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "if (other.$name$_.size() != 0) {\n"
+      "  for (int i = 0; i < other.$name$_.size(); i++)) {\n"
+      "    result.$name$_.addElement(other.$name$_.elementAt(i));\n"
+      "  }\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (!other.$name$_.isEmpty()) {\n"
+      "  if (result.$name$_.isEmpty()) {\n"
+      "    result.$name$_ = new java.util.ArrayList<java.lang.Integer>();\n"
+      "  }\n"
+      "  result.$name$_.addAll(other.$name$_);\n"
+      "}\n");
+  }
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  // If packed, set up the while loop
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "int length = input.readRawVarint32();\n"
+      "int oldLimit = input.pushLimit(length);\n"
+      "while(input.getBytesUntilLimit() > 0) {\n");
+    printer->Indent();
+  }
+
+  // Read and store the enum
+  printer->Print(variables_,
+    "  add$capitalized_name$(input.readInt32());\n");
+
+  if (descriptor_->options().packed()) {
+    printer->Outdent();
+    printer->Print(variables_,
+      "}\n"
+      "input.popLimit(oldLimit);\n");
+  }
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+        "if (get$capitalized_name$List().size() > 0) {\n"
+        "  output.writeRawVarint32($tag$);\n"
+        "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+        "}\n");
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+        "  output.writeRawVarint32(get$capitalized_name$(i));\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "for ($type$ element : get$capitalized_name$List()) {\n"
+        "  output.writeRawVarint32(element.getNumber());\n"
+        "}\n");
+    }
+  } else {
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+        "  output.writeInt32($number$, (int)get$capitalized_name$(i));\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "for (java.lang.Integer element : get$capitalized_name$List()) {\n"
+        "  output.writeInt32($number$, element);\n"
+        "}\n");
+    }
+  }
+}
+
+void RepeatedEnumFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+    printer->Indent();
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+      "  dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .computeInt32SizeNoTag(get$capitalized_name$(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for (java.lang.Integer element : get$capitalized_name$List()) {\n"
+      "  dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .computeInt32SizeNoTag(element);\n"
+      "}\n");
+  }
+  printer->Print(
+      "size += dataSize;\n");
+  if (descriptor_->options().packed()) {
+      printer->Print(variables_,
+        "if (get$capitalized_name$List().size() != 0) {"
+        "  size += $tag_size$;\n"
+        "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+        "    .computeRawVarint32Size(dataSize);\n"
+        "}");
+  } else {
+    printer->Print(variables_,
+        "size += $tag_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+string RepeatedEnumFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->enum_type());
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h
new file mode 100644
index 0000000..ab671c1
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_enum_field.h
@@ -0,0 +1,94 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javamicro/javamicro_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class EnumFieldGenerator : public FieldGenerator {
+ public:
+  explicit EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  ~EnumFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator);
+};
+
+class RepeatedEnumFieldGenerator : public FieldGenerator {
+ public:
+  explicit RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  ~RepeatedEnumFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_ENUM_FIELD_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_field.cc
new file mode 100644
index 0000000..a2ea4f9
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_field.cc
@@ -0,0 +1,102 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javamicro/javamicro_field.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h>
+#include <google/protobuf/compiler/javamicro/javamicro_enum_field.h>
+#include <google/protobuf/compiler/javamicro/javamicro_message_field.h>
+#include <google/protobuf/stubs/common.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+FieldGenerator::~FieldGenerator() {}
+
+FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor, const Params &params)
+  : descriptor_(descriptor),
+    field_generators_(
+      new scoped_ptr<FieldGenerator>[descriptor->field_count()]),
+    extension_generators_(
+      new scoped_ptr<FieldGenerator>[descriptor->extension_count()]) {
+
+  // Construct all the FieldGenerators.
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    field_generators_[i].reset(MakeGenerator(descriptor->field(i), params));
+  }
+  for (int i = 0; i < descriptor->extension_count(); i++) {
+    extension_generators_[i].reset(MakeGenerator(descriptor->extension(i), params));
+  }
+}
+
+FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, const Params &params) {
+  if (field->is_repeated()) {
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        return new RepeatedMessageFieldGenerator(field, params);
+      case JAVATYPE_ENUM:
+        return new RepeatedEnumFieldGenerator(field, params);
+      default:
+        return new RepeatedPrimitiveFieldGenerator(field, params);
+    }
+  } else {
+    switch (GetJavaType(field)) {
+      case JAVATYPE_MESSAGE:
+        return new MessageFieldGenerator(field, params);
+      case JAVATYPE_ENUM:
+        return new EnumFieldGenerator(field, params);
+      default:
+        return new PrimitiveFieldGenerator(field, params);
+    }
+  }
+}
+
+FieldGeneratorMap::~FieldGeneratorMap() {}
+
+const FieldGenerator& FieldGeneratorMap::get(
+    const FieldDescriptor* field) const {
+  GOOGLE_CHECK_EQ(field->containing_type(), descriptor_);
+  return *field_generators_[field->index()];
+}
+
+const FieldGenerator& FieldGeneratorMap::get_extension(int index) const {
+  return *extension_generators_[index];
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_field.h b/src/google/protobuf/compiler/javamicro/javamicro_field.h
new file mode 100644
index 0000000..1530778
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_field.h
@@ -0,0 +1,98 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+
+namespace google {
+namespace protobuf {
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class FieldGenerator {
+ public:
+  //FieldGenerator() {}
+  FieldGenerator(const Params& params) : params_(params) {}
+  virtual ~FieldGenerator();
+
+  virtual void GenerateMembers(io::Printer* printer) const = 0;
+  virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+  virtual void GenerateParsingCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
+  virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
+
+  virtual string GetBoxedType() const = 0;
+
+ protected:
+  const Params& params_;
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator);
+};
+
+// Convenience class which constructs FieldGenerators for a Descriptor.
+class FieldGeneratorMap {
+ public:
+  explicit FieldGeneratorMap(const Descriptor* descriptor, const Params &params);
+  ~FieldGeneratorMap();
+
+  const FieldGenerator& get(const FieldDescriptor* field) const;
+  const FieldGenerator& get_extension(int index) const;
+
+ private:
+  const Descriptor* descriptor_;
+  scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+  scoped_array<scoped_ptr<FieldGenerator> > extension_generators_;
+
+  static FieldGenerator* MakeGenerator(const FieldDescriptor* field, const Params &params);
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FIELD_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.cc b/src/google/protobuf/compiler/javamicro/javamicro_file.cc
new file mode 100644
index 0000000..0985538
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_file.cc
@@ -0,0 +1,251 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javamicro/javamicro_file.h>
+#include <google/protobuf/compiler/javamicro/javamicro_enum.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/compiler/javamicro/javamicro_message.h>
+#include <google/protobuf/compiler/code_generator.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+namespace {
+
+// Recursively searches the given message to see if it contains any extensions.
+bool UsesExtensions(const Message& message) {
+  const Reflection* reflection = message.GetReflection();
+
+  // We conservatively assume that unknown fields are extensions.
+  if (reflection->GetUnknownFields(message).field_count() > 0) return true;
+
+  vector<const FieldDescriptor*> fields;
+  reflection->ListFields(message, &fields);
+
+  for (int i = 0; i < fields.size(); i++) {
+    if (fields[i]->is_extension()) return true;
+
+    if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      if (fields[i]->is_repeated()) {
+        int size = reflection->FieldSize(message, fields[i]);
+        for (int j = 0; j < size; j++) {
+          const Message& sub_message =
+            reflection->GetRepeatedMessage(message, fields[i], j);
+          if (UsesExtensions(sub_message)) return true;
+        }
+      } else {
+        const Message& sub_message = reflection->GetMessage(message, fields[i]);
+        if (UsesExtensions(sub_message)) return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+}  // namespace
+
+FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params)
+  : file_(file),
+    params_(params),
+    java_package_(FileJavaPackage(params, file)),
+    classname_(FileClassName(params, file)) {}
+
+FileGenerator::~FileGenerator() {}
+
+bool FileGenerator::Validate(string* error) {
+  // Check for extensions
+  FileDescriptorProto file_proto;
+  file_->CopyTo(&file_proto);
+  if (UsesExtensions(file_proto)) {
+    error->assign(file_->name());
+    error->append(
+      ": Java MICRO_RUNTIME does not support extensions\"");
+    return false;
+  }
+
+  // If there is no outer class name then there must be only
+  // message and no enums defined in the file scope.
+  if (!params_.has_java_outer_classname(file_->name())) {
+    if (file_->message_type_count() != 1) {
+      error->assign(file_->name());
+      error->append(
+        ": Java MICRO_RUNTIME may only have 1 message if there is no 'option java_outer_classname'\"");
+      return false;
+    }
+
+    if (file_->enum_type_count() != 0) {
+      error->assign(file_->name());
+      error->append(
+        ": Java MICRO_RUNTIME must have an 'option java_outer_classname' if file scope enums are present\"");
+      return false;
+    }
+  }
+
+  // Check that no class name matches the file's class name.  This is a common
+  // problem that leads to Java compile errors that can be hard to understand.
+  // It's especially bad when using the java_multiple_files, since we would
+  // end up overwriting the outer class with one of the inner ones.
+  int found_fileName = 0;
+  for (int i = 0; i < file_->enum_type_count(); i++) {
+    if (file_->enum_type(i)->name() == classname_) {
+      found_fileName += 1;
+    }
+  }
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    if (file_->message_type(i)->name() == classname_) {
+      found_fileName += 1;
+    }
+  }
+  if (file_->service_count() != 0) {
+    error->assign(file_->name());
+    error->append(
+      ": Java MICRO_RUNTIME does not support services\"");
+    return false;
+  }
+
+  if (found_fileName > 1) {
+    error->assign(file_->name());
+    error->append(
+      ": Cannot generate Java output because there is more than one class name, \"");
+    error->append(classname_);
+    error->append(
+      "\", matches the name of one of the types declared inside it.  "
+      "Please either rename the type or use the java_outer_classname "
+      "option to specify a different outer class name for the .proto file."
+      " -- FIX THIS MESSAGE");
+    return false;
+  }
+  return true;
+}
+
+void FileGenerator::Generate(io::Printer* printer) {
+  // We don't import anything because we refer to all classes by their
+  // fully-qualified names in the generated source.
+  printer->Print(
+    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "\n");
+  if (!java_package_.empty()) {
+    printer->Print(
+      "package $package$;\n"
+      "\n",
+      "package", java_package_);
+  }
+
+  if (params_.has_java_outer_classname(file_->name())) {
+    printer->Print(
+      "public final class $classname$ {\n"
+      "  private $classname$() {}\n",
+      "classname", classname_);
+    printer->Indent();
+  }
+
+  // -----------------------------------------------------------------
+
+  if (!params_.java_multiple_files()) {
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      EnumGenerator(file_->enum_type(i), params_).Generate(printer);
+    }
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      MessageGenerator(file_->message_type(i), params_).Generate(printer);
+    }
+  }
+
+  // Static variables.
+  for (int i = 0; i < file_->message_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer);
+  }
+
+  if (params_.has_java_outer_classname(file_->name())) {
+    printer->Outdent();
+    printer->Print(
+      "}\n");
+  }
+}
+
+template<typename GeneratorClass, typename DescriptorClass>
+static void GenerateSibling(const string& package_dir,
+                            const string& java_package,
+                            const DescriptorClass* descriptor,
+                            OutputDirectory* output_directory,
+                            vector<string>* file_list,
+                            const Params& params) {
+  string filename = package_dir + descriptor->name() + ".java";
+  file_list->push_back(filename);
+
+  scoped_ptr<io::ZeroCopyOutputStream> output(
+    output_directory->Open(filename));
+  io::Printer printer(output.get(), '$');
+
+  printer.Print(
+    "// Generated by the protocol buffer compiler.  DO NOT EDIT!\n"
+    "\n");
+  if (!java_package.empty()) {
+    printer.Print(
+      "package $package$;\n"
+      "\n",
+      "package", java_package);
+  }
+
+  GeneratorClass(descriptor, params).Generate(&printer);
+}
+
+void FileGenerator::GenerateSiblings(const string& package_dir,
+                                     OutputDirectory* output_directory,
+                                     vector<string>* file_list) {
+  if (params_.java_multiple_files()) {
+    for (int i = 0; i < file_->enum_type_count(); i++) {
+      GenerateSibling<EnumGenerator>(package_dir, java_package_,
+                                     file_->enum_type(i),
+                                     output_directory, file_list, params_);
+    }
+    for (int i = 0; i < file_->message_type_count(); i++) {
+      GenerateSibling<MessageGenerator>(package_dir, java_package_,
+                                        file_->message_type(i),
+                                        output_directory, file_list, params_);
+    }
+  }
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_file.h b/src/google/protobuf/compiler/javamicro/javamicro_file.h
new file mode 100644
index 0000000..430172a
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_file.h
@@ -0,0 +1,94 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
+
+#include <string>
+#include <vector>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+
+namespace google {
+namespace protobuf {
+  class FileDescriptor;        // descriptor.h
+  namespace io {
+    class Printer;             // printer.h
+  }
+  namespace compiler {
+    class OutputDirectory;     // code_generator.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class FileGenerator {
+ public:
+  explicit FileGenerator(const FileDescriptor* file, const Params& params);
+  ~FileGenerator();
+
+  // Checks for problems that would otherwise lead to cryptic compile errors.
+  // Returns true if there are no problems, or writes an error description to
+  // the given string and returns false otherwise.
+  bool Validate(string* error);
+
+  void Generate(io::Printer* printer);
+
+  // If we aren't putting everything into one file, this will write all the
+  // files other than the outer file (i.e. one for each message, enum, and
+  // service type).
+  void GenerateSiblings(const string& package_dir,
+                        OutputDirectory* output_directory,
+                        vector<string>* file_list);
+
+  const string& java_package() { return java_package_; }
+  const string& classname()    { return classname_;    }
+
+ private:
+  const FileDescriptor* file_;
+  const Params& params_;
+  string java_package_;
+  string classname_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_FILE_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.cc b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc
new file mode 100644
index 0000000..bfba8c5
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_generator.cc
@@ -0,0 +1,209 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/compiler/javamicro/javamicro_generator.h>
+#include <google/protobuf/compiler/javamicro/javamicro_file.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/zero_copy_stream.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+void UpdateParamsRecursively(Params& params,
+    const FileDescriptor* file) {
+  // Add any parameters for this file
+  if (file->options().has_java_outer_classname()) {
+    params.set_java_outer_classname(
+      file->name(), file->options().java_outer_classname());
+  }
+  if (file->options().has_java_package()) {
+    params.set_java_package(
+      file->name(), file->options().java_package());
+  }
+
+  // Loop through all dependent files recursively
+  // adding dep
+  for (int i = 0; i < file->dependency_count(); i++) {
+    UpdateParamsRecursively(params, file->dependency(i));
+  }
+}
+
+JavaMicroGenerator::JavaMicroGenerator() {}
+JavaMicroGenerator::~JavaMicroGenerator() {}
+
+bool JavaMicroGenerator::Generate(const FileDescriptor* file,
+                             const string& parameter,
+                             OutputDirectory* output_directory,
+                             string* error) const {
+  vector<pair<string, string> > options;
+
+//  GOOGLE_LOG(INFO) << "wink: JavaMicroGenerator::Generate INFO";
+//  GOOGLE_LOG(WARNING) << "wink: JavaMicroGenerator::Generate WARNING";
+//  GOOGLE_LOG(ERROR) << "wink: JavaMicroGenerator::Generate ERROR";
+//  GOOGLE_LOG(FATAL) << "wink: JavaMicroGenerator::Generate";
+
+  ParseGeneratorParameter(parameter, &options);
+
+  // -----------------------------------------------------------------
+  // parse generator options
+
+  // Name a file where we will write a list of generated file names, one
+  // per line.
+  string output_list_file;
+  Params params(file->name());
+
+  // Get options from the proto file
+  if (file->options().has_java_multiple_files()) {
+    params.set_java_multiple_files(file->options().java_multiple_files());
+  }
+
+  // Update per file params
+  UpdateParamsRecursively(params, file);
+
+  // Replace any existing options with ones from command line
+  for (int i = 0; i < options.size(); i++) {
+    // GOOGLE_LOG(WARNING) << "first=" << options[i].first
+    //                     << " second=" << options[i].second;
+    if (options[i].first == "output_list_file") {
+      output_list_file = options[i].second;
+    } else if (options[i].first == "opt") {
+      if (options[i].second == "speed") {
+        params.set_optimization(JAVAMICRO_OPT_SPEED);
+      } else if (options[i].second == "space") {
+        params.set_optimization(JAVAMICRO_OPT_SPACE);
+      } else {
+        *error = "Unknown javamicro generator option: opt="
+                  + options[i].second + " expecting opt=space or opt=speed";
+        return false;
+      }
+    } else if (options[i].first == "java_package") {
+        vector<string> parts;
+        SplitStringUsing(options[i].second, "|", &parts);
+        if (parts.size() != 2) {
+          *error = "Bad java_package, expecting filename|PackageName found '"
+            + options[i].second + "'";
+          return false;
+        }
+        params.set_java_package(parts[0], parts[1]);
+    } else if (options[i].first == "java_outer_classname") {
+        vector<string> parts;
+        SplitStringUsing(options[i].second, "|", &parts);
+        if (parts.size() != 2) {
+          *error = "Bad java_outer_classname, "
+                   "expecting filename|ClassName found '"
+                   + options[i].second + "'";
+          return false;
+        }
+        params.set_java_outer_classname(parts[0], parts[1]);
+    } else if (options[i].first == "java_multiple_files") {
+        params.set_java_multiple_files(options[i].second == "true");
+    } else if (options[i].first == "java_use_vector") {
+        params.set_java_use_vector(options[i].second == "true");
+    } else {
+      *error = "Ignore unknown javamicro generator option: " + options[i].first;
+    }
+  }
+
+#if 0
+  GOOGLE_LOG(WARNING) << "optimization()=" << params.optimization();
+  GOOGLE_LOG(WARNING) << "java_multiple_files()=" << params.java_multiple_files();
+  GOOGLE_LOG(WARNING) << "java_use_vector()=" << params.java_use_vector();
+
+  GOOGLE_LOG(WARNING) << "----------";
+  for (Params::NameMap::const_iterator it = params.java_packages().begin();
+       it != params.java_packages().end();
+       ++it) {
+    GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " package=" << it->second;
+  }
+  for (Params::NameMap::const_iterator it = params.java_outer_classnames().begin();
+       it != params.java_outer_classnames().end();
+       ++it) {
+    GOOGLE_LOG(WARNING) << "cn.filename=" << it->first << " classname=" << it->second;
+  }
+  GOOGLE_LOG(WARNING) << "==========";
+
+#endif
+
+  // -----------------------------------------------------------------
+
+  FileGenerator file_generator(file, params);
+  if (!file_generator.Validate(error)) {
+    return false;
+  }
+
+  string package_dir =
+    StringReplace(file_generator.java_package(), ".", "/", true);
+  if (!package_dir.empty()) package_dir += "/";
+
+  vector<string> all_files;
+
+  string java_filename = package_dir;
+  java_filename += file_generator.classname();
+  java_filename += ".java";
+  all_files.push_back(java_filename);
+
+  // Generate main java file.
+  scoped_ptr<io::ZeroCopyOutputStream> output(
+    output_directory->Open(java_filename));
+  io::Printer printer(output.get(), '$');
+  file_generator.Generate(&printer);
+
+  // Generate sibling files.
+  file_generator.GenerateSiblings(package_dir, output_directory, &all_files);
+
+  // Generate output list if requested.
+  if (!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.
+    scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output(
+      output_directory->Open(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]);
+    }
+  }
+
+  return true;
+}
+
+}  // namespace java
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_generator.h b/src/google/protobuf/compiler/javamicro/javamicro_generator.h
new file mode 100644
index 0000000..a1c33b7
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_generator.h
@@ -0,0 +1,72 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+//
+// Generates Java micro code for a given .proto file.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__
+
+#include <string>
+#include <google/protobuf/compiler/code_generator.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+// CodeGenerator implementation which generates Java micro code.  If you create your
+// own protocol compiler binary and you want it to support Java output for the
+// micro runtime, you can do so by registering an instance of this CodeGenerator with
+// the CommandLineInterface in your main() function.
+class LIBPROTOC_EXPORT JavaMicroGenerator : public CodeGenerator {
+ public:
+  JavaMicroGenerator();
+  ~JavaMicroGenerator();
+
+  // implements CodeGenerator ----------------------------------------
+  bool Generate(const FileDescriptor* file,
+                const string& parameter,
+                OutputDirectory* output_directory,
+                string* error) const;
+
+ private:
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaMicroGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MICRO_GENERATOR_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc
new file mode 100644
index 0000000..11ba71a
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.cc
@@ -0,0 +1,381 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <vector>
+
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/stubs/substitute.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+const char kThickSeparator[] =
+  "// ===================================================================\n";
+const char kThinSeparator[] =
+  "// -------------------------------------------------------------------\n";
+
+namespace {
+
+const char* kDefaultPackage = "";
+
+const string& FieldName(const FieldDescriptor* field) {
+  // Groups are hacky:  The name of the field is just the lower-cased name
+  // of the group type.  In Java, though, we would like to retain the original
+  // capitalization of the type name.
+  if (field->type() == FieldDescriptor::TYPE_GROUP) {
+    return field->message_type()->name();
+  } else {
+    return field->name();
+  }
+}
+
+string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) {
+  string result;
+  // Note:  I distrust ctype.h due to locales.
+  for (int i = 0; i < input.size(); i++) {
+    if ('a' <= input[i] && input[i] <= 'z') {
+      if (cap_next_letter) {
+        result += input[i] + ('A' - 'a');
+      } else {
+        result += input[i];
+      }
+      cap_next_letter = false;
+    } else if ('A' <= input[i] && input[i] <= 'Z') {
+      if (i == 0 && !cap_next_letter) {
+        // Force first letter to lower-case unless explicitly told to
+        // capitalize it.
+        result += input[i] + ('a' - 'A');
+      } else {
+        // Capital letters after the first are left as-is.
+        result += input[i];
+      }
+      cap_next_letter = false;
+    } else if ('0' <= input[i] && input[i] <= '9') {
+      result += input[i];
+      cap_next_letter = true;
+    } else {
+      cap_next_letter = true;
+    }
+  }
+  return result;
+}
+
+}  // namespace
+
+string UnderscoresToCamelCase(const FieldDescriptor* field) {
+  return UnderscoresToCamelCaseImpl(FieldName(field), false);
+}
+
+string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) {
+  return UnderscoresToCamelCaseImpl(FieldName(field), true);
+}
+
+string UnderscoresToCamelCase(const MethodDescriptor* method) {
+  return UnderscoresToCamelCaseImpl(method->name(), false);
+}
+
+string StripProto(const string& filename) {
+  if (HasSuffixString(filename, ".protodevel")) {
+    return StripSuffixString(filename, ".protodevel");
+  } else {
+    return StripSuffixString(filename, ".proto");
+  }
+}
+
+string FileClassName(const Params& params, const FileDescriptor* file) {
+  string name;
+
+  if (params.has_java_outer_classname(file->name())) {
+      name = params.java_outer_classname(file->name());
+  } else {
+    if ((file->message_type_count() == 1)
+        || (file->enum_type_count() == 0)) {
+      // If no outer calls and only one message then
+      // use the message name as the file name
+      name = file->message_type(0)->name();
+    } else {
+      // Use the filename it self with underscores removed
+      // and a CamelCase style name.
+      string basename;
+      string::size_type last_slash = file->name().find_last_of('/');
+      if (last_slash == string::npos) {
+        basename = file->name();
+      } else {
+        basename = file->name().substr(last_slash + 1);
+      }
+      name = UnderscoresToCamelCaseImpl(StripProto(basename), true);
+    }
+  }
+
+  return name;
+}
+
+string FileJavaPackage(const Params& params, const FileDescriptor* file) {
+  if (params.has_java_package(file->name())) {
+    return params.java_package(file->name());
+  } else {
+    string result = kDefaultPackage;
+    if (!file->package().empty()) {
+      if (!result.empty()) result += '.';
+      result += file->package();
+    }
+    return result;
+  }
+}
+
+string ToJavaName(const Params& params, const string& full_name,
+    const FileDescriptor* file) {
+  string result;
+  if (params.java_multiple_files()) {
+    result = FileJavaPackage(params, file);
+  } else {
+    result = ClassName(params, file);
+  }
+  if (file->package().empty()) {
+    result += '.';
+    result += full_name;
+  } else {
+    // Strip the proto package from full_name since we've replaced it with
+    // the Java package. If there isn't an outer classname then strip it too.
+    int sizeToSkipPackageName = file->package().size();
+    int sizeToSkipOutClassName;
+    if (params.has_java_outer_classname(file->name())) {
+      sizeToSkipOutClassName = 0;
+    } else {
+      sizeToSkipOutClassName =
+                full_name.find_first_of('.', sizeToSkipPackageName + 1);
+    }
+    int sizeToSkip = sizeToSkipOutClassName > 0 ?
+            sizeToSkipOutClassName : sizeToSkipPackageName;
+    string class_name = full_name.substr(sizeToSkip + 1);
+    if (class_name == FileClassName(params, file)) {
+      // Done class_name is already present.
+    } else {
+      result += '.';
+      result += class_name;
+    }
+  }
+  return result;
+}
+
+string ClassName(const Params& params, const FileDescriptor* descriptor) {
+  string result = FileJavaPackage(params, descriptor);
+  if (!result.empty()) result += '.';
+  result += FileClassName(params, descriptor);
+  return result;
+}
+
+string ClassName(const Params& params, const EnumDescriptor* descriptor) {
+  string result;
+  const FileDescriptor* file = descriptor->file();
+  const string file_name = file->name();
+  const string full_name = descriptor->full_name();
+  int last_period = full_name.find_last_of('.');
+  int first_period = full_name.find_first_of('.');
+
+  // Remove class_name as we're using public static final int's not enums
+  string base_name = full_name.substr(0, full_name.find_last_of('.'));
+
+  if (!file->package().empty()) {
+    // Remove package name.
+    int offset = first_period;
+    if (last_period > first_period) {
+      // There was two or more periods so we need to remove this one too.
+      offset += 1;
+    }
+    base_name = base_name.substr(offset);
+  }
+
+  if (params.has_java_package(file_name)) {
+    result += params.java_package(file_name);
+  }
+  if (params.has_java_outer_classname(file_name)) {
+    result += ".";
+    result += params.java_outer_classname(file_name);
+  }
+  if (!base_name.empty()) {
+    result += ".";
+    result += base_name;
+  }
+  return result;
+}
+
+string FieldConstantName(const FieldDescriptor *field) {
+  string name = field->name() + "_FIELD_NUMBER";
+  UpperString(&name);
+  return name;
+}
+
+JavaType GetJavaType(FieldDescriptor::Type field_type) {
+  switch (field_type) {
+    case FieldDescriptor::TYPE_INT32:
+    case FieldDescriptor::TYPE_UINT32:
+    case FieldDescriptor::TYPE_SINT32:
+    case FieldDescriptor::TYPE_FIXED32:
+    case FieldDescriptor::TYPE_SFIXED32:
+      return JAVATYPE_INT;
+
+    case FieldDescriptor::TYPE_INT64:
+    case FieldDescriptor::TYPE_UINT64:
+    case FieldDescriptor::TYPE_SINT64:
+    case FieldDescriptor::TYPE_FIXED64:
+    case FieldDescriptor::TYPE_SFIXED64:
+      return JAVATYPE_LONG;
+
+    case FieldDescriptor::TYPE_FLOAT:
+      return JAVATYPE_FLOAT;
+
+    case FieldDescriptor::TYPE_DOUBLE:
+      return JAVATYPE_DOUBLE;
+
+    case FieldDescriptor::TYPE_BOOL:
+      return JAVATYPE_BOOLEAN;
+
+    case FieldDescriptor::TYPE_STRING:
+      return JAVATYPE_STRING;
+
+    case FieldDescriptor::TYPE_BYTES:
+      return JAVATYPE_BYTES;
+
+    case FieldDescriptor::TYPE_ENUM:
+      return JAVATYPE_ENUM;
+
+    case FieldDescriptor::TYPE_GROUP:
+    case FieldDescriptor::TYPE_MESSAGE:
+      return JAVATYPE_MESSAGE;
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return JAVATYPE_INT;
+}
+
+const char* BoxedPrimitiveTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT    : return "java.lang.Integer";
+    case JAVATYPE_LONG   : return "java.lang.Long";
+    case JAVATYPE_FLOAT  : return "java.lang.Float";
+    case JAVATYPE_DOUBLE : return "java.lang.Double";
+    case JAVATYPE_BOOLEAN: return "java.lang.Boolean";
+    case JAVATYPE_STRING : return "java.lang.String";
+    case JAVATYPE_BYTES  : return "com.google.protobuf.micro.ByteStringMicro";
+    case JAVATYPE_ENUM   : return "java.lang.Integer";
+    case JAVATYPE_MESSAGE: return NULL;
+
+    // No default because we want the compiler to complain if any new
+    // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+bool AllAscii(const string& text) {
+  for (int i = 0; i < text.size(); i++) {
+    if ((text[i] & 0x80) != 0) {
+      return false;
+    }
+  }
+  return true;
+}
+
+string DefaultValue(const Params& params, const FieldDescriptor* field) {
+  // Switch on cpp_type since we need to know which default_value_* method
+  // of FieldDescriptor to call.
+  switch (field->cpp_type()) {
+    case FieldDescriptor::CPPTYPE_INT32:
+      return SimpleItoa(field->default_value_int32());
+    case FieldDescriptor::CPPTYPE_UINT32:
+      // Need to print as a signed int since Java has no unsigned.
+      return SimpleItoa(static_cast<int32>(field->default_value_uint32()));
+    case FieldDescriptor::CPPTYPE_INT64:
+      return SimpleItoa(field->default_value_int64()) + "L";
+    case FieldDescriptor::CPPTYPE_UINT64:
+      return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
+             "L";
+    case FieldDescriptor::CPPTYPE_DOUBLE:
+      return SimpleDtoa(field->default_value_double()) + "D";
+    case FieldDescriptor::CPPTYPE_FLOAT:
+      return SimpleFtoa(field->default_value_float()) + "F";
+    case FieldDescriptor::CPPTYPE_BOOL:
+      return field->default_value_bool() ? "true" : "false";
+    case FieldDescriptor::CPPTYPE_STRING:
+      if (field->type() == FieldDescriptor::TYPE_BYTES) {
+        if (field->has_default_value()) {
+          // See comments in Internal.java for gory details.
+          return strings::Substitute(
+            "com.google.protobuf.micro.ByteStringMicro.copyFromUtf8(\"$0\")",
+            CEscape(field->default_value_string()));
+        } else {
+          return "com.google.protobuf.micro.ByteStringMicro.EMPTY";
+        }
+      } else {
+        if (AllAscii(field->default_value_string())) {
+          // All chars are ASCII.  In this case CEscape() works fine.
+          return "\"" + CEscape(field->default_value_string()) + "\"";
+        } else {
+          // See comments in Internal.java for gory details.
+          // BUG: Internal NOT SUPPORTED need to fix!!
+          return strings::Substitute(
+            "com.google.protobuf.micro.Internal.stringDefaultValue(\"$0\")",
+            CEscape(field->default_value_string()));
+        }
+      }
+
+    case FieldDescriptor::CPPTYPE_ENUM:
+      return ClassName(params, field->enum_type()) + "." +
+             field->default_value_enum()->name();
+
+    case FieldDescriptor::CPPTYPE_MESSAGE:
+      return ClassName(params, field->message_type()) + ".getDefaultInstance()";
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return "";
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_helpers.h b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h
new file mode 100644
index 0000000..eeddbf9
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_helpers.h
@@ -0,0 +1,128 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
+
+#include <string>
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/descriptor.pb.h>
+#include <google/protobuf/descriptor.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+// Commonly-used separator comments.  Thick is a line of '=', thin is a line
+// of '-'.
+extern const char kThickSeparator[];
+extern const char kThinSeparator[];
+
+// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes
+// "fooBarBaz" or "FooBarBaz", respectively.
+string UnderscoresToCamelCase(const FieldDescriptor* field);
+string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field);
+
+// Similar, but for method names.  (Typically, this merely has the effect
+// of lower-casing the first letter of the name.)
+string UnderscoresToCamelCase(const MethodDescriptor* method);
+
+// Strips ".proto" or ".protodevel" from the end of a filename.
+string StripProto(const string& filename);
+
+// Gets the unqualified class name for the file.  Each .proto file becomes a
+// single Java class, with all its contents nested in that class.
+string FileClassName(const Params& params, const FileDescriptor* file);
+
+// Returns the file's Java package name.
+string FileJavaPackage(const Params& params, const FileDescriptor* file);
+
+// Converts the given fully-qualified name in the proto namespace to its
+// fully-qualified name in the Java namespace, given that it is in the given
+// file.
+string ToJavaName(const Params& params, const string& full_name,
+    const FileDescriptor* file);
+
+// These return the fully-qualified class name corresponding to the given
+// descriptor.
+inline string ClassName(const Params& params, const Descriptor* descriptor) {
+  return ToJavaName(params, descriptor->full_name(), descriptor->file());
+}
+string ClassName(const Params& params, const EnumDescriptor* descriptor);
+inline string ClassName(const Params& params,
+    const ServiceDescriptor* descriptor) {
+  return ToJavaName(params, descriptor->full_name(), descriptor->file());
+}
+inline string ExtensionIdentifierName(const Params& params,
+    const FieldDescriptor* descriptor) {
+  return ToJavaName(params, descriptor->full_name(), descriptor->file());
+}
+string ClassName(const Params& params, const FileDescriptor* descriptor);
+
+// Get the unqualified name that should be used for a field's field
+// number constant.
+string FieldConstantName(const FieldDescriptor *field);
+
+enum JavaType {
+  JAVATYPE_INT,
+  JAVATYPE_LONG,
+  JAVATYPE_FLOAT,
+  JAVATYPE_DOUBLE,
+  JAVATYPE_BOOLEAN,
+  JAVATYPE_STRING,
+  JAVATYPE_BYTES,
+  JAVATYPE_ENUM,
+  JAVATYPE_MESSAGE
+};
+
+JavaType GetJavaType(FieldDescriptor::Type field_type);
+
+inline JavaType GetJavaType(const FieldDescriptor* field) {
+  return GetJavaType(field->type());
+}
+
+// Get the fully-qualified class name for a boxed primitive type, e.g.
+// "java.lang.Integer" for JAVATYPE_INT.  Returns NULL for enum and message
+// types.
+const char* BoxedPrimitiveTypeName(JavaType type);
+
+string DefaultValue(const Params& params, const FieldDescriptor* field);
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_HELPERS_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.cc b/src/google/protobuf/compiler/javamicro/javamicro_message.cc
new file mode 100644
index 0000000..7fc6c3d
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_message.cc
@@ -0,0 +1,474 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <algorithm>
+#include <google/protobuf/stubs/hash.h>
+#include <google/protobuf/compiler/javamicro/javamicro_message.h>
+#include <google/protobuf/compiler/javamicro/javamicro_enum.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/io/coded_stream.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.pb.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+  // Print the field's proto-syntax definition as a comment.  We don't want to
+  // print group bodies so we cut off after the first line.
+  string def = field->DebugString();
+  printer->Print("// $def$\n",
+    "def", def.substr(0, def.find_first_of('\n')));
+}
+
+struct FieldOrderingByNumber {
+  inline bool operator()(const FieldDescriptor* a,
+                         const FieldDescriptor* b) const {
+    return a->number() < b->number();
+  }
+};
+
+// Sort the fields of the given Descriptor by number into a new[]'d array
+// and return it.
+const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
+  const FieldDescriptor** fields =
+    new const FieldDescriptor*[descriptor->field_count()];
+  for (int i = 0; i < descriptor->field_count(); i++) {
+    fields[i] = descriptor->field(i);
+  }
+  sort(fields, fields + descriptor->field_count(),
+       FieldOrderingByNumber());
+  return fields;
+}
+
+// Get an identifier that uniquely identifies this type within the file.
+// This is used to declare static variables related to this type at the
+// outermost file scope.
+string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
+  return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
+}
+
+// Returns true if the message type has any required fields.  If it doesn't,
+// we can optimize out calls to its isInitialized() method.
+//
+// already_seen is used to avoid checking the same type multiple times
+// (and also to protect against recursion).
+static bool HasRequiredFields(
+    const Descriptor* type,
+    hash_set<const Descriptor*>* already_seen) {
+  if (already_seen->count(type) > 0) {
+    // The type is already in cache.  This means that either:
+    // a. The type has no required fields.
+    // b. We are in the midst of checking if the type has required fields,
+    //    somewhere up the stack.  In this case, we know that if the type
+    //    has any required fields, they'll be found when we return to it,
+    //    and the whole call to HasRequiredFields() will return true.
+    //    Therefore, we don't have to check if this type has required fields
+    //    here.
+    return false;
+  }
+  already_seen->insert(type);
+
+  // If the type has extensions, an extension with message type could contain
+  // required fields, so we have to be conservative and assume such an
+  // extension exists.
+  if (type->extension_range_count() > 0) return true;
+
+  for (int i = 0; i < type->field_count(); i++) {
+    const FieldDescriptor* field = type->field(i);
+    if (field->is_required()) {
+      return true;
+    }
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+      if (HasRequiredFields(field->message_type(), already_seen)) {
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+static bool HasRequiredFields(const Descriptor* type) {
+  hash_set<const Descriptor*> already_seen;
+  return HasRequiredFields(type, &already_seen);
+}
+
+}  // namespace
+
+// ===================================================================
+
+MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
+  : params_(params),
+    descriptor_(descriptor),
+    field_generators_(descriptor, params) {
+}
+
+MessageGenerator::~MessageGenerator() {}
+
+void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
+  // Generate static members for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    MessageGenerator(descriptor_->nested_type(i), params_)
+      .GenerateStaticVariables(printer);
+  }
+}
+
+void MessageGenerator::GenerateStaticVariableInitializers(
+    io::Printer* printer) {
+  // Generate static member initializers for all nested types.
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    // TODO(kenton):  Reuse MessageGenerator objects?
+    MessageGenerator(descriptor_->nested_type(i), params_)
+      .GenerateStaticVariableInitializers(printer);
+  }
+
+  if (descriptor_->extension_count() != 0) {
+    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
+  }
+}
+
+void MessageGenerator::Generate(io::Printer* printer) {
+  bool is_own_file =
+    params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
+        && !params_.has_java_outer_classname(descriptor_->file()->name()));
+
+#if 0
+  GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
+  GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
+  GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
+  GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
+#endif
+
+  if ((descriptor_->extension_count() != 0)
+      || (descriptor_->extension_range_count() != 0)) {
+    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
+  }
+
+  printer->Print(
+    "public $modifiers$ final class $classname$ extends\n"
+    "    com.google.protobuf.micro.MessageMicro {\n",
+    "modifiers", is_own_file ? "" : "static",
+    "classname", descriptor_->name());
+  printer->Indent();
+  printer->Print(
+    "public $classname$() {}\n"
+    "\n",
+    "classname", descriptor_->name());
+
+  // Nested types and extensions
+  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
+    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
+  }
+
+  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
+  }
+
+  // Fields
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    PrintFieldComment(printer, descriptor_->field(i));
+    printer->Print("public static final int $constant_name$ = $number$;\n",
+      "constant_name", FieldConstantName(descriptor_->field(i)),
+      "number", SimpleItoa(descriptor_->field(i)->number()));
+    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
+    printer->Print("\n");
+  }
+
+  GenerateClear(printer);
+  GenerateIsInitialized(printer);
+  GenerateMessageSerializationMethods(printer);
+  GenerateMergeFromMethods(printer);
+  GenerateParseFromMethods(printer);
+
+  printer->Outdent();
+  printer->Print("}\n\n");
+}
+
+// ===================================================================
+
+void MessageGenerator::
+GenerateMessageSerializationMethods(io::Printer* printer) {
+  scoped_array<const FieldDescriptor*> sorted_fields(
+    SortFieldsByNumber(descriptor_));
+
+  if (descriptor_->extension_range_count() != 0) {
+    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
+  }
+
+  printer->Print(
+    "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
+    "                    throws java.io.IOException {\n");
+  printer->Indent();
+
+  // Output the fields in sorted order
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+      GenerateSerializeOneField(printer, sorted_fields[i]);
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "}\n"
+    "\n"
+    "private int cachedSize = -1;\n"
+    "public int getCachedSize() {\n"
+    "  if (cachedSize < 0) {\n"
+    "    // getSerializedSize sets cachedSize\n"
+    "    getSerializedSize();\n"
+    "  }\n"
+    "  return cachedSize;\n"
+    "}\n"
+    "\n"
+    "public int getSerializedSize() {\n"
+    "  int size = 0;\n");
+  printer->Indent();
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  cachedSize = size;\n"
+    "  return size;\n"
+    "}\n"
+    "\n");
+}
+
+void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
+  scoped_array<const FieldDescriptor*> sorted_fields(
+    SortFieldsByNumber(descriptor_));
+
+  if (params_.java_use_vector()) {
+    printer->Print(
+      "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
+      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
+      "    throws java.io.IOException {\n",
+      "classname", descriptor_->name());
+  } else {
+    printer->Print(
+      "public $classname$ mergeFrom(\n"
+      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
+      "    throws java.io.IOException {\n",
+      "classname", descriptor_->name());
+  }
+  printer->Indent();
+
+  printer->Print(
+    "while (true) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "int tag = input.readTag();\n"
+    "switch (tag) {\n");
+  printer->Indent();
+
+  printer->Print(
+    "case 0:\n"          // zero signals EOF / limit reached
+    "  return this;\n"
+    "default: {\n"
+    "  if (!parseUnknownField(input, tag)) {\n"
+    "    return this;\n"   // it's an endgroup tag
+    "  }\n"
+    "  break;\n"
+    "}\n");
+
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = sorted_fields[i];
+    uint32 tag = WireFormatLite::MakeTag(field->number(),
+      WireFormat::WireTypeForField(field));
+
+    printer->Print(
+      "case $tag$: {\n",
+      "tag", SimpleItoa(tag));
+    printer->Indent();
+
+    field_generators_.get(field).GenerateParsingCode(printer);
+
+    printer->Outdent();
+    printer->Print(
+      "  break;\n"
+      "}\n");
+  }
+
+  printer->Outdent();
+  printer->Outdent();
+  printer->Outdent();
+  printer->Print(
+    "    }\n"     // switch (tag)
+    "  }\n"       // while (true)
+    "}\n"
+    "\n");
+}
+
+void MessageGenerator::
+GenerateParseFromMethods(io::Printer* printer) {
+  bool is_own_file =
+    descriptor_->containing_type() == NULL;
+
+  // Note:  These are separate from GenerateMessageSerializationMethods()
+  //   because they need to be generated even for messages that are optimized
+  //   for code size.
+  printer->Print(
+    "public $static$ $classname$ parseFrom(byte[] data)\n"
+    "    throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
+    "  return ($classname$) (new $classname$().mergeFrom(data));\n"
+    "}\n"
+    "\n"
+    "public $static$ $classname$ parseFrom(\n"
+    "        com.google.protobuf.micro.CodedInputStreamMicro input)\n"
+    "    throws java.io.IOException {\n"
+    "  return ($classname$) (new $classname$().mergeFrom(input));\n"
+    "}\n"
+    "\n",
+    "static", (is_own_file ? "static" : ""),
+    "classname", descriptor_->name());
+}
+
+void MessageGenerator::GenerateSerializeOneField(
+    io::Printer* printer, const FieldDescriptor* field) {
+  field_generators_.get(field).GenerateSerializationCode(printer);
+}
+
+void MessageGenerator::GenerateClear(io::Printer* printer) {
+  printer->Print(
+    "public final $classname$ clear() {\n",
+    "classname", descriptor_->name());
+  printer->Indent();
+
+  // Call clear for all of the fields.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    printer->Print(
+      "clear$name$();\n",
+      "name", UnderscoresToCapitalizedCamelCase(field));
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  cachedSize = -1;\n"
+    "  return this;\n"
+    "}\n"
+    "\n");
+}
+
+
+void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
+  printer->Print(
+    "public final boolean isInitialized() {\n");
+  printer->Indent();
+
+  // Check that all required fields in this message are set.
+  // TODO(kenton):  We can optimize this when we switch to putting all the
+  //   "has" fields into a single bitfield.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+
+    if (field->is_required()) {
+      printer->Print(
+        "if (!has$name$) return false;\n",
+        "name", UnderscoresToCapitalizedCamelCase(field));
+    }
+  }
+
+  // Now check that all embedded messages are initialized.
+  for (int i = 0; i < descriptor_->field_count(); i++) {
+    const FieldDescriptor* field = descriptor_->field(i);
+    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
+        HasRequiredFields(field->message_type())) {
+      switch (field->label()) {
+        case FieldDescriptor::LABEL_REQUIRED:
+          printer->Print(
+            "if (!get$name$().isInitialized()) return false;\n",
+            "type", ClassName(params_, field->message_type()),
+            "name", UnderscoresToCapitalizedCamelCase(field));
+          break;
+        case FieldDescriptor::LABEL_OPTIONAL:
+          printer->Print(
+            "if (has$name$()) {\n"
+            "  if (!get$name$().isInitialized()) return false;\n"
+            "}\n",
+            "type", ClassName(params_, field->message_type()),
+            "name", UnderscoresToCapitalizedCamelCase(field));
+          break;
+        case FieldDescriptor::LABEL_REPEATED:
+          if (params_.java_use_vector()) {
+            printer->Print(
+              "for (int i = 0; i < get$name$List().size(); i++) {\n"
+              "  if (get$name$(i).isInitialized()) return false;\n"
+              "}\n",
+              "type", ClassName(params_, field->message_type()),
+              "name", UnderscoresToCapitalizedCamelCase(field));
+          } else {
+            printer->Print(
+              "for ($type$ element : get$name$List()) {\n"
+              "  if (!element.isInitialized()) return false;\n"
+              "}\n",
+              "type", ClassName(params_, field->message_type()),
+              "name", UnderscoresToCapitalizedCamelCase(field));
+          }
+          break;
+      }
+    }
+  }
+
+  if (descriptor_->extension_range_count() > 0) {
+    printer->Print(
+      "if (!extensionsAreInitialized()) return false;\n");
+  }
+
+  printer->Outdent();
+  printer->Print(
+    "  return true;\n"
+    "}\n"
+    "\n");
+}
+
+// ===================================================================
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message.h b/src/google/protobuf/compiler/javamicro/javamicro_message.h
new file mode 100644
index 0000000..f44c7a7
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_message.h
@@ -0,0 +1,93 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
+
+#include <string>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javamicro/javamicro_params.h>
+#include <google/protobuf/compiler/javamicro/javamicro_field.h>
+
+namespace google {
+namespace protobuf {
+  namespace io {
+    class Printer;             // printer.h
+  }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class MessageGenerator {
+ public:
+  explicit MessageGenerator(const Descriptor* descriptor, const Params& params);
+  ~MessageGenerator();
+
+  // All static variables have to be declared at the top-level of the file
+  // so that we can control initialization order, which is important for
+  // DescriptorProto bootstrapping to work.
+  void GenerateStaticVariables(io::Printer* printer);
+
+  // Output code which initializes the static variables generated by
+  // GenerateStaticVariables().
+  void GenerateStaticVariableInitializers(io::Printer* printer);
+
+  // Generate the class itself.
+  void Generate(io::Printer* printer);
+
+ private:
+  void GenerateMessageSerializationMethods(io::Printer* printer);
+  void GenerateMergeFromMethods(io::Printer* printer);
+  void GenerateParseFromMethods(io::Printer* printer);
+  void GenerateSerializeOneField(io::Printer* printer,
+                                 const FieldDescriptor* field);
+
+  void GenerateClear(io::Printer* printer);
+  void GenerateIsInitialized(io::Printer* printer);
+
+  const Params& params_;
+  const Descriptor* descriptor_;
+  FieldGeneratorMap field_generators_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc
new file mode 100644
index 0000000..103c302
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_message_field.cc
@@ -0,0 +1,302 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javamicro/javamicro_message_field.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+namespace {
+
+// TODO(kenton):  Factor out a "SetCommonFieldVariables()" to get rid of
+//   repeat code between this and the other field types.
+void SetMessageVariables(const Params& params,
+    const FieldDescriptor* descriptor, map<string, string>* variables) {
+  (*variables)["name"] =
+    UnderscoresToCamelCase(descriptor);
+  (*variables)["capitalized_name"] =
+    UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  (*variables)["type"] = ClassName(params, descriptor->message_type());
+  (*variables)["group_or_message"] =
+    (descriptor->type() == FieldDescriptor::TYPE_GROUP) ?
+    "Group" : "Message";
+  (*variables)["message_name"] = descriptor->containing_type()->name();
+  //(*variables)["message_type"] = descriptor->message_type()->name();
+}
+
+}  // namespace
+
+// ===================================================================
+
+MessageFieldGenerator::
+MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetMessageVariables(params, descriptor, &variables_);
+}
+
+MessageFieldGenerator::~MessageFieldGenerator() {}
+
+void MessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private boolean has$capitalized_name$;\n"
+//    "private $type$ $name$_ = null;\n"
+//    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+//    "public $type$ get$capitalized_name$() { return $name$_; }\n"
+    "private $type$ $name$_ = null;\n"
+    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n"
+    "public $type$ get$capitalized_name$() { return $name$_; }\n"
+    "public $message_name$ set$capitalized_name$($type$ value) {\n"
+    "  if (value == null) {\n"
+    "    throw new NullPointerException();\n"
+    "  }\n"
+    "  has$capitalized_name$ = true;\n"
+    "  $name$_ = value;\n"
+    "  return this;\n"
+    "}\n"
+    "public $message_name$ clear$capitalized_name$() {\n"
+    "  has$capitalized_name$ = false;\n"
+    "  $name$_ = null;\n"
+    "  return this;\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  merge$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$type$ value = new $type$();\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+      "input.readGroup(value, $number$);\n");
+  } else {
+    printer->Print(variables_,
+      "input.readMessage(value);\n");
+  }
+
+  printer->Print(variables_,
+    "set$capitalized_name$(value);\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  output.write$group_or_message$($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+void MessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (has$capitalized_name$()) {\n"
+    "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+    "    .compute$group_or_message$Size($number$, get$capitalized_name$());\n"
+    "}\n");
+}
+
+string MessageFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->message_type());
+}
+
+// ===================================================================
+
+RepeatedMessageFieldGenerator::
+RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetMessageVariables(params, descriptor, &variables_);
+}
+
+RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {}
+
+void RepeatedMessageFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "private java.util.Vector $name$_ = new java.util.Vector();\n"
+      "public java.util.Vector get$capitalized_name$List() {\n"
+      "  return $name$_;\n"
+      "}\n"
+      "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+      "public $type$ get$capitalized_name$(int index) {\n"
+      "  return ($type$) $name$_.elementAt(index);\n"
+      "}\n"
+      "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n"
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n"
+      "  $name$_.setElementAt(value, index);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ add$capitalized_name$($type$ value) {\n"
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n"
+      "  $name$_.addElement(value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  $name$_.removeAllElements();\n"
+      "  return this;\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "private java.util.List<$type$> $name$_ =\n"
+      "  java.util.Collections.emptyList();\n"
+      "public java.util.List<$type$> get$capitalized_name$List() {\n"
+      "  return $name$_;\n"
+      "}\n"
+      "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+      "public $type$ get$capitalized_name$(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n"
+      "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n"
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n"
+      "  $name$_.set(index, value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ add$capitalized_name$($type$ value) {\n"
+      "  if (value == null) {\n"
+      "    throw new NullPointerException();\n"
+      "  }\n"
+      "  if ($name$_.isEmpty()) {\n"
+      "    $name$_ = new java.util.ArrayList<$type$>();\n"
+      "  }\n"
+      "  $name$_.add(value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  $name$_ = java.util.Collections.emptyList();\n"
+      "  return this;\n"
+      "}\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "if (other.$name$_.size() != 0) {\n"
+      "  for (int i = 0; i < other.$name$_.size(); i++) {\n"
+      "    result.$name$_.addElement(other.$name$_.elementAt(i));\n"
+      "  }\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (!other.$name$_.isEmpty()) {\n"
+      "  if (result.$name$_.isEmpty()) {\n"
+      "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
+      "  }\n"
+      "  result.$name$_.addAll(other.$name$_);\n"
+      "}\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "$type$ value = new $type$();\n");
+
+  if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) {
+    printer->Print(variables_,
+      "input.readGroup(value, $number$);\n");
+  } else {
+    printer->Print(variables_,
+      "input.readMessage(value);\n");
+  }
+
+  printer->Print(variables_,
+    "add$capitalized_name$(value);\n");
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+      "  output.write$group_or_message$($number$, get$capitalized_name$(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for ($type$ element : get$capitalized_name$List()) {\n"
+      "  output.write$group_or_message$($number$, element);\n"
+      "}\n");
+  }
+}
+
+void RepeatedMessageFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+      "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .compute$group_or_message$Size($number$, get$capitalized_name$(i));\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "for ($type$ element : get$capitalized_name$List()) {\n"
+      "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .compute$group_or_message$Size($number$, element);\n"
+      "}\n");
+  }
+}
+
+string RepeatedMessageFieldGenerator::GetBoxedType() const {
+  return ClassName(params_, descriptor_->message_type());
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_message_field.h b/src/google/protobuf/compiler/javamicro/javamicro_message_field.h
new file mode 100644
index 0000000..a32aa4e
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_message_field.h
@@ -0,0 +1,95 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javamicro/javamicro_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class MessageFieldGenerator : public FieldGenerator {
+ public:
+  explicit MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  ~MessageFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator);
+};
+
+class RepeatedMessageFieldGenerator : public FieldGenerator {
+ public:
+  explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor,
+        const Params& params);
+  ~RepeatedMessageFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_FIELD_H__
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_params.h b/src/google/protobuf/compiler/javamicro/javamicro_params.h
new file mode 100644
index 0000000..a4a72b7
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_params.h
@@ -0,0 +1,143 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2010 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: wink@google.com (Wink Saville)
+
+#ifndef PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_
+#define PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_
+
+#include <map>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+enum eOptimization { JAVAMICRO_OPT_SPEED, JAVAMICRO_OPT_SPACE, JAVAMICRO_OPT_DEFAULT = JAVAMICRO_OPT_SPACE };
+
+// Parameters for used by the generators
+class Params {
+ public:
+  typedef map<string, string> NameMap;
+ private:
+  string empty_;
+  string base_name_;
+  eOptimization optimization_;
+  bool java_multiple_files_;
+  bool java_use_vector_;
+  NameMap java_packages_;
+  NameMap java_outer_classnames_;
+
+ public:
+  Params(const string & base_name) :
+    empty_(""),
+    base_name_(base_name),
+    optimization_(JAVAMICRO_OPT_DEFAULT),
+    java_multiple_files_(false),
+    java_use_vector_(false) {
+  }
+
+  const string& base_name() const {
+    return base_name_;
+  }
+
+  bool has_java_package(const string& file_name) const {
+    return java_packages_.find(file_name)
+                        != java_packages_.end();
+  }
+  void set_java_package(const string& file_name,
+      const string& java_package) {
+    java_packages_[file_name] = java_package;
+  }
+  const string& java_package(const string& file_name) const {
+    NameMap::const_iterator itr;
+
+    itr = java_packages_.find(file_name);
+    if  (itr == java_packages_.end()) {
+      return empty_;
+    } else {
+      return itr->second;
+    }
+  }
+  const NameMap& java_packages() {
+    return java_packages_;
+  }
+
+  bool has_java_outer_classname(const string& file_name) const {
+    return java_outer_classnames_.find(file_name)
+                        != java_outer_classnames_.end();
+  }
+  void set_java_outer_classname(const string& file_name,
+      const string& java_outer_classname) {
+    java_outer_classnames_[file_name] = java_outer_classname;
+  }
+  const string& java_outer_classname(const string& file_name) const {
+    NameMap::const_iterator itr;
+
+    itr = java_outer_classnames_.find(file_name);
+    if  (itr == java_outer_classnames_.end()) {
+      return empty_;
+    } else {
+      return itr->second;
+    }
+  }
+  const NameMap& java_outer_classnames() {
+    return java_outer_classnames_;
+  }
+
+  void set_optimization(eOptimization optimization) {
+    optimization_ = optimization;
+  }
+  eOptimization optimization() const {
+    return optimization_;
+  }
+
+  void set_java_multiple_files(bool value) {
+    java_multiple_files_ = value;
+  }
+  bool java_multiple_files() const {
+    return java_multiple_files_;
+  }
+
+  void set_java_use_vector(bool value) {
+    java_use_vector_ = value;
+  }
+  bool java_use_vector() const {
+    return java_use_vector_;
+  }
+
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
+#endif  // PROTOBUF_COMPILER_JAVAMICRO_JAVAMICRO_PARAMS_H_
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc
new file mode 100644
index 0000000..d6daa44
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc
@@ -0,0 +1,660 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/javamicro/javamicro_primitive_field.h>
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* PrimitiveTypeName(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT    : return "int";
+    case JAVATYPE_LONG   : return "long";
+    case JAVATYPE_FLOAT  : return "float";
+    case JAVATYPE_DOUBLE : return "double";
+    case JAVATYPE_BOOLEAN: return "boolean";
+    case JAVATYPE_STRING : return "java.lang.String";
+    case JAVATYPE_BYTES  : return "com.google.protobuf.micro.ByteStringMicro";
+    case JAVATYPE_ENUM   : return NULL;
+    case JAVATYPE_MESSAGE: return NULL;
+
+    // No default because we want the compiler to complain if any new
+    // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+bool IsReferenceType(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT    : return false;
+    case JAVATYPE_LONG   : return false;
+    case JAVATYPE_FLOAT  : return false;
+    case JAVATYPE_DOUBLE : return false;
+    case JAVATYPE_BOOLEAN: return false;
+    case JAVATYPE_STRING : return true;
+    case JAVATYPE_BYTES  : return true;
+    case JAVATYPE_ENUM   : return false;
+    case JAVATYPE_MESSAGE: return true;
+
+    // No default because we want the compiler to complain if any new
+    // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+const char* GetCapitalizedType(const FieldDescriptor* field) {
+  switch (field->type()) {
+    case FieldDescriptor::TYPE_INT32   : return "Int32"   ;
+    case FieldDescriptor::TYPE_UINT32  : return "UInt32"  ;
+    case FieldDescriptor::TYPE_SINT32  : return "SInt32"  ;
+    case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ;
+    case FieldDescriptor::TYPE_SFIXED32: return "SFixed32";
+    case FieldDescriptor::TYPE_INT64   : return "Int64"   ;
+    case FieldDescriptor::TYPE_UINT64  : return "UInt64"  ;
+    case FieldDescriptor::TYPE_SINT64  : return "SInt64"  ;
+    case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ;
+    case FieldDescriptor::TYPE_SFIXED64: return "SFixed64";
+    case FieldDescriptor::TYPE_FLOAT   : return "Float"   ;
+    case FieldDescriptor::TYPE_DOUBLE  : return "Double"  ;
+    case FieldDescriptor::TYPE_BOOL    : return "Bool"    ;
+    case FieldDescriptor::TYPE_STRING  : return "String"  ;
+    case FieldDescriptor::TYPE_BYTES   : return "Bytes"   ;
+    case FieldDescriptor::TYPE_ENUM    : return "Enum"    ;
+    case FieldDescriptor::TYPE_GROUP   : return "Group"   ;
+    case FieldDescriptor::TYPE_MESSAGE : return "Message" ;
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return NULL;
+}
+
+// For encodings with fixed sizes, returns that size in bytes.  Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type) {
+  switch (type) {
+    case FieldDescriptor::TYPE_INT32   : return -1;
+    case FieldDescriptor::TYPE_INT64   : return -1;
+    case FieldDescriptor::TYPE_UINT32  : return -1;
+    case FieldDescriptor::TYPE_UINT64  : return -1;
+    case FieldDescriptor::TYPE_SINT32  : return -1;
+    case FieldDescriptor::TYPE_SINT64  : return -1;
+    case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size;
+    case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size;
+    case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size;
+    case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size;
+    case FieldDescriptor::TYPE_FLOAT   : return WireFormatLite::kFloatSize;
+    case FieldDescriptor::TYPE_DOUBLE  : return WireFormatLite::kDoubleSize;
+
+    case FieldDescriptor::TYPE_BOOL    : return WireFormatLite::kBoolSize;
+    case FieldDescriptor::TYPE_ENUM    : return -1;
+
+    case FieldDescriptor::TYPE_STRING  : return -1;
+    case FieldDescriptor::TYPE_BYTES   : return -1;
+    case FieldDescriptor::TYPE_GROUP   : return -1;
+    case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+    // No default because we want the compiler to complain if any new
+    // types are added.
+  }
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return -1;
+}
+
+// Return true if the type is a that has variable length
+// for instance String's.
+bool IsVariableLenType(JavaType type) {
+  switch (type) {
+    case JAVATYPE_INT    : return false;
+    case JAVATYPE_LONG   : return false;
+    case JAVATYPE_FLOAT  : return false;
+    case JAVATYPE_DOUBLE : return false;
+    case JAVATYPE_BOOLEAN: return false;
+    case JAVATYPE_STRING : return true;
+    case JAVATYPE_BYTES  : return true;
+    case JAVATYPE_ENUM   : return false;
+    case JAVATYPE_MESSAGE: return true;
+
+    // No default because we want the compiler to complain if any new
+    // JavaTypes are added.
+  }
+
+  GOOGLE_LOG(FATAL) << "Can't get here.";
+  return false;
+}
+
+bool IsStringUtf8Handling(const FieldDescriptor* descriptor,
+      const Params params) {
+  return ((params.optimization() == JAVAMICRO_OPT_SPEED)
+      && (GetJavaType(descriptor) == JAVATYPE_STRING));
+}
+
+void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params,
+                           map<string, string>* variables) {
+  (*variables)["name"] =
+    UnderscoresToCamelCase(descriptor);
+  (*variables)["capitalized_name"] =
+    UnderscoresToCapitalizedCamelCase(descriptor);
+  (*variables)["number"] = SimpleItoa(descriptor->number());
+  if (IsStringUtf8Handling(descriptor, params)) {
+    (*variables)["type"] = "com.google.protobuf.micro.StringUtf8Micro";
+    string defaultValue = DefaultValue(params, descriptor);
+    if (defaultValue == "\"\"") {
+      (*variables)["default"] =
+          "com.google.protobuf.micro.StringUtf8Micro.EMPTY";
+    } else {
+      (*variables)["default"] = "new com.google.protobuf.micro.StringUtf8Micro("
+              + defaultValue + ")";
+    }
+  } else {
+    (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor));
+    (*variables)["default"] = DefaultValue(params, descriptor);
+  }
+  (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
+  (*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
+  (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+  (*variables)["tag_size"] = SimpleItoa(
+      WireFormat::TagSize(descriptor->number(), descriptor->type()));
+  if (IsReferenceType(GetJavaType(descriptor))) {
+    (*variables)["null_check"] =
+        "  if (value == null) {\n"
+        "    throw new NullPointerException();\n"
+        "  }\n";
+  } else {
+    (*variables)["null_check"] = "";
+  }
+  int fixed_size = FixedSize(descriptor->type());
+  if (fixed_size != -1) {
+    (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+  }
+  (*variables)["message_name"] = descriptor->containing_type()->name();
+}
+}  // namespace
+
+// ===================================================================
+
+PrimitiveFieldGenerator::
+PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetPrimitiveVariables(descriptor, params, &variables_);
+}
+
+PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
+
+void PrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  printer->Print(variables_,
+    "private boolean has$capitalized_name$;\n"
+    "private $type$ $name$_ = $default$;\n"
+    "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n");
+  if (IsStringUtf8Handling(descriptor_, params_)) {
+    printer->Print(variables_,
+      "public String get$capitalized_name$() { return $name$_.getString(); }\n"
+      "public $type$ get$capitalized_name$StringUtf8() { return $name$_; }\n"
+      "public $message_name$ set$capitalized_name$(String value) {\n"
+      "  has$capitalized_name$ = true;\n"
+      "  if ($name$_ == $default$) {\n"
+      "    $name$_ = new $type$(value);\n"
+      "  } else {\n"
+      "    $name$_.setString(value);\n"
+      "  }\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  has$capitalized_name$ = false;\n"
+      "  $name$_ = $default$;\n"
+      "  return this;\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "public $type$ get$capitalized_name$() { return $name$_; }\n");
+    if (IsVariableLenType(GetJavaType(descriptor_))) {
+      printer->Print(variables_,
+        "public $message_name$ set$capitalized_name$($type$ value) {\n"
+        "  has$capitalized_name$ = true;\n"
+        "  $name$_ = value;\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  has$capitalized_name$ = false;\n"
+        "  $name$_ = $default$;\n"
+        "  return this;\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "public $message_name$ set$capitalized_name$($type$ value) {\n"
+        "  has$capitalized_name$ = true;\n"
+        "  $name$_ = value;\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  has$capitalized_name$ = false;\n"
+        "  $name$_ = $default$;\n"
+        "  return this;\n"
+        "}\n");
+    }
+  }
+}
+
+void PrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "if (other.has$capitalized_name$()) {\n"
+    "  set$capitalized_name$(other.get$capitalized_name$());\n"
+    "}\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "set$capitalized_name$(input.read$capitalized_type$());\n");
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (IsStringUtf8Handling(descriptor_, params_)) {
+    printer->Print(variables_,
+      "if (has$capitalized_name$()) {\n"
+      "  output.writeStringUtf8($number$, get$capitalized_name$StringUtf8());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (has$capitalized_name$()) {\n"
+      "  output.write$capitalized_type$($number$, get$capitalized_name$());\n"
+      "}\n");
+  }
+}
+
+void PrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  if (IsStringUtf8Handling(descriptor_, params_)) {
+    printer->Print(variables_,
+      "if (has$capitalized_name$()) {\n"
+      "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .computeStringUtf8Size($number$, get$capitalized_name$StringUtf8());\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (has$capitalized_name$()) {\n"
+      "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+      "    .compute$capitalized_type$Size($number$, get$capitalized_name$());\n"
+      "}\n");
+  }
+}
+
+string PrimitiveFieldGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+// ===================================================================
+
+RepeatedPrimitiveFieldGenerator::
+RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params)
+  : FieldGenerator(params), descriptor_(descriptor) {
+  SetPrimitiveVariables(descriptor, params, &variables_);
+  if (descriptor_->options().packed()) {
+    GOOGLE_LOG(FATAL) << "MicroRuntime does not support packed";
+  }
+}
+
+RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMembers(io::Printer* printer) const {
+  if (IsStringUtf8Handling(descriptor_, params_)) {
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "private java.util.Vector $name$_ = new java.util.Vector();\n"
+        "public java.util.Vector get$capitalized_name$List() {\n"
+        "  return $name$_;\n"
+        "}\n"
+        "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+        "public String get$capitalized_name$(int index) {\n"
+        "  return (($type$)$name$_.elementAt(index)).getString();\n"
+        "}\n"
+        "public $type$ get$capitalized_name$StringUtf8(int index) {\n"
+        "  return ($type$)$name$_.elementAt(index);\n"
+        "}\n"
+        "public $message_name$ set$capitalized_name$(int index, String value) {\n"
+        "$null_check$"
+        "  $name$_.setElementAt(new $type$(value), index);\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ add$capitalized_name$(String value) {\n"
+        "$null_check$"
+        "  $name$_.addElement(new $type$(value));\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  $name$_.removeAllElements();\n"
+        "  return this;\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "private java.util.List<$type$> $name$_ =\n"
+        "  java.util.Collections.emptyList();\n"
+        "public java.util.List<$type$> get$capitalized_name$List() {\n"
+        "  return $name$_;\n"   // note:  unmodifiable list
+        "}\n"
+        "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+        "public String get$capitalized_name$(int index) {\n"
+        "  return $name$_.get(index).getString();\n"
+        "}\n"
+        "public $message_name$ set$capitalized_name$(int index, String value) {\n"
+        "$null_check$"
+        "  $name$_.set(index, new $type$(value));\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ add$capitalized_name$(String value) {\n"
+        "$null_check$"
+        "  if ($name$_.isEmpty()) {\n"
+        "    $name$_ = new java.util.ArrayList<$type$>();\n"
+        "  }\n"
+        "  $name$_.add(new $type$(value));\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  $name$_ = java.util.Collections.emptyList();\n"
+        "  return this;\n"
+        "}\n");
+    }
+  } else if (params_.java_use_vector()) {
+    if (IsReferenceType(GetJavaType(descriptor_))) {
+      printer->Print(variables_,
+        "private java.util.Vector $name$_ = new java.util.Vector();\n"
+        "public java.util.Vector get$capitalized_name$List() {\n"
+        "  return $name$_;\n"
+        "}\n"
+        "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+        "public $type$ get$capitalized_name$(int index) {\n"
+        "  return ($type$) $name$_.elementAt(index);\n"
+        "}\n"
+        "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n"
+        "$null_check$"
+        "  $name$_.setElementAt(value, index);\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ add$capitalized_name$($type$ value) {\n"
+        "$null_check$"
+        "  $name$_.addElement(value);\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  $name$_.removeAllElements();\n"
+        "  return this;\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "private java.util.Vector $name$_ = new java.util.Vector();\n"
+        "public java.util.Vector get$capitalized_name$List() {\n"
+        "  return $name$_;\n"
+        "}\n"
+        "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+        "public $type$ get$capitalized_name$(int index) {\n"
+        "  return (($boxed_type$)$name$_.elementAt(index)).$type$Value();\n"
+        "}\n"
+        "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n"
+        "$null_check$"
+        "  $name$_.setElementAt(new $boxed_type$(value), index);\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ add$capitalized_name$($type$ value) {\n"
+        "$null_check$"
+        "  $name$_.addElement(new $boxed_type$(value));\n"
+        "  return this;\n"
+        "}\n"
+        "public $message_name$ clear$capitalized_name$() {\n"
+        "  $name$_.removeAllElements();\n"
+        "  return this;\n"
+        "}\n");
+    }
+  } else {
+    printer->Print(variables_,
+      "private java.util.List<$boxed_type$> $name$_ =\n"
+      "  java.util.Collections.emptyList();\n"
+      "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
+      "  return $name$_;\n"   // note:  unmodifiable list
+      "}\n"
+      "public int get$capitalized_name$Count() { return $name$_.size(); }\n"
+      "public $type$ get$capitalized_name$(int index) {\n"
+      "  return $name$_.get(index);\n"
+      "}\n"
+      "public $message_name$ set$capitalized_name$(int index, $type$ value) {\n"
+      "$null_check$"
+      "  $name$_.set(index, value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ add$capitalized_name$($type$ value) {\n"
+      "$null_check$"
+      "  if ($name$_.isEmpty()) {\n"
+      "    $name$_ = new java.util.ArrayList<$boxed_type$>();\n"
+      "  }\n"
+      "  $name$_.add(value);\n"
+      "  return this;\n"
+      "}\n"
+      "public $message_name$ clear$capitalized_name$() {\n"
+      "  $name$_ = java.util.Collections.emptyList();\n"
+      "  return this;\n"
+      "}\n");
+  }
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "private int $name$MemoizedSerializedSize;\n");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+  if (params_.java_use_vector()) {
+    printer->Print(variables_,
+      "if (other.$name$_.size() != 0) {\n"
+      "  for (int i = 0; i < other.$name$_.size(); i++)) {\n"
+      "    result.$name$_.addElement(other.$name$_.elementAt(i));\n"
+      "  }\n"
+      "}\n");
+  } else {
+    printer->Print(variables_,
+      "if (!other.$name$_.isEmpty()) {\n"
+      "  if (result.$name$_.isEmpty()) {\n"
+      "    result.$name$_ = new java.util.ArrayList<$type$>();\n"
+      "  }\n"
+      "  result.$name$_.addAll(other.$name$_);\n"
+      "}\n");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateParsingCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "int length = input.readRawVarint32();\n"
+      "int limit = input.pushLimit(length);\n"
+      "while (input.getBytesUntilLimit() > 0) {\n"
+      "  add$capitalized_name$(input.read$capitalized_type$());\n"
+      "}\n"
+      "input.popLimit(limit);\n");
+  } else {
+    printer->Print(variables_,
+      "add$capitalized_name$(input.read$capitalized_type$());\n");
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializationCode(io::Printer* printer) const {
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+        "if (get$capitalized_name$List().size() > 0) {\n"
+        "  output.writeRawVarint32($tag$);\n"
+        "  output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+        "}\n");
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+        "  output.write$capitalized_type$NoTag(get$capitalized_name$(i));\n"
+        "}\n");
+    } else {
+      printer->Print(variables_,
+        "for ($type$ element : get$capitalized_name$List()) {\n"
+        "  output.write$capitalized_type$NoTag(element);\n"
+        "}\n");
+    }
+  } else {
+    if (params_.java_use_vector()) {
+      if (IsStringUtf8Handling(descriptor_, params_)) {
+        printer->Print(variables_,
+          "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+          "  output.writeStringUtf8($number$, get$capitalized_name$StringUtf8(i));\n"
+          "}\n");
+      } else {
+        printer->Print(variables_,
+          "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+          "  output.write$capitalized_type$($number$, get$capitalized_name$(i));\n"
+          "}\n");
+      }
+    } else {
+      if (IsStringUtf8Handling(descriptor_, params_)) {
+        printer->Print(variables_,
+          "for ($type$ element : get$capitalized_name$List()) {\n"
+          "  output.writeStringUtf8($number$, element);\n"
+          "}\n");
+      } else {
+        printer->Print(variables_,
+          "for ($type$ element : get$capitalized_name$List()) {\n"
+          "  output.write$capitalized_type$($number$, element);\n"
+          "}\n");
+      }
+    }
+  }
+}
+
+void RepeatedPrimitiveFieldGenerator::
+GenerateSerializedSizeCode(io::Printer* printer) const {
+  printer->Print(variables_,
+    "{\n"
+    "  int dataSize = 0;\n");
+  printer->Indent();
+
+  if (FixedSize(descriptor_->type()) == -1) {
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "for (int i = 0; i < get$capitalized_name$List().size(); i++) {\n"
+        "  dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n");
+      if (IsStringUtf8Handling(descriptor_, params_)) {
+        printer->Print(variables_,
+          "    .computeStringUtf8SizeNoTag(get$capitalized_name$StringUtf8(i));\n"
+          "}\n");
+      } else {
+        printer->Print(variables_,
+          "    .compute$capitalized_type$SizeNoTag(($type$)get$capitalized_name$(i));\n"
+          "}\n");
+      }
+    } else {
+      printer->Print(variables_,
+        "for ($type$ element : get$capitalized_name$List()) {\n"
+        "  dataSize += com.google.protobuf.micro.CodedOutputStreamMicro\n");
+      if (IsStringUtf8Handling(descriptor_, params_)) {
+        printer->Print(variables_,
+          "    .computeStringUtf8SizeNoTag(element);\n"
+          "}\n");
+      } else {
+        printer->Print(variables_,
+          "    .compute$capitalized_type$SizeNoTag(element);\n"
+          "}\n");
+      }
+    }
+  } else {
+    printer->Print(variables_,
+      "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  printer->Print(
+      "size += dataSize;\n");
+
+  if (descriptor_->options().packed()) {
+    if (params_.java_use_vector()) {
+      printer->Print(variables_,
+        "if (get$capitalized_name$List().size() != 0) {\n");
+    } else {
+      printer->Print(variables_,
+        "if (!get$capitalized_name$List().isEmpty()) {\n");
+    }
+    printer->Print(variables_,
+        "  size += $tag_size$;\n"
+        "  size += com.google.protobuf.micro.CodedOutputStreamMicro\n"
+        "      .computeInt32SizeNoTag(dataSize);\n"
+        "}\n");
+  } else {
+    printer->Print(variables_,
+      "size += $tag_size$ * get$capitalized_name$List().size();\n");
+  }
+
+  // cache the data size for packed fields.
+  if (descriptor_->options().packed()) {
+    printer->Print(variables_,
+      "$name$MemoizedSerializedSize = dataSize;\n");
+  }
+
+  printer->Outdent();
+  printer->Print("}\n");
+}
+
+string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
+  return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+}
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+}  // namespace google
diff --git a/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h
new file mode 100644
index 0000000..88d8eec
--- /dev/null
+++ b/src/google/protobuf/compiler/javamicro/javamicro_primitive_field.h
@@ -0,0 +1,94 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//  Based on original Protocol Buffers design by
+//  Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__
+
+#include <map>
+#include <string>
+#include <google/protobuf/compiler/javamicro/javamicro_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javamicro {
+
+class PrimitiveFieldGenerator : public FieldGenerator {
+ public:
+  explicit PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params &params);
+  ~PrimitiveFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator);
+};
+
+class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
+ public:
+  explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params);
+  ~RepeatedPrimitiveFieldGenerator();
+
+  // implements FieldGenerator ---------------------------------------
+  void GenerateMembers(io::Printer* printer) const;
+  void GenerateMergingCode(io::Printer* printer) const;
+  void GenerateParsingCode(io::Printer* printer) const;
+  void GenerateSerializationCode(io::Printer* printer) const;
+  void GenerateSerializedSizeCode(io::Printer* printer) const;
+
+  string GetBoxedType() const;
+
+ private:
+  const FieldDescriptor* descriptor_;
+  map<string, string> variables_;
+
+  GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator);
+};
+
+}  // namespace javamicro
+}  // namespace compiler
+}  // namespace protobuf
+
+}  // namespace google
+#endif  // GOOGLE_PROTOBUF_COMPILER_JAVAMICRO_PRIMITIVE_FIELD_H__
diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc
index d9b0c3f..813a011 100644
--- a/src/google/protobuf/compiler/main.cc
+++ b/src/google/protobuf/compiler/main.cc
@@ -34,6 +34,7 @@
 #include <google/protobuf/compiler/cpp/cpp_generator.h>
 #include <google/protobuf/compiler/python/python_generator.h>
 #include <google/protobuf/compiler/java/java_generator.h>
+#include <google/protobuf/compiler/javamicro/javamicro_generator.h>
 
 
 int main(int argc, char* argv[]) {
@@ -57,5 +58,10 @@
   cli.RegisterGenerator("--python_out", &py_generator,
                         "Generate Python source file.");
 
+  // Proto2 JavaMicro
+  google::protobuf::compiler::javamicro::JavaMicroGenerator javamicro_generator;
+  cli.RegisterGenerator("--javamicro_out", &javamicro_generator,
+                        "Generate Java source file micro runtime.");
+
   return cli.Run(argc, argv);
 }
diff --git a/src/google/protobuf/unittest_import_micro.proto b/src/google/protobuf/unittest_import_micro.proto
new file mode 100644
index 0000000..adac807
--- /dev/null
+++ b/src/google/protobuf/unittest_import_micro.proto
@@ -0,0 +1,49 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// This is like unittest_import.proto but with optimize_for = MICRO_RUNTIME.
+
+package protobuf_unittest_import;
+
+// java_package and java_outer_classname are specified on the command line.
+//option java_package = "com.google.protobuf.micro";
+//option java_outer_classname = "UnittestImportMicro";
+
+message ImportMessageMicro {
+  optional int32 d = 1;
+}
+
+enum ImportEnumMicro {
+  IMPORT_MICRO_FOO = 7;
+  IMPORT_MICRO_BAR = 8;
+  IMPORT_MICRO_BAZ = 9;
+}
diff --git a/src/google/protobuf/unittest_micro.proto b/src/google/protobuf/unittest_micro.proto
new file mode 100644
index 0000000..3d7fcd2
--- /dev/null
+++ b/src/google/protobuf/unittest_micro.proto
@@ -0,0 +1,162 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: wink@google.com (Wink Saville)
+
+package protobuf_unittest;
+
+import "google/protobuf/unittest_import_micro.proto";
+
+option java_package = "com.google.protobuf.micro";
+option java_outer_classname = "MicroOuterClass";
+
+// Same as TestAllTypes but with the micro runtime.
+message TestAllTypesMicro {
+
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  // Singular
+  optional    int32 optional_int32    =  1;
+  optional    int64 optional_int64    =  2;
+  optional   uint32 optional_uint32   =  3;
+  optional   uint64 optional_uint64   =  4;
+  optional   sint32 optional_sint32   =  5;
+  optional   sint64 optional_sint64   =  6;
+  optional  fixed32 optional_fixed32  =  7;
+  optional  fixed64 optional_fixed64  =  8;
+  optional sfixed32 optional_sfixed32 =  9;
+  optional sfixed64 optional_sfixed64 = 10;
+  optional    float optional_float    = 11;
+  optional   double optional_double   = 12;
+  optional     bool optional_bool     = 13;
+  optional   string optional_string   = 14;
+  optional    bytes optional_bytes    = 15;
+
+  optional group OptionalGroup = 16 {
+    optional int32 a = 17;
+  }
+
+  optional NestedMessage      optional_nested_message  = 18;
+  optional ForeignMessageMicro optional_foreign_message = 19;
+  optional protobuf_unittest_import.ImportMessageMicro
+    optional_import_message = 20;
+
+  optional NestedEnum      optional_nested_enum     = 21;
+  optional ForeignEnumMicro optional_foreign_enum    = 22;
+  optional protobuf_unittest_import.ImportEnumMicro optional_import_enum = 23;
+
+  optional string optional_string_piece = 24 [ctype=STRING_PIECE];
+  optional string optional_cord = 25 [ctype=CORD];
+
+  // Repeated
+  repeated    int32 repeated_int32    = 31;
+  repeated    int64 repeated_int64    = 32;
+  repeated   uint32 repeated_uint32   = 33;
+  repeated   uint64 repeated_uint64   = 34;
+  repeated   sint32 repeated_sint32   = 35;
+  repeated   sint64 repeated_sint64   = 36;
+  repeated  fixed32 repeated_fixed32  = 37;
+  repeated  fixed64 repeated_fixed64  = 38;
+  repeated sfixed32 repeated_sfixed32 = 39;
+  repeated sfixed64 repeated_sfixed64 = 40;
+  repeated    float repeated_float    = 41;
+  repeated   double repeated_double   = 42;
+  repeated     bool repeated_bool     = 43;
+  repeated   string repeated_string   = 44;
+  repeated    bytes repeated_bytes    = 45;
+
+  repeated group RepeatedGroup = 46 {
+    optional int32 a = 47;
+  }
+
+  repeated NestedMessage      repeated_nested_message  = 48;
+  repeated ForeignMessageMicro repeated_foreign_message = 49;
+  repeated protobuf_unittest_import.ImportMessageMicro
+    repeated_import_message = 50;
+
+  repeated NestedEnum      repeated_nested_enum  = 51;
+  repeated ForeignEnumMicro repeated_foreign_enum = 52;
+  repeated protobuf_unittest_import.ImportEnumMicro repeated_import_enum = 53;
+
+  repeated string repeated_string_piece = 54 [ctype=STRING_PIECE];
+  repeated string repeated_cord = 55 [ctype=CORD];
+
+  // Singular with defaults
+  optional    int32 default_int32    = 61 [default =  41    ];
+  optional    int64 default_int64    = 62 [default =  42    ];
+  optional   uint32 default_uint32   = 63 [default =  43    ];
+  optional   uint64 default_uint64   = 64 [default =  44    ];
+  optional   sint32 default_sint32   = 65 [default = -45    ];
+  optional   sint64 default_sint64   = 66 [default =  46    ];
+  optional  fixed32 default_fixed32  = 67 [default =  47    ];
+  optional  fixed64 default_fixed64  = 68 [default =  48    ];
+  optional sfixed32 default_sfixed32 = 69 [default =  49    ];
+  optional sfixed64 default_sfixed64 = 70 [default = -50    ];
+  optional    float default_float    = 71 [default =  51.5  ];
+  optional   double default_double   = 72 [default =  52e3  ];
+  optional     bool default_bool     = 73 [default = true   ];
+  optional   string default_string   = 74 [default = "hello"];
+  optional    bytes default_bytes    = 75 [default = "world"];
+
+  optional NestedEnum default_nested_enum = 81 [default = BAR];
+  optional ForeignEnumMicro default_foreign_enum = 82
+      [default = FOREIGN_MICRO_BAR];
+  optional protobuf_unittest_import.ImportEnumMicro
+      default_import_enum = 83 [default = IMPORT_MICRO_BAR];
+
+  optional string default_string_piece = 84 [ctype=STRING_PIECE,default="abc"];
+  optional string default_cord = 85 [ctype=CORD,default="123"];
+
+  required int32 id = 86;
+}
+
+message ForeignMessageMicro {
+  optional int32 c = 1;
+}
+
+enum ForeignEnumMicro {
+  FOREIGN_MICRO_FOO = 4;
+  FOREIGN_MICRO_BAR = 5;
+  FOREIGN_MICRO_BAZ = 6;
+}
+
+// Test that deprecated fields work.  We only verify that they compile (at one
+// point this failed).
+message TestDeprecatedMicro {
+  optional int32 deprecated_field = 1 [deprecated = true];
+}
diff --git a/src/google/protobuf/unittest_recursive_micro.proto b/src/google/protobuf/unittest_recursive_micro.proto
new file mode 100644
index 0000000..a256852
--- /dev/null
+++ b/src/google/protobuf/unittest_recursive_micro.proto
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.micro";
+
+message RecursiveMessageMicro {
+  message NestedMessage {
+    optional RecursiveMessageMicro a = 1;
+  }
+
+  required int32 id = 1;
+  optional NestedMessage nested_message = 2;
+  optional RecursiveMessageMicro optional_recursive_message_micro = 3;
+  repeated RecursiveMessageMicro repeated_recursive_message_micro = 4;
+}
diff --git a/src/google/protobuf/unittest_simple_micro.proto b/src/google/protobuf/unittest_simple_micro.proto
new file mode 100644
index 0000000..057bf3d
--- /dev/null
+++ b/src/google/protobuf/unittest_simple_micro.proto
@@ -0,0 +1,52 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.micro";
+
+message SimpleMessageMicro {
+  message NestedMessage {
+    optional int32 bb = 1;
+  }
+
+  enum NestedEnum {
+    FOO = 1;
+    BAR = 2;
+    BAZ = 3;
+  }
+
+  optional int32 d = 1 [default = 123];
+  optional NestedMessage nested_msg = 2;
+  optional NestedEnum default_nested_enum = 3 [default = BAZ];
+}
diff --git a/src/google/protobuf/unittest_stringutf8_micro.proto b/src/google/protobuf/unittest_stringutf8_micro.proto
new file mode 100644
index 0000000..e4bbe3d
--- /dev/null
+++ b/src/google/protobuf/unittest_stringutf8_micro.proto
@@ -0,0 +1,41 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc.  All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: wink@google.com (Wink Saville)
+//
+
+package protobuf_unittest_import;
+
+option java_package = "com.google.protobuf.micro";
+
+message StringUtf8 {
+  optional string id = 1;
+  repeated string rs = 2;
+}