aboutsummaryrefslogtreecommitdiffstats
path: root/java
diff options
context:
space:
mode:
authorWink Saville <wink@google.com>2010-05-27 16:25:37 -0700
committerWink Saville <wink@google.com>2010-05-27 16:25:37 -0700
commitfbaaef999ba563838ebd00874ed8a1c01fbf286d (patch)
tree24ff5c76344e90abc5b0fe6f07120ea0d2d011ee /java
parent79a4a60053f74ab71c7c3ec436d2f6caedc5be61 (diff)
downloadexternal_protobuf-fbaaef999ba563838ebd00874ed8a1c01fbf286d.zip
external_protobuf-fbaaef999ba563838ebd00874ed8a1c01fbf286d.tar.gz
external_protobuf-fbaaef999ba563838ebd00874ed8a1c01fbf286d.tar.bz2
Add protobuf 2.2.0a sources
This is the contents of protobuf-2.2.0a.tar.bz2 from http://code.google.com/p/protobuf/downloads/list and is the base code for the javamicro code generator. Change-Id: Ie9a0440a824d615086445b6636944484b3155afa
Diffstat (limited to 'java')
-rw-r--r--java/README.txt96
-rw-r--r--java/pom.xml174
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessage.java690
-rw-r--r--java/src/main/java/com/google/protobuf/AbstractMessageLite.java321
-rw-r--r--java/src/main/java/com/google/protobuf/BlockingRpcChannel.java51
-rw-r--r--java/src/main/java/com/google/protobuf/BlockingService.java64
-rw-r--r--java/src/main/java/com/google/protobuf/ByteString.java344
-rw-r--r--java/src/main/java/com/google/protobuf/CodedInputStream.java826
-rw-r--r--java/src/main/java/com/google/protobuf/CodedOutputStream.java1017
-rw-r--r--java/src/main/java/com/google/protobuf/Descriptors.java1871
-rw-r--r--java/src/main/java/com/google/protobuf/DynamicMessage.java438
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionRegistry.java261
-rw-r--r--java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java169
-rw-r--r--java/src/main/java/com/google/protobuf/FieldSet.java712
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessage.java1318
-rw-r--r--java/src/main/java/com/google/protobuf/GeneratedMessageLite.java539
-rw-r--r--java/src/main/java/com/google/protobuf/Internal.java121
-rw-r--r--java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java93
-rw-r--r--java/src/main/java/com/google/protobuf/Message.java305
-rw-r--r--java/src/main/java/com/google/protobuf/MessageLite.java331
-rw-r--r--java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java58
-rw-r--r--java/src/main/java/com/google/protobuf/RpcCallback.java41
-rw-r--r--java/src/main/java/com/google/protobuf/RpcChannel.java65
-rw-r--r--java/src/main/java/com/google/protobuf/RpcController.java112
-rw-r--r--java/src/main/java/com/google/protobuf/RpcUtil.java135
-rw-r--r--java/src/main/java/com/google/protobuf/Service.java111
-rw-r--r--java/src/main/java/com/google/protobuf/ServiceException.java44
-rw-r--r--java/src/main/java/com/google/protobuf/TextFormat.java1323
-rw-r--r--java/src/main/java/com/google/protobuf/UninitializedMessageException.java99
-rw-r--r--java/src/main/java/com/google/protobuf/UnknownFieldSet.java947
-rw-r--r--java/src/main/java/com/google/protobuf/WireFormat.java153
-rw-r--r--java/src/test/java/com/google/protobuf/AbstractMessageTest.java421
-rw-r--r--java/src/test/java/com/google/protobuf/CodedInputStreamTest.java486
-rw-r--r--java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java304
-rw-r--r--java/src/test/java/com/google/protobuf/DescriptorsTest.java408
-rw-r--r--java/src/test/java/com/google/protobuf/DynamicMessageTest.java226
-rw-r--r--java/src/test/java/com/google/protobuf/GeneratedMessageTest.java618
-rw-r--r--java/src/test/java/com/google/protobuf/LiteTest.java114
-rw-r--r--java/src/test/java/com/google/protobuf/MessageTest.java313
-rw-r--r--java/src/test/java/com/google/protobuf/ServiceTest.java271
-rw-r--r--java/src/test/java/com/google/protobuf/TestUtil.java3660
-rw-r--r--java/src/test/java/com/google/protobuf/TextFormatTest.java636
-rw-r--r--java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java437
-rw-r--r--java/src/test/java/com/google/protobuf/WireFormatTest.java402
-rw-r--r--java/src/test/java/com/google/protobuf/multiple_files_test.proto67
45 files changed, 21192 insertions, 0 deletions
diff --git a/java/README.txt b/java/README.txt
new file mode 100644
index 0000000..3ed06a1
--- /dev/null
+++ b/java/README.txt
@@ -0,0 +1,96 @@
+Protocol Buffers - Google's data interchange format
+Copyright 2008 Google Inc.
+
+This directory contains the Java Protocol Buffers runtime library.
+
+Installation - With Maven
+=========================
+
+The Protocol Buffers build is managed using Maven. If you would
+rather build without Maven, see below.
+
+1) Install Apache Maven if you don't have it:
+
+ http://maven.apache.org/
+
+2) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ You will need to place the protoc executable in ../src. (If you
+ built it yourself, it should already be there.)
+
+3) Run the tests:
+
+ $ mvn test
+
+ If some tests fail, this library may not work correctly on your
+ system. Continue at your own risk.
+
+4) Install the library into your Maven repository:
+
+ $ mvn install
+
+5) If you do not use Maven to manage your own build, you can build a
+ .jar file to use:
+
+ $ mvn package
+
+ The .jar will be placed in the "target" directory.
+
+Installation - 'Lite' Version - With Maven
+==========================================
+
+Building the 'lite' version of the Java Protocol Buffers library is
+the same as building the full version, except that all commands are
+run using the 'lite' profile. (see
+http://maven.apache.org/guides/introduction/introduction-to-profiles.html)
+
+E.g. to install the lite version of the jar, you would run:
+
+ $ mvn install -P lite
+
+The resulting artifact has the 'lite' classifier. To reference it
+for dependency resolution, you would specify it as:
+
+ <dependency>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>${version}</version>
+ <classifier>lite</classifier>
+ </dependency>
+
+Installation - Without Maven
+============================
+
+If you would rather not install Maven to build the library, you may
+follow these instructions instead. Note that these instructions skip
+running unit tests.
+
+1) Build the C++ code, or obtain a binary distribution of protoc. If
+ you install a binary distribution, make sure that it is the same
+ version as this package. If in doubt, run:
+
+ $ protoc --version
+
+ If you built the C++ code without installing, the compiler binary
+ should be located in ../src.
+
+2) Invoke protoc to build DescriptorProtos.java:
+
+ $ protoc --java_out=src/main/java -I../src \
+ ../src/google/protobuf/descriptor.proto
+
+3) Compile the code in src/main/java using whatever means you prefer.
+
+4) Install the classes wherever you prefer.
+
+Usage
+=====
+
+The complete documentation for Protocol Buffers is available via the
+web at:
+
+ http://code.google.com/apis/protocolbuffers/
diff --git a/java/pom.xml b/java/pom.xml
new file mode 100644
index 0000000..4a35a57
--- /dev/null
+++ b/java/pom.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google</groupId>
+ <artifactId>google</artifactId>
+ <version>1</version>
+ </parent>
+ <groupId>com.google.protobuf</groupId>
+ <artifactId>protobuf-java</artifactId>
+ <version>2.2.0</version>
+ <packaging>jar</packaging>
+ <name>Protocol Buffer Java API</name>
+ <description>
+ Protocol Buffers are a way of encoding structured data in an efficient yet
+ extensible format.
+ </description>
+ <inceptionYear>2008</inceptionYear>
+ <url>http://code.google.com/p/protobuf</url>
+ <licenses>
+ <license>
+ <name>New BSD license</name>
+ <url>http://www.opensource.org/licenses/bsd-license.php</url>
+ <distribution>repo</distribution>
+ </license>
+ </licenses>
+ <scm>
+ <url>http://code.google.com/p/protobuf/source/browse</url>
+ <connection>
+ scm:svn:http://protobuf.googlecode.com/svn/trunk/
+ </connection>
+ </scm>
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.2</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymockclassextension</artifactId>
+ <version>2.2.1</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/*Test.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-antrun-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-sources</id>
+ <phase>generate-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--java_out=target/generated-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="../src/google/protobuf/descriptor.proto" />
+ </exec>
+ </tasks>
+ <sourceRoot>target/generated-sources</sourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>generate-test-sources</id>
+ <phase>generate-test-sources</phase>
+ <configuration>
+ <tasks>
+ <mkdir dir="target/generated-test-sources" />
+ <exec executable="../src/protoc">
+ <arg value="--java_out=target/generated-test-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="--proto_path=src/test/java" />
+ <arg value="../src/google/protobuf/unittest.proto" />
+ <arg value="../src/google/protobuf/unittest_import.proto" />
+ <arg value="../src/google/protobuf/unittest_mset.proto" />
+ <arg
+ value="src/test/java/com/google/protobuf/multiple_files_test.proto" />
+ <arg
+ value="../src/google/protobuf/unittest_optimize_for.proto" />
+ <arg
+ value="../src/google/protobuf/unittest_custom_options.proto" />
+ <arg value="../src/google/protobuf/unittest_lite.proto" />
+ <arg value="../src/google/protobuf/unittest_import_lite.proto" />
+ <arg value="../src/google/protobuf/unittest_lite_imports_nonlite.proto" />
+ <arg value="../src/google/protobuf/unittest_enormous_descriptor.proto" />
+ </exec>
+ </tasks>
+ <testSourceRoot>target/generated-test-sources</testSourceRoot>
+ </configuration>
+ <goals>
+ <goal>run</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <profiles>
+ <profile>
+ <id>lite</id>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/AbstractMessageLite.java</include>
+ <include>**/ByteString.java</include>
+ <include>**/CodedInputStream.java</include>
+ <include>**/CodedOutputStream.java</include>
+ <include>**/ExtensionRegistryLite.java</include>
+ <include>**/FieldSet.java</include>
+ <include>**/GeneratedMessageLite.java</include>
+ <include>**/InvalidProtocolBufferException.java</include>
+ <include>**/Internal.java</include>
+ <include>**/MessageLite.java</include>
+ <include>**/UninitializedMessageException.java</include>
+ <include>**/WireFormat.java</include>
+ </includes>
+ <testIncludes>
+ <testInclude>**/LiteTest.java</testInclude>
+ <testInclude>**/*Lite.java</testInclude>
+ </testIncludes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <includes>
+ <include>**/LiteTest.java</include>
+ </includes>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <classifier>lite</classifier>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+</project>
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessage.java b/java/src/main/java/com/google/protobuf/AbstractMessage.java
new file mode 100644
index 0000000..e5bdefe
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/AbstractMessage.java
@@ -0,0 +1,690 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A partial implementation of the {@link Message} interface which implements
+ * as many methods of that interface as possible in terms of other methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessage extends AbstractMessageLite
+ implements Message {
+ @SuppressWarnings("unchecked")
+ public boolean isInitialized() {
+ // Check that all required fields are present.
+ for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+ if (field.isRequired()) {
+ if (!hasField(field)) {
+ return false;
+ }
+ }
+ }
+
+ // Check that embedded messages are initialized.
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ getAllFields().entrySet()) {
+ final FieldDescriptor field = entry.getKey();
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ for (final Message element : (List<Message>) entry.getValue()) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!((Message) entry.getValue()).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public final String toString() {
+ return TextFormat.printToString(this);
+ }
+
+ public void writeTo(final CodedOutputStream output) throws IOException {
+ final boolean isMessageSet =
+ getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ getAllFields().entrySet()) {
+ final FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+ if (isMessageSet && field.isExtension() &&
+ field.getType() == FieldDescriptor.Type.MESSAGE &&
+ !field.isRepeated()) {
+ output.writeMessageSetExtension(field.getNumber(), (Message) value);
+ } else {
+ FieldSet.writeField(field, value, output);
+ }
+ }
+
+ final UnknownFieldSet unknownFields = getUnknownFields();
+ if (isMessageSet) {
+ unknownFields.writeAsMessageSetTo(output);
+ } else {
+ unknownFields.writeTo(output);
+ }
+ }
+
+ private int memoizedSize = -1;
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) {
+ return size;
+ }
+
+ size = 0;
+ final boolean isMessageSet =
+ getDescriptorForType().getOptions().getMessageSetWireFormat();
+
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ getAllFields().entrySet()) {
+ final FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+ if (isMessageSet && field.isExtension() &&
+ field.getType() == FieldDescriptor.Type.MESSAGE &&
+ !field.isRepeated()) {
+ size += CodedOutputStream.computeMessageSetExtensionSize(
+ field.getNumber(), (Message) value);
+ } else {
+ size += FieldSet.computeFieldSize(field, value);
+ }
+ }
+
+ final UnknownFieldSet unknownFields = getUnknownFields();
+ if (isMessageSet) {
+ size += unknownFields.getSerializedSizeAsMessageSet();
+ } else {
+ size += unknownFields.getSerializedSize();
+ }
+
+ memoizedSize = size;
+ return size;
+ }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof Message)) {
+ return false;
+ }
+ final Message otherMessage = (Message) other;
+ if (getDescriptorForType() != otherMessage.getDescriptorForType()) {
+ return false;
+ }
+ return getAllFields().equals(otherMessage.getAllFields()) &&
+ getUnknownFields().equals(otherMessage.getUnknownFields());
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 41;
+ hash = (19 * hash) + getDescriptorForType().hashCode();
+ hash = (53 * hash) + getAllFields().hashCode();
+ hash = (29 * hash) + getUnknownFields().hashCode();
+ return hash;
+ }
+
+ // =================================================================
+
+ /**
+ * A partial implementation of the {@link Message.Builder} interface which
+ * implements as many methods of that interface as possible in terms of
+ * other methods.
+ */
+ @SuppressWarnings("unchecked")
+ public static abstract class Builder<BuilderType extends Builder>
+ extends AbstractMessageLite.Builder<BuilderType>
+ implements Message.Builder {
+ // The compiler produces an error if this is not declared explicitly.
+ @Override
+ public abstract BuilderType clone();
+
+ public BuilderType clear() {
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ getAllFields().entrySet()) {
+ clearField(entry.getKey());
+ }
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(final Message other) {
+ if (other.getDescriptorForType() != getDescriptorForType()) {
+ throw new IllegalArgumentException(
+ "mergeFrom(Message) can only merge messages of the same type.");
+ }
+
+ // Note: We don't attempt to verify that other's fields have valid
+ // types. Doing so would be a losing battle. We'd have to verify
+ // all sub-messages as well, and we'd have to make copies of all of
+ // them to insure that they don't change after verification (since
+ // the Message interface itself cannot enforce immutability of
+ // implementations).
+ // TODO(kenton): Provide a function somewhere called makeDeepCopy()
+ // which allows people to make secure deep copies of messages.
+
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ other.getAllFields().entrySet()) {
+ final FieldDescriptor field = entry.getKey();
+ if (field.isRepeated()) {
+ for (final Object element : (List)entry.getValue()) {
+ addRepeatedField(field, element);
+ }
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ final Message existingValue = (Message)getField(field);
+ if (existingValue == existingValue.getDefaultInstanceForType()) {
+ setField(field, entry.getValue());
+ } else {
+ setField(field,
+ existingValue.newBuilderForType()
+ .mergeFrom(existingValue)
+ .mergeFrom((Message)entry.getValue())
+ .build());
+ }
+ } else {
+ setField(field, entry.getValue());
+ }
+ }
+
+ mergeUnknownFields(other.getUnknownFields());
+
+ return (BuilderType) this;
+ }
+
+ @Override
+ public BuilderType mergeFrom(final CodedInputStream input)
+ throws IOException {
+ return mergeFrom(input, ExtensionRegistry.getEmptyRegistry());
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final CodedInputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ final UnknownFieldSet.Builder unknownFields =
+ UnknownFieldSet.newBuilder(getUnknownFields());
+ while (true) {
+ final int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (!mergeFieldFrom(input, unknownFields, extensionRegistry,
+ this, tag)) {
+ // end group tag
+ break;
+ }
+ }
+ setUnknownFields(unknownFields.build());
+ return (BuilderType) this;
+ }
+
+ /**
+ * Like {@link #mergeFrom(CodedInputStream, UnknownFieldSet.Builder,
+ * ExtensionRegistryLite, Message.Builder)}, but parses a single field.
+ * Package-private because it is used by GeneratedMessage.ExtendableMessage.
+ * @param tag The tag, which should have already been read.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ @SuppressWarnings("unchecked")
+ static boolean mergeFieldFrom(
+ final CodedInputStream input,
+ final UnknownFieldSet.Builder unknownFields,
+ final ExtensionRegistryLite extensionRegistry,
+ final Message.Builder builder,
+ final int tag) throws IOException {
+ final Descriptor type = builder.getDescriptorForType();
+
+ if (type.getOptions().getMessageSetWireFormat() &&
+ tag == WireFormat.MESSAGE_SET_ITEM_TAG) {
+ mergeMessageSetExtensionFromCodedStream(
+ input, unknownFields, extensionRegistry, builder);
+ return true;
+ }
+
+ final int wireType = WireFormat.getTagWireType(tag);
+ final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ final FieldDescriptor field;
+ Message defaultInstance = null;
+
+ if (type.isExtensionNumber(fieldNumber)) {
+ // extensionRegistry may be either ExtensionRegistry or
+ // ExtensionRegistryLite. Since the type we are parsing is a full
+ // message, only a full ExtensionRegistry could possibly contain
+ // extensions of it. Otherwise we will treat the registry as if it
+ // were empty.
+ if (extensionRegistry instanceof ExtensionRegistry) {
+ final ExtensionRegistry.ExtensionInfo extension =
+ ((ExtensionRegistry) extensionRegistry)
+ .findExtensionByNumber(type, fieldNumber);
+ if (extension == null) {
+ field = null;
+ } else {
+ field = extension.descriptor;
+ defaultInstance = extension.defaultInstance;
+ }
+ } else {
+ field = null;
+ }
+ } else {
+ field = type.findFieldByNumber(fieldNumber);
+ }
+
+ if (field == null || wireType !=
+ FieldSet.getWireFormatForFieldType(
+ field.getLiteType(),
+ field.getOptions().getPacked())) {
+ // Unknown field or wrong wire type. Skip.
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+
+ if (field.getOptions().getPacked()) {
+ final int length = input.readRawVarint32();
+ final int limit = input.pushLimit(length);
+ if (field.getLiteType() == WireFormat.FieldType.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ final int rawValue = input.readEnum();
+ final Object value = field.getEnumType().findValueByNumber(rawValue);
+ if (value == null) {
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
+ return true;
+ }
+ builder.addRepeatedField(field, value);
+ }
+ } else {
+ while (input.getBytesUntilLimit() > 0) {
+ final Object value =
+ FieldSet.readPrimitiveField(input, field.getLiteType());
+ builder.addRepeatedField(field, value);
+ }
+ }
+ input.popLimit(limit);
+ } else {
+ final Object value;
+ switch (field.getType()) {
+ case GROUP: {
+ final Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readGroup(field.getNumber(), subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
+ }
+ case MESSAGE: {
+ final Message.Builder subBuilder;
+ if (defaultInstance != null) {
+ subBuilder = defaultInstance.newBuilderForType();
+ } else {
+ subBuilder = builder.newBuilderForField(field);
+ }
+ if (!field.isRepeated()) {
+ subBuilder.mergeFrom((Message) builder.getField(field));
+ }
+ input.readMessage(subBuilder, extensionRegistry);
+ value = subBuilder.build();
+ break;
+ }
+ case ENUM:
+ final int rawValue = input.readEnum();
+ value = field.getEnumType().findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ unknownFields.mergeVarintField(fieldNumber, rawValue);
+ return true;
+ }
+ break;
+ default:
+ value = FieldSet.readPrimitiveField(input, field.getLiteType());
+ break;
+ }
+
+ if (field.isRepeated()) {
+ builder.addRepeatedField(field, value);
+ } else {
+ builder.setField(field, value);
+ }
+ }
+
+ return true;
+ }
+
+ /** Called by {@code #mergeFieldFrom()} to parse a MessageSet extension. */
+ private static void mergeMessageSetExtensionFromCodedStream(
+ final CodedInputStream input,
+ final UnknownFieldSet.Builder unknownFields,
+ final ExtensionRegistryLite extensionRegistry,
+ final Message.Builder builder) throws IOException {
+ final Descriptor type = builder.getDescriptorForType();
+
+ // The wire format for MessageSet is:
+ // message MessageSet {
+ // repeated group Item = 1 {
+ // required int32 typeId = 2;
+ // required bytes message = 3;
+ // }
+ // }
+ // "typeId" is the extension's field number. The extension can only be
+ // a message type, where "message" contains the encoded bytes of that
+ // message.
+ //
+ // In practice, we will probably never see a MessageSet item in which
+ // the message appears before the type ID, or where either field does not
+ // appear exactly once. However, in theory such cases are valid, so we
+ // should be prepared to accept them.
+
+ int typeId = 0;
+ ByteString rawBytes = null; // If we encounter "message" before "typeId"
+ Message.Builder subBuilder = null;
+ FieldDescriptor field = null;
+
+ while (true) {
+ final int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ if (tag == WireFormat.MESSAGE_SET_TYPE_ID_TAG) {
+ typeId = input.readUInt32();
+ // Zero is not a valid type ID.
+ if (typeId != 0) {
+ final ExtensionRegistry.ExtensionInfo extension;
+
+ // extensionRegistry may be either ExtensionRegistry or
+ // ExtensionRegistryLite. Since the type we are parsing is a full
+ // message, only a full ExtensionRegistry could possibly contain
+ // extensions of it. Otherwise we will treat the registry as if it
+ // were empty.
+ if (extensionRegistry instanceof ExtensionRegistry) {
+ extension = ((ExtensionRegistry) extensionRegistry)
+ .findExtensionByNumber(type, typeId);
+ } else {
+ extension = null;
+ }
+
+ if (extension != null) {
+ field = extension.descriptor;
+ subBuilder = extension.defaultInstance.newBuilderForType();
+ final Message originalMessage = (Message)builder.getField(field);
+ if (originalMessage != null) {
+ subBuilder.mergeFrom(originalMessage);
+ }
+ if (rawBytes != null) {
+ // We already encountered the message. Parse it now.
+ subBuilder.mergeFrom(
+ CodedInputStream.newInstance(rawBytes.newInput()));
+ rawBytes = null;
+ }
+ } else {
+ // Unknown extension number. If we already saw data, put it
+ // in rawBytes.
+ if (rawBytes != null) {
+ unknownFields.mergeField(typeId,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(rawBytes)
+ .build());
+ rawBytes = null;
+ }
+ }
+ }
+ } else if (tag == WireFormat.MESSAGE_SET_MESSAGE_TAG) {
+ if (typeId == 0) {
+ // We haven't seen a type ID yet, so we have to store the raw bytes
+ // for now.
+ rawBytes = input.readBytes();
+ } else if (subBuilder == null) {
+ // We don't know how to parse this. Ignore it.
+ unknownFields.mergeField(typeId,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(input.readBytes())
+ .build());
+ } else {
+ // We already know the type, so we can parse directly from the input
+ // with no copying. Hooray!
+ input.readMessage(subBuilder, extensionRegistry);
+ }
+ } else {
+ // Unknown tag. Skip it.
+ if (!input.skipField(tag)) {
+ break; // end of group
+ }
+ }
+ }
+
+ input.checkLastTagWas(WireFormat.MESSAGE_SET_ITEM_END_TAG);
+
+ if (subBuilder != null) {
+ builder.setField(field, subBuilder.build());
+ }
+ }
+
+ public BuilderType mergeUnknownFields(final UnknownFieldSet unknownFields) {
+ setUnknownFields(
+ UnknownFieldSet.newBuilder(getUnknownFields())
+ .mergeFrom(unknownFields)
+ .build());
+ return (BuilderType) this;
+ }
+
+ /**
+ * Construct an UninitializedMessageException reporting missing fields in
+ * the given message.
+ */
+ protected static UninitializedMessageException
+ newUninitializedMessageException(Message message) {
+ return new UninitializedMessageException(findMissingFields(message));
+ }
+
+ /**
+ * Populates {@code this.missingFields} with the full "path" of each
+ * missing required field in the given message.
+ */
+ private static List<String> findMissingFields(final Message message) {
+ final List<String> results = new ArrayList<String>();
+ findMissingFields(message, "", results);
+ return results;
+ }
+
+ /** Recursive helper implementing {@link #findMissingFields(Message)}. */
+ private static void findMissingFields(final Message message,
+ final String prefix,
+ final List<String> results) {
+ for (final FieldDescriptor field :
+ message.getDescriptorForType().getFields()) {
+ if (field.isRequired() && !message.hasField(field)) {
+ results.add(prefix + field.getName());
+ }
+ }
+
+ for (final Map.Entry<FieldDescriptor, Object> entry :
+ message.getAllFields().entrySet()) {
+ final FieldDescriptor field = entry.getKey();
+ final Object value = entry.getValue();
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ int i = 0;
+ for (final Object element : (List) value) {
+ findMissingFields((Message) element,
+ subMessagePrefix(prefix, field, i++),
+ results);
+ }
+ } else {
+ if (message.hasField(field)) {
+ findMissingFields((Message) value,
+ subMessagePrefix(prefix, field, -1),
+ results);
+ }
+ }
+ }
+ }
+ }
+
+ private static String subMessagePrefix(final String prefix,
+ final FieldDescriptor field,
+ final int index) {
+ final StringBuilder result = new StringBuilder(prefix);
+ if (field.isExtension()) {
+ result.append('(')
+ .append(field.getFullName())
+ .append(')');
+ } else {
+ result.append(field.getName());
+ }
+ if (index != -1) {
+ result.append('[')
+ .append(index)
+ .append(']');
+ }
+ result.append('.');
+ return result.toString();
+ }
+
+ // ===============================================================
+ // The following definitions seem to be required in order to make javac
+ // not produce weird errors like:
+ //
+ // java/com/google/protobuf/DynamicMessage.java:203: types
+ // com.google.protobuf.AbstractMessage.Builder<
+ // com.google.protobuf.DynamicMessage.Builder> and
+ // com.google.protobuf.AbstractMessage.Builder<
+ // com.google.protobuf.DynamicMessage.Builder> are incompatible; both
+ // define mergeFrom(com.google.protobuf.ByteString), but with unrelated
+ // return types.
+ //
+ // Strangely, these lines are only needed if javac is invoked separately
+ // on AbstractMessage.java and AbstractMessageLite.java. If javac is
+ // invoked on both simultaneously, it works. (Or maybe the important
+ // point is whether or not DynamicMessage.java is compiled together with
+ // AbstractMessageLite.java -- not sure.) I suspect this is a compiler
+ // bug.
+
+ @Override
+ public BuilderType mergeFrom(final ByteString data)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data);
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final ByteString data,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data, extensionRegistry);
+ }
+
+ @Override
+ public BuilderType mergeFrom(final byte[] data)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data);
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final byte[] data, final int off, final int len)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data, off, len);
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final byte[] data,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data, extensionRegistry);
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final byte[] data, final int off, final int len,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return super.mergeFrom(data, off, len, extensionRegistry);
+ }
+
+ @Override
+ public BuilderType mergeFrom(final InputStream input)
+ throws IOException {
+ return super.mergeFrom(input);
+ }
+
+ @Override
+ public BuilderType mergeFrom(
+ final InputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ return super.mergeFrom(input, extensionRegistry);
+ }
+
+ @Override
+ public BuilderType mergeDelimitedFrom(final InputStream input)
+ throws IOException {
+ return super.mergeDelimitedFrom(input);
+ }
+
+ @Override
+ public BuilderType mergeDelimitedFrom(
+ final InputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ return super.mergeDelimitedFrom(input, extensionRegistry);
+ }
+
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/AbstractMessageLite.java b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
new file mode 100644
index 0000000..489577d
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/AbstractMessageLite.java
@@ -0,0 +1,321 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collection;
+
+/**
+ * A partial implementation of the {@link MessageLite} interface which
+ * implements as many methods of that interface as possible in terms of other
+ * methods.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class AbstractMessageLite implements MessageLite {
+ public ByteString toByteString() {
+ try {
+ final ByteString.CodedBuilder out =
+ ByteString.newCodedBuilder(getSerializedSize());
+ writeTo(out.getCodedOutput());
+ return out.build();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public byte[] toByteArray() {
+ try {
+ final byte[] result = new byte[getSerializedSize()];
+ final CodedOutputStream output = CodedOutputStream.newInstance(result);
+ writeTo(output);
+ output.checkNoSpaceLeft();
+ return result;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Serializing to a byte array threw an IOException " +
+ "(should never happen).", e);
+ }
+ }
+
+ public void writeTo(final OutputStream output) throws IOException {
+ final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ public void writeDelimitedTo(final OutputStream output) throws IOException {
+ final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ codedOutput.writeRawVarint32(getSerializedSize());
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ /**
+ * A partial implementation of the {@link Message.Builder} interface which
+ * implements as many methods of that interface as possible in terms of
+ * other methods.
+ */
+ @SuppressWarnings("unchecked")
+ public static abstract class Builder<BuilderType extends Builder>
+ implements MessageLite.Builder {
+ // The compiler produces an error if this is not declared explicitly.
+ @Override
+ public abstract BuilderType clone();
+
+ public BuilderType mergeFrom(final CodedInputStream input)
+ throws IOException {
+ // TODO(kenton): Don't use null here. Currently we have to because
+ // using ExtensionRegistry.getEmptyRegistry() would imply a dependency
+ // on ExtensionRegistry. However, AbstractMessage overrides this with
+ // a correct implementation, and lite messages don't yet support
+ // extensions, so it ends up not mattering for now. It will matter
+ // once lite messages support extensions.
+ return mergeFrom(input, null);
+ }
+
+ // Re-defined here for return type covariance.
+ public abstract BuilderType mergeFrom(
+ final CodedInputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+
+ public BuilderType mergeFrom(final ByteString data)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input = data.newCodedInput();
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(
+ final ByteString data,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input = data.newCodedInput();
+ mergeFrom(input, extensionRegistry);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(final byte[] data)
+ throws InvalidProtocolBufferException {
+ return mergeFrom(data, 0, data.length);
+ }
+
+ public BuilderType mergeFrom(final byte[] data, final int off,
+ final int len)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input =
+ CodedInputStream.newInstance(data, off, len);
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(
+ final byte[] data,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return mergeFrom(data, 0, data.length, extensionRegistry);
+ }
+
+ public BuilderType mergeFrom(
+ final byte[] data, final int off, final int len,
+ final ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input =
+ CodedInputStream.newInstance(data, off, len);
+ mergeFrom(input, extensionRegistry);
+ input.checkLastTagWas(0);
+ return (BuilderType) this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public BuilderType mergeFrom(final InputStream input) throws IOException {
+ final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput);
+ codedInput.checkLastTagWas(0);
+ return (BuilderType) this;
+ }
+
+ public BuilderType mergeFrom(
+ final InputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput, extensionRegistry);
+ codedInput.checkLastTagWas(0);
+ return (BuilderType) this;
+ }
+
+ /**
+ * An InputStream implementations which reads from some other InputStream
+ * but is limited to a particular number of bytes. Used by
+ * mergeDelimitedFrom(). This is intentionally package-private so that
+ * UnknownFieldSet can share it.
+ */
+ static final class LimitedInputStream extends FilterInputStream {
+ private int limit;
+
+ LimitedInputStream(InputStream in, int limit) {
+ super(in);
+ this.limit = limit;
+ }
+
+ @Override
+ public int available() throws IOException {
+ return Math.min(super.available(), limit);
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (limit <= 0) {
+ return -1;
+ }
+ final int result = super.read();
+ if (result >= 0) {
+ --limit;
+ }
+ return result;
+ }
+
+ @Override
+ public int read(final byte[] b, final int off, int len)
+ throws IOException {
+ if (limit <= 0) {
+ return -1;
+ }
+ len = Math.min(len, limit);
+ final int result = super.read(b, off, len);
+ if (result >= 0) {
+ limit -= result;
+ }
+ return result;
+ }
+
+ @Override
+ public long skip(final long n) throws IOException {
+ final long result = super.skip(Math.min(n, limit));
+ if (result >= 0) {
+ limit -= result;
+ }
+ return result;
+ }
+ }
+
+ public BuilderType mergeDelimitedFrom(
+ final InputStream input,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ final int size = CodedInputStream.readRawVarint32(input);
+ final InputStream limitedInput = new LimitedInputStream(input, size);
+ return mergeFrom(limitedInput, extensionRegistry);
+ }
+
+ public BuilderType mergeDelimitedFrom(final InputStream input)
+ throws IOException {
+ final int size = CodedInputStream.readRawVarint32(input);
+ final InputStream limitedInput = new LimitedInputStream(input, size);
+ return mergeFrom(limitedInput);
+ }
+
+ /**
+ * Construct an UninitializedMessageException reporting missing fields in
+ * the given message.
+ */
+ protected static UninitializedMessageException
+ newUninitializedMessageException(MessageLite message) {
+ return new UninitializedMessageException(message);
+ }
+
+ /**
+ * Adds the {@code values} to the {@code list}. This is a helper method
+ * used by generated code. Users should ignore it.
+ *
+ * @throws NullPointerException if any of the elements of {@code values} is
+ * null.
+ */
+ protected static <T> void addAll(final Iterable<T> values,
+ final Collection<? super T> list) {
+ for (final T value : values) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ }
+ if (values instanceof Collection) {
+ @SuppressWarnings("unsafe") final
+ Collection<T> collection = (Collection<T>) values;
+ list.addAll(collection);
+ } else {
+ for (final T value : values) {
+ list.add(value);
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
new file mode 100644
index 0000000..1e81143
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/BlockingRpcChannel.java
@@ -0,0 +1,51 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+/**
+ * <p>Abstract interface for a blocking RPC channel. {@code BlockingRpcChannel}
+ * is the blocking equivalent to {@link RpcChannel}.
+ *
+ * @author kenton@google.com Kenton Varda
+ * @author cpovirk@google.com Chris Povirk
+ */
+public interface BlockingRpcChannel {
+ /**
+ * Call the given method of the remote service and blocks until it returns.
+ * {@code callBlockingMethod()} is the blocking equivalent to
+ * {@link RpcChannel#callMethod}.
+ */
+ Message callBlockingMethod(
+ Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request,
+ Message responsePrototype) throws ServiceException;
+}
diff --git a/java/src/main/java/com/google/protobuf/BlockingService.java b/java/src/main/java/com/google/protobuf/BlockingService.java
new file mode 100644
index 0000000..ecc8009
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/BlockingService.java
@@ -0,0 +1,64 @@
+// 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;
+
+/**
+ * Blocking equivalent to {@link Service}.
+ *
+ * @author kenton@google.com Kenton Varda
+ * @author cpovirk@google.com Chris Povirk
+ */
+public interface BlockingService {
+ /**
+ * Equivalent to {@link Service#getDescriptorForType}.
+ */
+ Descriptors.ServiceDescriptor getDescriptorForType();
+
+ /**
+ * Equivalent to {@link Service#callMethod}, except that
+ * {@code callBlockingMethod()} returns the result of the RPC or throws a
+ * {@link ServiceException} if there is a failure, rather than passing the
+ * information to a callback.
+ */
+ Message callBlockingMethod(Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request) throws ServiceException;
+
+ /**
+ * Equivalent to {@link Service#getRequestPrototype}.
+ */
+ Message getRequestPrototype(Descriptors.MethodDescriptor method);
+
+ /**
+ * Equivalent to {@link Service#getResponsePrototype}.
+ */
+ Message getResponsePrototype(Descriptors.MethodDescriptor method);
+}
diff --git a/java/src/main/java/com/google/protobuf/ByteString.java b/java/src/main/java/com/google/protobuf/ByteString.java
new file mode 100644
index 0000000..c83c335
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ByteString.java
@@ -0,0 +1,344 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.InputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FilterOutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+
+/**
+ * Immutable array of bytes.
+ *
+ * @author crazybob@google.com Bob Lee
+ * @author kenton@google.com Kenton Varda
+ */
+public final class ByteString {
+ private final byte[] bytes;
+
+ private ByteString(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[] -> ByteString
+
+ /**
+ * Empty ByteString.
+ */
+ public static final ByteString EMPTY = new ByteString(new byte[0]);
+
+ /**
+ * Copies the given bytes into a {@code ByteString}.
+ */
+ public static ByteString 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 ByteString(copy);
+ }
+
+ /**
+ * Copies the given bytes into a {@code ByteString}.
+ */
+ public static ByteString 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 ByteString}.
+ */
+ public static ByteString copyFrom(final String text, final String charsetName)
+ throws UnsupportedEncodingException {
+ return new ByteString(text.getBytes(charsetName));
+ }
+
+ /**
+ * Encodes {@code text} into a sequence of UTF-8 bytes and returns the
+ * result as a {@code ByteString}.
+ */
+ public static ByteString copyFromUtf8(final String text) {
+ try {
+ return new ByteString(text.getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported?", e);
+ }
+ }
+
+ // =================================================================
+ // ByteString -> 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 read-only {@code java.nio.ByteBuffer} with the
+ * same backing byte array.
+ */
+ public ByteBuffer asReadOnlyByteBuffer() {
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
+ return byteBuffer.asReadOnlyBuffer();
+ }
+
+ /**
+ * 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?", e);
+ }
+ }
+
+ // =================================================================
+ // equals() and hashCode()
+
+ @Override
+ public boolean equals(final Object o) {
+ if (o == this) {
+ return true;
+ }
+
+ if (!(o instanceof ByteString)) {
+ return false;
+ }
+
+ final ByteString other = (ByteString) 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
+ 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;
+ }
+
+ // =================================================================
+ // Input stream
+
+ /**
+ * Creates an {@code InputStream} which can be used to read the bytes.
+ */
+ public InputStream newInput() {
+ return new ByteArrayInputStream(bytes);
+ }
+
+ /**
+ * Creates a {@link CodedInputStream} which can be used to read the bytes.
+ * Using this is more efficient than creating a {@link CodedInputStream}
+ * wrapping the result of {@link #newInput()}.
+ */
+ public CodedInputStream newCodedInput() {
+ // We trust CodedInputStream not to modify the bytes, or to give anyone
+ // else access to them.
+ return CodedInputStream.newInstance(bytes);
+ }
+
+ // =================================================================
+ // Output stream
+
+ /**
+ * Creates a new {@link Output} with the given initial capacity.
+ */
+ public static Output newOutput(final int initialCapacity) {
+ return new Output(new ByteArrayOutputStream(initialCapacity));
+ }
+
+ /**
+ * Creates a new {@link Output}.
+ */
+ public static Output newOutput() {
+ return newOutput(32);
+ }
+
+ /**
+ * Outputs to a {@code ByteString} instance. Call {@link #toByteString()} to
+ * create the {@code ByteString} instance.
+ */
+ public static final class Output extends FilterOutputStream {
+ private final ByteArrayOutputStream bout;
+
+ /**
+ * Constructs a new output with the given initial capacity.
+ */
+ private Output(final ByteArrayOutputStream bout) {
+ super(bout);
+ this.bout = bout;
+ }
+
+ /**
+ * Creates a {@code ByteString} instance from this {@code Output}.
+ */
+ public ByteString toByteString() {
+ final byte[] byteArray = bout.toByteArray();
+ return new ByteString(byteArray);
+ }
+ }
+
+ /**
+ * Constructs a new ByteString builder, which allows you to efficiently
+ * construct a {@code ByteString} by writing to a {@link CodedOutputStream}.
+ * Using this is much more efficient than calling {@code newOutput()} and
+ * wrapping that in a {@code CodedOutputStream}.
+ *
+ * <p>This is package-private because it's a somewhat confusing interface.
+ * Users can call {@link Message#toByteString()} instead of calling this
+ * directly.
+ *
+ * @param size The target byte size of the {@code ByteString}. You must
+ * write exactly this many bytes before building the result.
+ */
+ static CodedBuilder newCodedBuilder(final int size) {
+ return new CodedBuilder(size);
+ }
+
+ /** See {@link ByteString#newCodedBuilder(int)}. */
+ static final class CodedBuilder {
+ private final CodedOutputStream output;
+ private final byte[] buffer;
+
+ private CodedBuilder(final int size) {
+ buffer = new byte[size];
+ output = CodedOutputStream.newInstance(buffer);
+ }
+
+ public ByteString build() {
+ output.checkNoSpaceLeft();
+
+ // We can be confident that the CodedOutputStream will not modify the
+ // underlying bytes anymore because it already wrote all of them. So,
+ // no need to make a copy.
+ return new ByteString(buffer);
+ }
+
+ public CodedOutputStream getCodedOutput() {
+ return output;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/CodedInputStream.java b/java/src/main/java/com/google/protobuf/CodedInputStream.java
new file mode 100644
index 0000000..9125957
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -0,0 +1,826 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 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 CodedInputStream {
+ /**
+ * Create a new CodedInputStream wrapping the given InputStream.
+ */
+ public static CodedInputStream newInstance(final InputStream input) {
+ return new CodedInputStream(input);
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping the given byte array.
+ */
+ public static CodedInputStream newInstance(final byte[] buf) {
+ return newInstance(buf, 0, buf.length);
+ }
+
+ /**
+ * Create a new CodedInputStream wrapping the given byte array slice.
+ */
+ public static CodedInputStream newInstance(final byte[] buf, final int off,
+ final int len) {
+ return new CodedInputStream(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 InvalidProtocolBufferException.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 InvalidProtocolBufferException {@code value} does not match the
+ * last tag.
+ */
+ public void checkLastTagWas(final int value)
+ throws InvalidProtocolBufferException {
+ if (lastTag != value) {
+ throw InvalidProtocolBufferException.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 (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ readInt32();
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ readRawLittleEndian64();
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ skipRawBytes(readRawVarint32());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ skipMessage();
+ checkLastTagWas(
+ WireFormat.makeTag(WireFormat.getTagFieldNumber(tag),
+ WireFormat.WIRETYPE_END_GROUP));
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ readRawLittleEndian32();
+ return true;
+ default:
+ throw InvalidProtocolBufferException.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 int fieldNumber,
+ final MessageLite.Builder builder,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(
+ WireFormat.makeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP));
+ --recursionDepth;
+ }
+
+ /**
+ * Reads a {@code group} field value from the stream and merges it into the
+ * given {@link UnknownFieldSet}.
+ *
+ * @deprecated UnknownFieldSet.Builder now implements MessageLite.Builder, so
+ * you can just call {@link #readGroup}.
+ */
+ @Deprecated
+ public void readUnknownGroup(final int fieldNumber,
+ final MessageLite.Builder builder)
+ throws IOException {
+ // We know that UnknownFieldSet will ignore any ExtensionRegistry so it
+ // is safe to pass null here. (We can't call
+ // ExtensionRegistry.getEmptyRegistry() because that would make this
+ // class depend on ExtensionRegistry, which is not part of the lite
+ // library.)
+ readGroup(fieldNumber, builder, null);
+ }
+
+ /** Read an embedded message field value from the stream. */
+ public void readMessage(final MessageLite.Builder builder,
+ final ExtensionRegistryLite extensionRegistry)
+ throws IOException {
+ final int length = readRawVarint32();
+ if (recursionDepth >= recursionLimit) {
+ throw InvalidProtocolBufferException.recursionLimitExceeded();
+ }
+ final int oldLimit = pushLimit(length);
+ ++recursionDepth;
+ builder.mergeFrom(this, extensionRegistry);
+ checkLastTagWas(0);
+ --recursionDepth;
+ popLimit(oldLimit);
+ }
+
+ /** Read a {@code bytes} field value from the stream. */
+ public ByteString 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 ByteString result = ByteString.copyFrom(buffer, bufferPos, size);
+ bufferPos += size;
+ return result;
+ } else {
+ // Slow path: Build a byte array first then copy it.
+ return ByteString.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 InvalidProtocolBufferException.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 InvalidProtocolBufferException.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 InvalidProtocolBufferException.truncatedMessage();
+ }
+ if ((b & 0x80) == 0) {
+ return result;
+ }
+ }
+ throw InvalidProtocolBufferException.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 InvalidProtocolBufferException.malformedVarint();
+ }
+
+ /** Read a 32-bit little-endian integer from the stream. */
+ public int readRawLittleEndian32() throws IOException {
+ final byte b1 = readRawByte();
+ final byte b2 = readRawByte();
+ final byte b3 = readRawByte();
+ final byte b4 = readRawByte();
+ return (((int)b1 & 0xff) ) |
+ (((int)b2 & 0xff) << 8) |
+ (((int)b3 & 0xff) << 16) |
+ (((int)b4 & 0xff) << 24);
+ }
+
+ /** 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 CodedInputStream(final byte[] buffer, final int off, final int len) {
+ this.buffer = buffer;
+ bufferSize = off + len;
+ bufferPos = off;
+ input = null;
+ }
+
+ private CodedInputStream(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 ByteString#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 InvalidProtocolBufferException {
+ if (byteLimit < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+ byteLimit += totalBytesRetired + bufferPos;
+ final int oldLimit = currentLimit;
+ if (byteLimit > oldLimit) {
+ throw InvalidProtocolBufferException.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 InvalidProtocolBufferException.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 InvalidProtocolBufferException.truncatedMessage();
+ } else {
+ return false;
+ }
+ } else {
+ recomputeBufferSizeAfterLimit();
+ final int totalBytesRead =
+ totalBytesRetired + bufferSize + bufferSizeAfterLimit;
+ if (totalBytesRead > sizeLimit || totalBytesRead < 0) {
+ throw InvalidProtocolBufferException.sizeLimitExceeded();
+ }
+ return true;
+ }
+ }
+
+ /**
+ * Read one byte from the input.
+ *
+ * @throws InvalidProtocolBufferException 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 InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ public byte[] readRawBytes(final int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+
+ if (totalBytesRetired + bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ if (size <= bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ final byte[] bytes = new byte[size];
+ System.arraycopy(buffer, bufferPos, bytes, 0, size);
+ bufferPos += size;
+ return bytes;
+ } else if (size < BUFFER_SIZE) {
+ // 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);
+ final List<byte[]> chunks = new ArrayList<byte[]>();
+
+ 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 InvalidProtocolBufferException.truncatedMessage();
+ }
+ totalBytesRetired += n;
+ pos += n;
+ }
+ sizeLeft -= chunk.length;
+ chunks.add(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 (final byte[] chunk : chunks) {
+ System.arraycopy(chunk, 0, bytes, pos, chunk.length);
+ pos += chunk.length;
+ }
+
+ // Done.
+ return bytes;
+ }
+ }
+
+ /**
+ * Reads and discards {@code size} bytes.
+ *
+ * @throws InvalidProtocolBufferException The end of the stream or the current
+ * limit was reached.
+ */
+ public void skipRawBytes(final int size) throws IOException {
+ if (size < 0) {
+ throw InvalidProtocolBufferException.negativeSize();
+ }
+
+ if (totalBytesRetired + bufferPos + size > currentLimit) {
+ // Read to the end of the stream anyway.
+ skipRawBytes(currentLimit - totalBytesRetired - bufferPos);
+ // Then fail.
+ throw InvalidProtocolBufferException.truncatedMessage();
+ }
+
+ if (size <= bufferSize - bufferPos) {
+ // We have all the bytes we need already.
+ bufferPos += size;
+ } else {
+ // Skipping more bytes than are in the buffer. First skip what we have.
+ int pos = bufferSize - bufferPos;
+ 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 InvalidProtocolBufferException.truncatedMessage();
+ }
+ pos += n;
+ totalBytesRetired += n;
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/CodedOutputStream.java b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
new file mode 100644
index 0000000..d3907a7
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/CodedOutputStream.java
@@ -0,0 +1,1017 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.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 CodedOutputStream {
+ 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 CodedOutputStream(final byte[] buffer, final int offset,
+ final int length) {
+ output = null;
+ this.buffer = buffer;
+ position = offset;
+ limit = offset + length;
+ }
+
+ private CodedOutputStream(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 CodedOutputStream 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 CodedOutputStream newInstance(final OutputStream output,
+ final int bufferSize) {
+ return new CodedOutputStream(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}. See also
+ * {@link ByteString#newCodedBuilder}.
+ */
+ public static CodedOutputStream 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}. See also
+ * {@link ByteString#newCodedBuilder}.
+ */
+ public static CodedOutputStream newInstance(final byte[] flatArray,
+ final int offset,
+ final int length) {
+ return new CodedOutputStream(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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeStringNoTag(value);
+ }
+
+ /** Write a {@code group} field, including tag, to the stream. */
+ public void writeGroup(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_START_GROUP);
+ writeGroupNoTag(value);
+ writeTag(fieldNumber, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ /**
+ * Write a group represented by an {@link UnknownFieldSet}.
+ *
+ * @deprecated UnknownFieldSet now implements MessageLite, so you can just
+ * call {@link #writeGroup}.
+ */
+ @Deprecated
+ public void writeUnknownGroup(final int fieldNumber,
+ final MessageLite value)
+ throws IOException {
+ writeGroup(fieldNumber, value);
+ }
+
+ /** Write an embedded message field, including tag, to the stream. */
+ public void writeMessage(final int fieldNumber, final MessageLite value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ writeMessageNoTag(value);
+ }
+
+ /** Write a {@code bytes} field, including tag, to the stream. */
+ public void writeBytes(final int fieldNumber, final ByteString value)
+ throws IOException {
+ writeTag(fieldNumber, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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, WireFormat.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 MessageLite value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeMessage(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.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 ByteString value)
+ throws IOException {
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_START_GROUP);
+ writeUInt32(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber);
+ writeBytes(WireFormat.MESSAGE_SET_MESSAGE, value);
+ writeTag(WireFormat.MESSAGE_SET_ITEM, WireFormat.WIRETYPE_END_GROUP);
+ }
+
+ // -----------------------------------------------------------------
+
+ /** Write a {@code double} field to the stream. */
+ public void writeDoubleNoTag(final double value) throws IOException {
+ writeRawLittleEndian64(Double.doubleToRawLongBits(value));
+ }
+
+ /** Write a {@code float} field to the stream. */
+ public void writeFloatNoTag(final float value) throws IOException {
+ writeRawLittleEndian32(Float.floatToRawIntBits(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 group} field to the stream. */
+ public void writeGroupNoTag(final MessageLite value) throws IOException {
+ value.writeTo(this);
+ }
+
+ /**
+ * Write a group represented by an {@link UnknownFieldSet}.
+ *
+ * @deprecated UnknownFieldSet now implements MessageLite, so you can just
+ * call {@link #writeGroupNoTag}.
+ */
+ @Deprecated
+ public void writeUnknownGroupNoTag(final MessageLite value)
+ throws IOException {
+ writeGroupNoTag(value);
+ }
+
+ /** Write an embedded message field to the stream. */
+ public void writeMessageNoTag(final MessageLite value) throws IOException {
+ writeRawVarint32(value.getSerializedSize());
+ value.writeTo(this);
+ }
+
+ /** Write a {@code bytes} field to the stream. */
+ public void writeBytesNoTag(final ByteString 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 group} field, including tag.
+ */
+ public static int computeGroupSize(final int fieldNumber,
+ final MessageLite value) {
+ return computeTagSize(fieldNumber) * 2 + computeGroupSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field represented by an {@code UnknownFieldSet}, including
+ * tag.
+ *
+ * @deprecated UnknownFieldSet now implements MessageLite, so you can just
+ * call {@link #computeGroupSize}.
+ */
+ @Deprecated
+ public static int computeUnknownGroupSize(final int fieldNumber,
+ final MessageLite value) {
+ return computeGroupSize(fieldNumber, 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 MessageLite 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 ByteString 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 MessageLite value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
+ computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
+ computeMessageSize(WireFormat.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 ByteString value) {
+ return computeTagSize(WireFormat.MESSAGE_SET_ITEM) * 2 +
+ computeUInt32Size(WireFormat.MESSAGE_SET_TYPE_ID, fieldNumber) +
+ computeBytesSize(WireFormat.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.", e);
+ }
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field.
+ */
+ public static int computeGroupSizeNoTag(final MessageLite value) {
+ return value.getSerializedSize();
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code group} field represented by an {@code UnknownFieldSet}, including
+ * tag.
+ *
+ * @deprecated UnknownFieldSet now implements MessageLite, so you can just
+ * call {@link #computeUnknownGroupSizeNoTag}.
+ */
+ @Deprecated
+ public static int computeUnknownGroupSizeNoTag(final MessageLite value) {
+ return computeGroupSizeNoTag(value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode an embedded
+ * message field.
+ */
+ public static int computeMessageSizeNoTag(final MessageLite value) {
+ final int size = value.getSerializedSize();
+ return computeRawVarint32Size(size) + size;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * {@code bytes} field.
+ */
+ public static int computeBytesSizeNoTag(final ByteString 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(WireFormat.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(WireFormat.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/Descriptors.java b/java/src/main/java/com/google/protobuf/Descriptors.java
new file mode 100644
index 0000000..0c162d5
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Descriptors.java
@@ -0,0 +1,1871 @@
+// 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.DescriptorProtos.*;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.io.UnsupportedEncodingException;
+
+/**
+ * Contains a collection of classes which describe protocol message types.
+ *
+ * Every message type has a {@link Descriptor}, which lists all
+ * its fields and other information about a type. You can get a message
+ * type's descriptor by calling {@code MessageType.getDescriptor()}, or
+ * (given a message object of the type) {@code message.getDescriptorForType()}.
+ *
+ * Descriptors are built from DescriptorProtos, as defined in
+ * {@code net/proto2/proto/descriptor.proto}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class Descriptors {
+ /**
+ * Describes a {@code .proto} file, including everything defined within.
+ */
+ public static final class FileDescriptor {
+ /** Convert the descriptor to its protocol message representation. */
+ public FileDescriptorProto toProto() { return proto; }
+
+ /** Get the file name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the proto package name. This is the package name given by the
+ * {@code package} statement in the {@code .proto} file, which differs
+ * from the Java package.
+ */
+ public String getPackage() { return proto.getPackage(); }
+
+ /** Get the {@code FileOptions}, defined in {@code descriptor.proto}. */
+ public FileOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of top-level message types declared in this file. */
+ public List<Descriptor> getMessageTypes() {
+ return Collections.unmodifiableList(Arrays.asList(messageTypes));
+ }
+
+ /** Get a list of top-level enum types declared in this file. */
+ public List<EnumDescriptor> getEnumTypes() {
+ return Collections.unmodifiableList(Arrays.asList(enumTypes));
+ }
+
+ /** Get a list of top-level services declared in this file. */
+ public List<ServiceDescriptor> getServices() {
+ return Collections.unmodifiableList(Arrays.asList(services));
+ }
+
+ /** Get a list of top-level extensions declared in this file. */
+ public List<FieldDescriptor> getExtensions() {
+ return Collections.unmodifiableList(Arrays.asList(extensions));
+ }
+
+ /** Get a list of this file's dependencies (imports). */
+ public List<FileDescriptor> getDependencies() {
+ return Collections.unmodifiableList(Arrays.asList(dependencies));
+ }
+
+ /**
+ * Find a message type in the file by name. Does not find nested types.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The message type's descriptor, or {@code null} if not found.
+ */
+ public Descriptor findMessageTypeByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) {
+ return null;
+ }
+ if (getPackage().length() > 0) {
+ name = getPackage() + '.' + name;
+ }
+ final GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof Descriptor &&
+ result.getFile() == this) {
+ return (Descriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an enum type in the file by name. Does not find nested types.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The enum type's descriptor, or {@code null} if not found.
+ */
+ public EnumDescriptor findEnumTypeByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) {
+ return null;
+ }
+ if (getPackage().length() > 0) {
+ name = getPackage() + '.' + name;
+ }
+ final GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof EnumDescriptor &&
+ result.getFile() == this) {
+ return (EnumDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find a service type in the file by name.
+ *
+ * @param name The unqualified type name to look for.
+ * @return The service type's descriptor, or {@code null} if not found.
+ */
+ public ServiceDescriptor findServiceByName(String name) {
+ // Don't allow looking up nested types. This will make optimization
+ // easier later.
+ if (name.indexOf('.') != -1) {
+ return null;
+ }
+ if (getPackage().length() > 0) {
+ name = getPackage() + '.' + name;
+ }
+ final GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof ServiceDescriptor &&
+ result.getFile() == this) {
+ return (ServiceDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an extension in the file by name. Does not find extensions nested
+ * inside message types.
+ *
+ * @param name The unqualified extension name to look for.
+ * @return The extension's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findExtensionByName(String name) {
+ if (name.indexOf('.') != -1) {
+ return null;
+ }
+ if (getPackage().length() > 0) {
+ name = getPackage() + '.' + name;
+ }
+ final GenericDescriptor result = pool.findSymbol(name);
+ if (result != null && result instanceof FieldDescriptor &&
+ result.getFile() == this) {
+ return (FieldDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Construct a {@code FileDescriptor}.
+ *
+ * @param proto The protocol message form of the FileDescriptor.
+ * @param dependencies {@code FileDescriptor}s corresponding to all of
+ * the file's dependencies, in the exact order listed
+ * in {@code proto}.
+ * @throws DescriptorValidationException {@code proto} is not a valid
+ * descriptor. This can occur for a number of reasons, e.g.
+ * because a field has an undefined type or because two messages
+ * were defined with the same name.
+ */
+ public static FileDescriptor buildFrom(final FileDescriptorProto proto,
+ final FileDescriptor[] dependencies)
+ throws DescriptorValidationException {
+ // Building decsriptors involves two steps: translating and linking.
+ // In the translation step (implemented by FileDescriptor's
+ // constructor), we build an object tree mirroring the
+ // FileDescriptorProto's tree and put all of the descriptors into the
+ // DescriptorPool's lookup tables. In the linking step, we look up all
+ // type references in the DescriptorPool, so that, for example, a
+ // FieldDescriptor for an embedded message contains a pointer directly
+ // to the Descriptor for that message's type. We also detect undefined
+ // types in the linking step.
+ final DescriptorPool pool = new DescriptorPool(dependencies);
+ final FileDescriptor result =
+ new FileDescriptor(proto, dependencies, pool);
+
+ if (dependencies.length != proto.getDependencyCount()) {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.buildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ for (int i = 0; i < proto.getDependencyCount(); i++) {
+ if (!dependencies[i].getName().equals(proto.getDependency(i))) {
+ throw new DescriptorValidationException(result,
+ "Dependencies passed to FileDescriptor.buildFrom() don't match " +
+ "those listed in the FileDescriptorProto.");
+ }
+ }
+
+ result.crossLink();
+ return result;
+ }
+
+ /**
+ * This method is to be called by generated code only. It is equivalent
+ * to {@code buildFrom} except that the {@code FileDescriptorProto} is
+ * encoded in protocol buffer wire format.
+ */
+ public static void internalBuildGeneratedFileFrom(
+ final String[] descriptorDataParts,
+ final FileDescriptor[] dependencies,
+ final InternalDescriptorAssigner descriptorAssigner) {
+ // Hack: We can't embed a raw byte array inside generated Java code
+ // (at least, not efficiently), but we can embed Strings. So, the
+ // protocol compiler embeds the FileDescriptorProto as a giant
+ // string literal which is passed to this function to construct the
+ // file's FileDescriptor. The string literal contains only 8-bit
+ // characters, each one representing a byte of the FileDescriptorProto's
+ // serialized form. So, if we convert it to bytes in ISO-8859-1, we
+ // should get the original bytes that we want.
+
+ // descriptorData may contain multiple strings in order to get around the
+ // Java 64k string literal limit.
+ StringBuilder descriptorData = new StringBuilder();
+ for (String part : descriptorDataParts) {
+ descriptorData.append(part);
+ }
+
+ final byte[] descriptorBytes;
+ try {
+ descriptorBytes = descriptorData.toString().getBytes("ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(
+ "Standard encoding ISO-8859-1 not supported by JVM.", e);
+ }
+
+ FileDescriptorProto proto;
+ try {
+ proto = FileDescriptorProto.parseFrom(descriptorBytes);
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalArgumentException(
+ "Failed to parse protocol buffer descriptor for generated code.", e);
+ }
+
+ final FileDescriptor result;
+ try {
+ result = buildFrom(proto, dependencies);
+ } catch (DescriptorValidationException e) {
+ throw new IllegalArgumentException(
+ "Invalid embedded descriptor for \"" + proto.getName() + "\".", e);
+ }
+
+ final ExtensionRegistry registry =
+ descriptorAssigner.assignDescriptors(result);
+
+ if (registry != null) {
+ // We must re-parse the proto using the registry.
+ try {
+ proto = FileDescriptorProto.parseFrom(descriptorBytes, registry);
+ } catch (InvalidProtocolBufferException e) {
+ throw new IllegalArgumentException(
+ "Failed to parse protocol buffer descriptor for generated code.",
+ e);
+ }
+
+ result.setProto(proto);
+ }
+ }
+
+ /**
+ * This class should be used by generated code only. When calling
+ * {@link FileDescriptor#internalBuildGeneratedFileFrom}, the caller
+ * provides a callback implementing this interface. The callback is called
+ * after the FileDescriptor has been constructed, in order to assign all
+ * the global variales defined in the generated code which point at parts
+ * of the FileDescriptor. The callback returns an ExtensionRegistry which
+ * contains any extensions which might be used in the descriptor -- that
+ * is, extensions of the various "Options" messages defined in
+ * descriptor.proto. The callback may also return null to indicate that
+ * no extensions are used in the decsriptor.
+ */
+ public interface InternalDescriptorAssigner {
+ ExtensionRegistry assignDescriptors(FileDescriptor root);
+ }
+
+ private FileDescriptorProto proto;
+ private final Descriptor[] messageTypes;
+ private final EnumDescriptor[] enumTypes;
+ private final ServiceDescriptor[] services;
+ private final FieldDescriptor[] extensions;
+ private final FileDescriptor[] dependencies;
+ private final DescriptorPool pool;
+
+ private FileDescriptor(final FileDescriptorProto proto,
+ final FileDescriptor[] dependencies,
+ final DescriptorPool pool)
+ throws DescriptorValidationException {
+ this.pool = pool;
+ this.proto = proto;
+ this.dependencies = dependencies.clone();
+
+ pool.addPackage(getPackage(), this);
+
+ messageTypes = new Descriptor[proto.getMessageTypeCount()];
+ for (int i = 0; i < proto.getMessageTypeCount(); i++) {
+ messageTypes[i] =
+ new Descriptor(proto.getMessageType(i), this, null, i);
+ }
+
+ enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+ for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+ enumTypes[i] = new EnumDescriptor(proto.getEnumType(i), this, null, i);
+ }
+
+ services = new ServiceDescriptor[proto.getServiceCount()];
+ for (int i = 0; i < proto.getServiceCount(); i++) {
+ services[i] = new ServiceDescriptor(proto.getService(i), this, i);
+ }
+
+ extensions = new FieldDescriptor[proto.getExtensionCount()];
+ for (int i = 0; i < proto.getExtensionCount(); i++) {
+ extensions[i] = new FieldDescriptor(
+ proto.getExtension(i), this, null, i, true);
+ }
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ for (final Descriptor messageType : messageTypes) {
+ messageType.crossLink();
+ }
+
+ for (final ServiceDescriptor service : services) {
+ service.crossLink();
+ }
+
+ for (final FieldDescriptor extension : extensions) {
+ extension.crossLink();
+ }
+ }
+
+ /**
+ * Replace our {@link FileDescriptorProto} with the given one, which is
+ * identical except that it might contain extensions that weren't present
+ * in the original. This method is needed for bootstrapping when a file
+ * defines custom options. The options may be defined in the file itself,
+ * so we can't actually parse them until we've constructed the descriptors,
+ * but to construct the decsriptors we have to have parsed the descriptor
+ * protos. So, we have to parse the descriptor protos a second time after
+ * constructing the descriptors.
+ */
+ private void setProto(final FileDescriptorProto proto) {
+ this.proto = proto;
+
+ for (int i = 0; i < messageTypes.length; i++) {
+ messageTypes[i].setProto(proto.getMessageType(i));
+ }
+
+ for (int i = 0; i < enumTypes.length; i++) {
+ enumTypes[i].setProto(proto.getEnumType(i));
+ }
+
+ for (int i = 0; i < services.length; i++) {
+ services[i].setProto(proto.getService(i));
+ }
+
+ for (int i = 0; i < extensions.length; i++) {
+ extensions[i].setProto(proto.getExtension(i));
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a message type. */
+ public static final class Descriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent. In other words,
+ * given a {@link FileDescriptor} {@code file}, the following is true:
+ * <pre>
+ * for all i in [0, file.getMessageTypeCount()):
+ * file.getMessageType(i).getIndex() == i
+ * </pre>
+ * Similarly, for a {@link Descriptor} {@code messageType}:
+ * <pre>
+ * for all i in [0, messageType.getNestedTypeCount()):
+ * messageType.getNestedType(i).getIndex() == i
+ * </pre>
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public DescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name, within the proto language's
+ * namespace. This differs from the Java name. For example, given this
+ * {@code .proto}:
+ * <pre>
+ * package foo.bar;
+ * option java_package = "com.example.protos"
+ * message Baz {}
+ * </pre>
+ * {@code Baz}'s full name is "foo.bar.Baz".
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** If this is a nested type, get the outer descriptor, otherwise null. */
+ public Descriptor getContainingType() { return containingType; }
+
+ /** Get the {@code MessageOptions}, defined in {@code descriptor.proto}. */
+ public MessageOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of this message type's fields. */
+ public List<FieldDescriptor> getFields() {
+ return Collections.unmodifiableList(Arrays.asList(fields));
+ }
+
+ /** Get a list of this message type's extensions. */
+ public List<FieldDescriptor> getExtensions() {
+ return Collections.unmodifiableList(Arrays.asList(extensions));
+ }
+
+ /** Get a list of message types nested within this one. */
+ public List<Descriptor> getNestedTypes() {
+ return Collections.unmodifiableList(Arrays.asList(nestedTypes));
+ }
+
+ /** Get a list of enum types nested within this one. */
+ public List<EnumDescriptor> getEnumTypes() {
+ return Collections.unmodifiableList(Arrays.asList(enumTypes));
+ }
+
+ /** Determines if the given field number is an extension. */
+ public boolean isExtensionNumber(final int number) {
+ for (final DescriptorProto.ExtensionRange range :
+ proto.getExtensionRangeList()) {
+ if (range.getStart() <= number && number < range.getEnd()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds a field by name.
+ * @param name The unqualified name of the field (e.g. "foo").
+ * @return The field's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findFieldByName(final String name) {
+ final GenericDescriptor result =
+ file.pool.findSymbol(fullName + '.' + name);
+ if (result != null && result instanceof FieldDescriptor) {
+ return (FieldDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds a field by field number.
+ * @param number The field number within this message type.
+ * @return The field's descriptor, or {@code null} if not found.
+ */
+ public FieldDescriptor findFieldByNumber(final int number) {
+ return file.pool.fieldsByNumber.get(
+ new DescriptorPool.DescriptorIntPair(this, number));
+ }
+
+ /**
+ * Finds a nested message type by name.
+ * @param name The unqualified name of the nested type (e.g. "Foo").
+ * @return The types's descriptor, or {@code null} if not found.
+ */
+ public Descriptor findNestedTypeByName(final String name) {
+ final GenericDescriptor result =
+ file.pool.findSymbol(fullName + '.' + name);
+ if (result != null && result instanceof Descriptor) {
+ return (Descriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Finds a nested enum type by name.
+ * @param name The unqualified name of the nested type (e.g. "Foo").
+ * @return The types's descriptor, or {@code null} if not found.
+ */
+ public EnumDescriptor findEnumTypeByName(final String name) {
+ final GenericDescriptor result =
+ file.pool.findSymbol(fullName + '.' + name);
+ if (result != null && result instanceof EnumDescriptor) {
+ return (EnumDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ private final int index;
+ private DescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor containingType;
+ private final Descriptor[] nestedTypes;
+ private final EnumDescriptor[] enumTypes;
+ private final FieldDescriptor[] fields;
+ private final FieldDescriptor[] extensions;
+
+ private Descriptor(final DescriptorProto proto,
+ final FileDescriptor file,
+ final Descriptor parent,
+ final int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+ containingType = parent;
+
+ nestedTypes = new Descriptor[proto.getNestedTypeCount()];
+ for (int i = 0; i < proto.getNestedTypeCount(); i++) {
+ nestedTypes[i] = new Descriptor(
+ proto.getNestedType(i), file, this, i);
+ }
+
+ enumTypes = new EnumDescriptor[proto.getEnumTypeCount()];
+ for (int i = 0; i < proto.getEnumTypeCount(); i++) {
+ enumTypes[i] = new EnumDescriptor(
+ proto.getEnumType(i), file, this, i);
+ }
+
+ fields = new FieldDescriptor[proto.getFieldCount()];
+ for (int i = 0; i < proto.getFieldCount(); i++) {
+ fields[i] = new FieldDescriptor(
+ proto.getField(i), file, this, i, false);
+ }
+
+ extensions = new FieldDescriptor[proto.getExtensionCount()];
+ for (int i = 0; i < proto.getExtensionCount(); i++) {
+ extensions[i] = new FieldDescriptor(
+ proto.getExtension(i), file, this, i, true);
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ for (final Descriptor nestedType : nestedTypes) {
+ nestedType.crossLink();
+ }
+
+ for (final FieldDescriptor field : fields) {
+ field.crossLink();
+ }
+
+ for (final FieldDescriptor extension : extensions) {
+ extension.crossLink();
+ }
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final DescriptorProto proto) {
+ this.proto = proto;
+
+ for (int i = 0; i < nestedTypes.length; i++) {
+ nestedTypes[i].setProto(proto.getNestedType(i));
+ }
+
+ for (int i = 0; i < enumTypes.length; i++) {
+ enumTypes[i].setProto(proto.getEnumType(i));
+ }
+
+ for (int i = 0; i < fields.length; i++) {
+ fields[i].setProto(proto.getField(i));
+ }
+
+ for (int i = 0; i < extensions.length; i++) {
+ extensions[i].setProto(proto.getExtension(i));
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a field of a message type. */
+ public static final class FieldDescriptor
+ implements GenericDescriptor, Comparable<FieldDescriptor>,
+ FieldSet.FieldDescriptorLite<FieldDescriptor> {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public FieldDescriptorProto toProto() { return proto; }
+
+ /** Get the field's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /** Get the field's number. */
+ public int getNumber() { return proto.getNumber(); }
+
+ /**
+ * Get the field's fully-qualified name.
+ * @see Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /**
+ * Get the field's java type. This is just for convenience. Every
+ * {@code FieldDescriptorProto.Type} maps to exactly one Java type.
+ */
+ public JavaType getJavaType() { return type.getJavaType(); }
+
+ /** For internal use only. */
+ public WireFormat.JavaType getLiteJavaType() {
+ return getLiteType().getJavaType();
+ }
+
+ /** Get the {@code FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the field's declared type. */
+ public Type getType() { return type; }
+
+ /** For internal use only. */
+ public WireFormat.FieldType getLiteType() {
+ return table[type.ordinal()];
+ }
+ // I'm pretty sure values() constructs a new array every time, since there
+ // is nothing stopping the caller from mutating the array. Therefore we
+ // make a static copy here.
+ private static final WireFormat.FieldType[] table =
+ WireFormat.FieldType.values();
+
+ /** Is this field declared required? */
+ public boolean isRequired() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REQUIRED;
+ }
+
+ /** Is this field declared optional? */
+ public boolean isOptional() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_OPTIONAL;
+ }
+
+ /** Is this field declared repeated? */
+ public boolean isRepeated() {
+ return proto.getLabel() == FieldDescriptorProto.Label.LABEL_REPEATED;
+ }
+
+ /** Does this field have the {@code [packed = true]} option? */
+ public boolean isPacked() {
+ return getOptions().getPacked();
+ }
+
+ /** Returns true if the field had an explicitly-defined default value. */
+ public boolean hasDefaultValue() { return proto.hasDefaultValue(); }
+
+ /**
+ * Returns the field's default value. Valid for all types except for
+ * messages and groups. For all other types, the object returned is of
+ * the same class that would returned by Message.getField(this).
+ */
+ public Object getDefaultValue() {
+ if (getJavaType() == JavaType.MESSAGE) {
+ throw new UnsupportedOperationException(
+ "FieldDescriptor.getDefaultValue() called on an embedded message " +
+ "field.");
+ }
+ return defaultValue;
+ }
+
+ /** Get the {@code FieldOptions}, defined in {@code descriptor.proto}. */
+ public FieldOptions getOptions() { return proto.getOptions(); }
+
+ /** Is this field an extension? */
+ public boolean isExtension() { return proto.hasExtendee(); }
+
+ /**
+ * Get the field's containing type. For extensions, this is the type being
+ * extended, not the location where the extension was defined. See
+ * {@link #getExtensionScope()}.
+ */
+ public Descriptor getContainingType() { return containingType; }
+
+ /**
+ * For extensions defined nested within message types, gets the outer
+ * type. Not valid for non-extension fields. For example, consider
+ * this {@code .proto} file:
+ * <pre>
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ * extend Foo {
+ * optional int32 baz = 1234;
+ * }
+ * message Bar {
+ * extend Foo {
+ * optional int32 qux = 4321;
+ * }
+ * }
+ * </pre>
+ * Both {@code baz}'s and {@code qux}'s containing type is {@code Foo}.
+ * However, {@code baz}'s extension scope is {@code null} while
+ * {@code qux}'s extension scope is {@code Bar}.
+ */
+ public Descriptor getExtensionScope() {
+ if (!isExtension()) {
+ throw new UnsupportedOperationException(
+ "This field is not an extension.");
+ }
+ return extensionScope;
+ }
+
+ /** For embedded message and group fields, gets the field's type. */
+ public Descriptor getMessageType() {
+ if (getJavaType() != JavaType.MESSAGE) {
+ throw new UnsupportedOperationException(
+ "This field is not of message type.");
+ }
+ return messageType;
+ }
+
+ /** For enum fields, gets the field's type. */
+ public EnumDescriptor getEnumType() {
+ if (getJavaType() != JavaType.ENUM) {
+ throw new UnsupportedOperationException(
+ "This field is not of enum type.");
+ }
+ return enumType;
+ }
+
+ /**
+ * Compare with another {@code FieldDescriptor}. This orders fields in
+ * "canonical" order, which simply means ascending order by field number.
+ * {@code other} must be a field of the same type -- i.e.
+ * {@code getContainingType()} must return the same {@code Descriptor} for
+ * both fields.
+ *
+ * @return negative, zero, or positive if {@code this} is less than,
+ * equal to, or greater than {@code other}, respectively.
+ */
+ public int compareTo(final FieldDescriptor other) {
+ if (other.containingType != containingType) {
+ throw new IllegalArgumentException(
+ "FieldDescriptors can only be compared to other FieldDescriptors " +
+ "for fields of the same message type.");
+ }
+ return getNumber() - other.getNumber();
+ }
+
+ private final int index;
+
+ private FieldDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor extensionScope;
+
+ // Possibly initialized during cross-linking.
+ private Type type;
+ private Descriptor containingType;
+ private Descriptor messageType;
+ private EnumDescriptor enumType;
+ private Object defaultValue;
+
+ public enum Type {
+ DOUBLE (FieldDescriptorProto.Type.TYPE_DOUBLE , JavaType.DOUBLE ),
+ FLOAT (FieldDescriptorProto.Type.TYPE_FLOAT , JavaType.FLOAT ),
+ INT64 (FieldDescriptorProto.Type.TYPE_INT64 , JavaType.LONG ),
+ UINT64 (FieldDescriptorProto.Type.TYPE_UINT64 , JavaType.LONG ),
+ INT32 (FieldDescriptorProto.Type.TYPE_INT32 , JavaType.INT ),
+ FIXED64 (FieldDescriptorProto.Type.TYPE_FIXED64 , JavaType.LONG ),
+ FIXED32 (FieldDescriptorProto.Type.TYPE_FIXED32 , JavaType.INT ),
+ BOOL (FieldDescriptorProto.Type.TYPE_BOOL , JavaType.BOOLEAN ),
+ STRING (FieldDescriptorProto.Type.TYPE_STRING , JavaType.STRING ),
+ GROUP (FieldDescriptorProto.Type.TYPE_GROUP , JavaType.MESSAGE ),
+ MESSAGE (FieldDescriptorProto.Type.TYPE_MESSAGE , JavaType.MESSAGE ),
+ BYTES (FieldDescriptorProto.Type.TYPE_BYTES , JavaType.BYTE_STRING),
+ UINT32 (FieldDescriptorProto.Type.TYPE_UINT32 , JavaType.INT ),
+ ENUM (FieldDescriptorProto.Type.TYPE_ENUM , JavaType.ENUM ),
+ SFIXED32(FieldDescriptorProto.Type.TYPE_SFIXED32, JavaType.INT ),
+ SFIXED64(FieldDescriptorProto.Type.TYPE_SFIXED64, JavaType.LONG ),
+ SINT32 (FieldDescriptorProto.Type.TYPE_SINT32 , JavaType.INT ),
+ SINT64 (FieldDescriptorProto.Type.TYPE_SINT64 , JavaType.LONG );
+
+ Type(final FieldDescriptorProto.Type proto, final JavaType javaType) {
+ this.proto = proto;
+ this.javaType = javaType;
+
+ if (ordinal() != proto.getNumber() - 1) {
+ throw new RuntimeException(
+ "descriptor.proto changed but Desrciptors.java wasn't updated.");
+ }
+ }
+
+ private FieldDescriptorProto.Type proto;
+ private JavaType javaType;
+
+ public FieldDescriptorProto.Type toProto() { return proto; }
+ public JavaType getJavaType() { return javaType; }
+
+ public static Type valueOf(final FieldDescriptorProto.Type type) {
+ return values()[type.getNumber() - 1];
+ }
+ }
+
+ static {
+ // Refuse to init if someone added a new declared type.
+ if (Type.values().length != FieldDescriptorProto.Type.values().length) {
+ throw new RuntimeException(
+ "descriptor.proto has a new declared type but Desrciptors.java " +
+ "wasn't updated.");
+ }
+ }
+
+ public enum JavaType {
+ INT(0),
+ LONG(0L),
+ FLOAT(0F),
+ DOUBLE(0D),
+ BOOLEAN(false),
+ STRING(""),
+ BYTE_STRING(ByteString.EMPTY),
+ ENUM(null),
+ MESSAGE(null);
+
+ JavaType(final Object defaultDefault) {
+ this.defaultDefault = defaultDefault;
+ }
+
+ /**
+ * The default default value for fields of this type, if it's a primitive
+ * type. This is meant for use inside this file only, hence is private.
+ */
+ private final Object defaultDefault;
+ }
+
+ private FieldDescriptor(final FieldDescriptorProto proto,
+ final FileDescriptor file,
+ final Descriptor parent,
+ final int index,
+ final boolean isExtension)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+
+ if (proto.hasType()) {
+ type = Type.valueOf(proto.getType());
+ }
+
+ if (getNumber() <= 0) {
+ throw new DescriptorValidationException(this,
+ "Field numbers must be positive integers.");
+ }
+
+ // Only repeated primitive fields may be packed.
+ if (proto.getOptions().getPacked()) {
+ if (proto.getLabel() != FieldDescriptorProto.Label.LABEL_REPEATED ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_STRING ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_GROUP ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_MESSAGE ||
+ proto.getType() == FieldDescriptorProto.Type.TYPE_BYTES) {
+ throw new DescriptorValidationException(this,
+ "[packed = true] can only be specified for repeated primitive " +
+ "fields.");
+ }
+ }
+
+ if (isExtension) {
+ if (!proto.hasExtendee()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.extendee not set for extension field.");
+ }
+ containingType = null; // Will be filled in when cross-linking
+ if (parent != null) {
+ extensionScope = parent;
+ } else {
+ extensionScope = null;
+ }
+ } else {
+ if (proto.hasExtendee()) {
+ throw new DescriptorValidationException(this,
+ "FieldDescriptorProto.extendee set for non-extension field.");
+ }
+ containingType = parent;
+ extensionScope = null;
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ /** Look up and cross-link all field types, etc. */
+ private void crossLink() throws DescriptorValidationException {
+ if (proto.hasExtendee()) {
+ final GenericDescriptor extendee =
+ file.pool.lookupSymbol(proto.getExtendee(), this);
+ if (!(extendee instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getExtendee() + "\" is not a message type.");
+ }
+ containingType = (Descriptor)extendee;
+
+ if (!getContainingType().isExtensionNumber(getNumber())) {
+ throw new DescriptorValidationException(this,
+ '\"' + getContainingType().getFullName() +
+ "\" does not declare " + getNumber() +
+ " as an extension number.");
+ }
+ }
+
+ if (proto.hasTypeName()) {
+ final GenericDescriptor typeDescriptor =
+ file.pool.lookupSymbol(proto.getTypeName(), this);
+
+ if (!proto.hasType()) {
+ // Choose field type based on symbol.
+ if (typeDescriptor instanceof Descriptor) {
+ type = Type.MESSAGE;
+ } else if (typeDescriptor instanceof EnumDescriptor) {
+ type = Type.ENUM;
+ } else {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getTypeName() + "\" is not a type.");
+ }
+ }
+
+ if (getJavaType() == JavaType.MESSAGE) {
+ if (!(typeDescriptor instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getTypeName() + "\" is not a message type.");
+ }
+ messageType = (Descriptor)typeDescriptor;
+
+ if (proto.hasDefaultValue()) {
+ throw new DescriptorValidationException(this,
+ "Messages can't have default values.");
+ }
+ } else if (getJavaType() == JavaType.ENUM) {
+ if (!(typeDescriptor instanceof EnumDescriptor)) {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getTypeName() + "\" is not an enum type.");
+ }
+ enumType = (EnumDescriptor)typeDescriptor;
+ } else {
+ throw new DescriptorValidationException(this,
+ "Field with primitive type has type_name.");
+ }
+ } else {
+ if (getJavaType() == JavaType.MESSAGE ||
+ getJavaType() == JavaType.ENUM) {
+ throw new DescriptorValidationException(this,
+ "Field with message or enum type missing type_name.");
+ }
+ }
+
+ // We don't attempt to parse the default value until here because for
+ // enums we need the enum type's descriptor.
+ if (proto.hasDefaultValue()) {
+ if (isRepeated()) {
+ throw new DescriptorValidationException(this,
+ "Repeated fields cannot have default values.");
+ }
+
+ try {
+ switch (getType()) {
+ case INT32:
+ case SINT32:
+ case SFIXED32:
+ defaultValue = TextFormat.parseInt32(proto.getDefaultValue());
+ break;
+ case UINT32:
+ case FIXED32:
+ defaultValue = TextFormat.parseUInt32(proto.getDefaultValue());
+ break;
+ case INT64:
+ case SINT64:
+ case SFIXED64:
+ defaultValue = TextFormat.parseInt64(proto.getDefaultValue());
+ break;
+ case UINT64:
+ case FIXED64:
+ defaultValue = TextFormat.parseUInt64(proto.getDefaultValue());
+ break;
+ case FLOAT:
+ defaultValue = Float.valueOf(proto.getDefaultValue());
+ break;
+ case DOUBLE:
+ defaultValue = Double.valueOf(proto.getDefaultValue());
+ break;
+ case BOOL:
+ defaultValue = Boolean.valueOf(proto.getDefaultValue());
+ break;
+ case STRING:
+ defaultValue = proto.getDefaultValue();
+ break;
+ case BYTES:
+ try {
+ defaultValue =
+ TextFormat.unescapeBytes(proto.getDefaultValue());
+ } catch (TextFormat.InvalidEscapeSequenceException e) {
+ throw new DescriptorValidationException(this,
+ "Couldn't parse default value: " + e.getMessage(), e);
+ }
+ break;
+ case ENUM:
+ defaultValue = enumType.findValueByName(proto.getDefaultValue());
+ if (defaultValue == null) {
+ throw new DescriptorValidationException(this,
+ "Unknown enum default value: \"" +
+ proto.getDefaultValue() + '\"');
+ }
+ break;
+ case MESSAGE:
+ case GROUP:
+ throw new DescriptorValidationException(this,
+ "Message type had default value.");
+ }
+ } catch (NumberFormatException e) {
+ final DescriptorValidationException validationException =
+ new DescriptorValidationException(this,
+ "Could not parse default value: \"" +
+ proto.getDefaultValue() + '\"');
+ validationException.initCause(e);
+ throw validationException;
+ }
+ } else {
+ // Determine the default default for this field.
+ if (isRepeated()) {
+ defaultValue = Collections.emptyList();
+ } else {
+ switch (getJavaType()) {
+ case ENUM:
+ // We guarantee elsewhere that an enum type always has at least
+ // one possible value.
+ defaultValue = enumType.getValues().get(0);
+ break;
+ case MESSAGE:
+ defaultValue = null;
+ break;
+ default:
+ defaultValue = getJavaType().defaultDefault;
+ break;
+ }
+ }
+ }
+
+ if (!isExtension()) {
+ file.pool.addFieldByNumber(this);
+ }
+
+ if (containingType != null &&
+ containingType.getOptions().getMessageSetWireFormat()) {
+ if (isExtension()) {
+ if (!isOptional() || getType() != Type.MESSAGE) {
+ throw new DescriptorValidationException(this,
+ "Extensions of MessageSets must be optional messages.");
+ }
+ } else {
+ throw new DescriptorValidationException(this,
+ "MessageSets cannot have fields, only extensions.");
+ }
+ }
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final FieldDescriptorProto proto) {
+ this.proto = proto;
+ }
+
+ /**
+ * For internal use only. This is to satisfy the FieldDescriptorLite
+ * interface.
+ */
+ public MessageLite.Builder internalMergeFrom(
+ MessageLite.Builder to, MessageLite from) {
+ // FieldDescriptors are only used with non-lite messages so we can just
+ // down-cast and call mergeFrom directly.
+ return ((Message.Builder) to).mergeFrom((Message) from);
+ }
+ }
+
+ // =================================================================
+
+ /** Describes an enum type. */
+ public static final class EnumDescriptor
+ implements GenericDescriptor, Internal.EnumLiteMap<EnumValueDescriptor> {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public EnumDescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name.
+ * @see Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** If this is a nested type, get the outer descriptor, otherwise null. */
+ public Descriptor getContainingType() { return containingType; }
+
+ /** Get the {@code EnumOptions}, defined in {@code descriptor.proto}. */
+ public EnumOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of defined values for this enum. */
+ public List<EnumValueDescriptor> getValues() {
+ return Collections.unmodifiableList(Arrays.asList(values));
+ }
+
+ /**
+ * Find an enum value by name.
+ * @param name The unqualified name of the value (e.g. "FOO").
+ * @return the value's decsriptor, or {@code null} if not found.
+ */
+ public EnumValueDescriptor findValueByName(final String name) {
+ final GenericDescriptor result =
+ file.pool.findSymbol(fullName + '.' + name);
+ if (result != null && result instanceof EnumValueDescriptor) {
+ return (EnumValueDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Find an enum value by number. If multiple enum values have the same
+ * number, this returns the first defined value with that number.
+ * @param number The value's number.
+ * @return the value's decsriptor, or {@code null} if not found.
+ */
+ public EnumValueDescriptor findValueByNumber(final int number) {
+ return file.pool.enumValuesByNumber.get(
+ new DescriptorPool.DescriptorIntPair(this, number));
+ }
+
+ private final int index;
+ private EnumDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final Descriptor containingType;
+ private EnumValueDescriptor[] values;
+
+ private EnumDescriptor(final EnumDescriptorProto proto,
+ final FileDescriptor file,
+ final Descriptor parent,
+ final int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ fullName = computeFullName(file, parent, proto.getName());
+ this.file = file;
+ containingType = parent;
+
+ if (proto.getValueCount() == 0) {
+ // We cannot allow enums with no values because this would mean there
+ // would be no valid default value for fields of this type.
+ throw new DescriptorValidationException(this,
+ "Enums must contain at least one value.");
+ }
+
+ values = new EnumValueDescriptor[proto.getValueCount()];
+ for (int i = 0; i < proto.getValueCount(); i++) {
+ values[i] = new EnumValueDescriptor(
+ proto.getValue(i), file, this, i);
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final EnumDescriptorProto proto) {
+ this.proto = proto;
+
+ for (int i = 0; i < values.length; i++) {
+ values[i].setProto(proto.getValue(i));
+ }
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Describes one value within an enum type. Note that multiple defined
+ * values may have the same number. In generated Java code, all values
+ * with the same number after the first become aliases of the first.
+ * However, they still have independent EnumValueDescriptors.
+ */
+ public static final class EnumValueDescriptor
+ implements GenericDescriptor, Internal.EnumLite {
+ /**
+ * Get the index of this descriptor within its parent.
+ * @see Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public EnumValueDescriptorProto toProto() { return proto; }
+
+ /** Get the value's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /** Get the value's number. */
+ public int getNumber() { return proto.getNumber(); }
+
+ /**
+ * Get the value's fully-qualified name.
+ * @see Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the value's enum type. */
+ public EnumDescriptor getType() { return type; }
+
+ /**
+ * Get the {@code EnumValueOptions}, defined in {@code descriptor.proto}.
+ */
+ public EnumValueOptions getOptions() { return proto.getOptions(); }
+
+ private final int index;
+ private EnumValueDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final EnumDescriptor type;
+
+ private EnumValueDescriptor(final EnumValueDescriptorProto proto,
+ final FileDescriptor file,
+ final EnumDescriptor parent,
+ final int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.file = file;
+ type = parent;
+
+ fullName = parent.getFullName() + '.' + proto.getName();
+
+ file.pool.addSymbol(this);
+ file.pool.addEnumValueByNumber(this);
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final EnumValueDescriptorProto proto) {
+ this.proto = proto;
+ }
+ }
+
+ // =================================================================
+
+ /** Describes a service type. */
+ public static final class ServiceDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public ServiceDescriptorProto toProto() { return proto; }
+
+ /** Get the type's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the type's fully-qualified name.
+ * @see Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the {@code ServiceOptions}, defined in {@code descriptor.proto}. */
+ public ServiceOptions getOptions() { return proto.getOptions(); }
+
+ /** Get a list of methods for this service. */
+ public List<MethodDescriptor> getMethods() {
+ return Collections.unmodifiableList(Arrays.asList(methods));
+ }
+
+ /**
+ * Find a method by name.
+ * @param name The unqualified name of the method (e.g. "Foo").
+ * @return the method's decsriptor, or {@code null} if not found.
+ */
+ public MethodDescriptor findMethodByName(final String name) {
+ final GenericDescriptor result =
+ file.pool.findSymbol(fullName + '.' + name);
+ if (result != null && result instanceof MethodDescriptor) {
+ return (MethodDescriptor)result;
+ } else {
+ return null;
+ }
+ }
+
+ private final int index;
+ private ServiceDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private MethodDescriptor[] methods;
+
+ private ServiceDescriptor(final ServiceDescriptorProto proto,
+ final FileDescriptor file,
+ final int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ fullName = computeFullName(file, null, proto.getName());
+ this.file = file;
+
+ methods = new MethodDescriptor[proto.getMethodCount()];
+ for (int i = 0; i < proto.getMethodCount(); i++) {
+ methods[i] = new MethodDescriptor(
+ proto.getMethod(i), file, this, i);
+ }
+
+ file.pool.addSymbol(this);
+ }
+
+ private void crossLink() throws DescriptorValidationException {
+ for (final MethodDescriptor method : methods) {
+ method.crossLink();
+ }
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final ServiceDescriptorProto proto) {
+ this.proto = proto;
+
+ for (int i = 0; i < methods.length; i++) {
+ methods[i].setProto(proto.getMethod(i));
+ }
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Describes one method within a service type.
+ */
+ public static final class MethodDescriptor implements GenericDescriptor {
+ /**
+ * Get the index of this descriptor within its parent.
+ * * @see Descriptors.Descriptor#getIndex()
+ */
+ public int getIndex() { return index; }
+
+ /** Convert the descriptor to its protocol message representation. */
+ public MethodDescriptorProto toProto() { return proto; }
+
+ /** Get the method's unqualified name. */
+ public String getName() { return proto.getName(); }
+
+ /**
+ * Get the method's fully-qualified name.
+ * @see Descriptor#getFullName()
+ */
+ public String getFullName() { return fullName; }
+
+ /** Get the {@link FileDescriptor} containing this descriptor. */
+ public FileDescriptor getFile() { return file; }
+
+ /** Get the method's service type. */
+ public ServiceDescriptor getService() { return service; }
+
+ /** Get the method's input type. */
+ public Descriptor getInputType() { return inputType; }
+
+ /** Get the method's output type. */
+ public Descriptor getOutputType() { return outputType; }
+
+ /**
+ * Get the {@code MethodOptions}, defined in {@code descriptor.proto}.
+ */
+ public MethodOptions getOptions() { return proto.getOptions(); }
+
+ private final int index;
+ private MethodDescriptorProto proto;
+ private final String fullName;
+ private final FileDescriptor file;
+ private final ServiceDescriptor service;
+
+ // Initialized during cross-linking.
+ private Descriptor inputType;
+ private Descriptor outputType;
+
+ private MethodDescriptor(final MethodDescriptorProto proto,
+ final FileDescriptor file,
+ final ServiceDescriptor parent,
+ final int index)
+ throws DescriptorValidationException {
+ this.index = index;
+ this.proto = proto;
+ this.file = file;
+ service = parent;
+
+ fullName = parent.getFullName() + '.' + proto.getName();
+
+ file.pool.addSymbol(this);
+ }
+
+ private void crossLink() throws DescriptorValidationException {
+ final GenericDescriptor input =
+ file.pool.lookupSymbol(proto.getInputType(), this);
+ if (!(input instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getInputType() + "\" is not a message type.");
+ }
+ inputType = (Descriptor)input;
+
+ final GenericDescriptor output =
+ file.pool.lookupSymbol(proto.getOutputType(), this);
+ if (!(output instanceof Descriptor)) {
+ throw new DescriptorValidationException(this,
+ '\"' + proto.getOutputType() + "\" is not a message type.");
+ }
+ outputType = (Descriptor)output;
+ }
+
+ /** See {@link FileDescriptor#setProto}. */
+ private void setProto(final MethodDescriptorProto proto) {
+ this.proto = proto;
+ }
+ }
+
+ // =================================================================
+
+ private static String computeFullName(final FileDescriptor file,
+ final Descriptor parent,
+ final String name) {
+ if (parent != null) {
+ return parent.getFullName() + '.' + name;
+ } else if (file.getPackage().length() > 0) {
+ return file.getPackage() + '.' + name;
+ } else {
+ return name;
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * All descriptors except {@code FileDescriptor} implement this to make
+ * {@code DescriptorPool}'s life easier.
+ */
+ private interface GenericDescriptor {
+ Message toProto();
+ String getName();
+ String getFullName();
+ FileDescriptor getFile();
+ }
+
+ /**
+ * Thrown when building descriptors fails because the source DescriptorProtos
+ * are not valid.
+ */
+ public static class DescriptorValidationException extends Exception {
+ private static final long serialVersionUID = 5750205775490483148L;
+
+ /** Gets the full name of the descriptor where the error occurred. */
+ public String getProblemSymbolName() { return name; }
+
+ /**
+ * Gets the the protocol message representation of the invalid descriptor.
+ */
+ public Message getProblemProto() { return proto; }
+
+ /**
+ * Gets a human-readable description of the error.
+ */
+ public String getDescription() { return description; }
+
+ private final String name;
+ private final Message proto;
+ private final String description;
+
+ private DescriptorValidationException(
+ final GenericDescriptor problemDescriptor,
+ final String description) {
+ this(problemDescriptor, description, null);
+ }
+
+ private DescriptorValidationException(
+ final GenericDescriptor problemDescriptor,
+ final String description,
+ final Throwable cause) {
+ super(problemDescriptor.getFullName() + ": " + description, cause);
+
+ // Note that problemDescriptor may be partially uninitialized, so we
+ // don't want to expose it directly to the user. So, we only provide
+ // the name and the original proto.
+ name = problemDescriptor.getFullName();
+ proto = problemDescriptor.toProto();
+ this.description = description;
+ }
+
+ private DescriptorValidationException(
+ final FileDescriptor problemDescriptor,
+ final String description) {
+ super(problemDescriptor.getName() + ": " + description);
+
+ // Note that problemDescriptor may be partially uninitialized, so we
+ // don't want to expose it directly to the user. So, we only provide
+ // the name and the original proto.
+ name = problemDescriptor.getName();
+ proto = problemDescriptor.toProto();
+ this.description = description;
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * A private helper class which contains lookup tables containing all the
+ * descriptors defined in a particular file.
+ */
+ private static final class DescriptorPool {
+ DescriptorPool(final FileDescriptor[] dependencies) {
+ this.dependencies = new DescriptorPool[dependencies.length];
+
+ for (int i = 0; i < dependencies.length; i++) {
+ this.dependencies[i] = dependencies[i].pool;
+ }
+
+ for (final FileDescriptor dependency : dependencies) {
+ try {
+ addPackage(dependency.getPackage(), dependency);
+ } catch (DescriptorValidationException e) {
+ // Can't happen, because addPackage() only fails when the name
+ // conflicts with a non-package, but we have not yet added any
+ // non-packages at this point.
+ assert false;
+ }
+ }
+ }
+
+ private final DescriptorPool[] dependencies;
+
+ private final Map<String, GenericDescriptor> descriptorsByName =
+ new HashMap<String, GenericDescriptor>();
+ private final Map<DescriptorIntPair, FieldDescriptor> fieldsByNumber =
+ new HashMap<DescriptorIntPair, FieldDescriptor>();
+ private final Map<DescriptorIntPair, EnumValueDescriptor> enumValuesByNumber
+ = new HashMap<DescriptorIntPair, EnumValueDescriptor>();
+
+ /** Find a generic descriptor by fully-qualified name. */
+ GenericDescriptor findSymbol(final String fullName) {
+ GenericDescriptor result = descriptorsByName.get(fullName);
+ if (result != null) {
+ return result;
+ }
+
+ for (final DescriptorPool dependency : dependencies) {
+ result = dependency.descriptorsByName.get(fullName);
+ if (result != null) {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Look up a descriptor by name, relative to some other descriptor.
+ * The name may be fully-qualified (with a leading '.'),
+ * partially-qualified, or unqualified. C++-like name lookup semantics
+ * are used to search for the matching descriptor.
+ */
+ GenericDescriptor lookupSymbol(final String name,
+ final GenericDescriptor relativeTo)
+ throws DescriptorValidationException {
+ // TODO(kenton): This could be optimized in a number of ways.
+
+ GenericDescriptor result;
+ if (name.startsWith(".")) {
+ // Fully-qualified name.
+ result = findSymbol(name.substring(1));
+ } else {
+ // If "name" is a compound identifier, we want to search for the
+ // first component of it, then search within it for the rest.
+ final int firstPartLength = name.indexOf('.');
+ final String firstPart;
+ if (firstPartLength == -1) {
+ firstPart = name;
+ } else {
+ firstPart = name.substring(0, firstPartLength);
+ }
+
+ // We will search each parent scope of "relativeTo" looking for the
+ // symbol.
+ final StringBuilder scopeToTry =
+ new StringBuilder(relativeTo.getFullName());
+
+ while (true) {
+ // Chop off the last component of the scope.
+ final int dotpos = scopeToTry.lastIndexOf(".");
+ if (dotpos == -1) {
+ result = findSymbol(name);
+ break;
+ } else {
+ scopeToTry.setLength(dotpos + 1);
+
+ // Append firstPart and try to find.
+ scopeToTry.append(firstPart);
+ result = findSymbol(scopeToTry.toString());
+
+ if (result != null) {
+ if (firstPartLength != -1) {
+ // We only found the first part of the symbol. Now look for
+ // the whole thing. If this fails, we *don't* want to keep
+ // searching parent scopes.
+ scopeToTry.setLength(dotpos + 1);
+ scopeToTry.append(name);
+ result = findSymbol(scopeToTry.toString());
+ }
+ break;
+ }
+
+ // Not found. Remove the name so we can try again.
+ scopeToTry.setLength(dotpos);
+ }
+ }
+ }
+
+ if (result == null) {
+ throw new DescriptorValidationException(relativeTo,
+ '\"' + name + "\" is not defined.");
+ } else {
+ return result;
+ }
+ }
+
+ /**
+ * Adds a symbol to the symbol table. If a symbol with the same name
+ * already exists, throws an error.
+ */
+ void addSymbol(final GenericDescriptor descriptor)
+ throws DescriptorValidationException {
+ validateSymbolName(descriptor);
+
+ final String fullName = descriptor.getFullName();
+ final int dotpos = fullName.lastIndexOf('.');
+
+ final GenericDescriptor old = descriptorsByName.put(fullName, descriptor);
+ if (old != null) {
+ descriptorsByName.put(fullName, old);
+
+ if (descriptor.getFile() == old.getFile()) {
+ if (dotpos == -1) {
+ throw new DescriptorValidationException(descriptor,
+ '\"' + fullName + "\" is already defined.");
+ } else {
+ throw new DescriptorValidationException(descriptor,
+ '\"' + fullName.substring(dotpos + 1) +
+ "\" is already defined in \"" +
+ fullName.substring(0, dotpos) + "\".");
+ }
+ } else {
+ throw new DescriptorValidationException(descriptor,
+ '\"' + fullName + "\" is already defined in file \"" +
+ old.getFile().getName() + "\".");
+ }
+ }
+ }
+
+ /**
+ * Represents a package in the symbol table. We use PackageDescriptors
+ * just as placeholders so that someone cannot define, say, a message type
+ * that has the same name as an existing package.
+ */
+ private static final class PackageDescriptor implements GenericDescriptor {
+ public Message toProto() { return file.toProto(); }
+ public String getName() { return name; }
+ public String getFullName() { return fullName; }
+ public FileDescriptor getFile() { return file; }
+
+ PackageDescriptor(final String name, final String fullName,
+ final FileDescriptor file) {
+ this.file = file;
+ this.fullName = fullName;
+ this.name = name;
+ }
+
+ private final String name;
+ private final String fullName;
+ private final FileDescriptor file;
+ }
+
+ /**
+ * Adds a package to the symbol tables. If a package by the same name
+ * already exists, that is fine, but if some other kind of symbol exists
+ * under the same name, an exception is thrown. If the package has
+ * multiple components, this also adds the parent package(s).
+ */
+ void addPackage(final String fullName, final FileDescriptor file)
+ throws DescriptorValidationException {
+ final int dotpos = fullName.lastIndexOf('.');
+ final String name;
+ if (dotpos == -1) {
+ name = fullName;
+ } else {
+ addPackage(fullName.substring(0, dotpos), file);
+ name = fullName.substring(dotpos + 1);
+ }
+
+ final GenericDescriptor old =
+ descriptorsByName.put(fullName,
+ new PackageDescriptor(name, fullName, file));
+ if (old != null) {
+ descriptorsByName.put(fullName, old);
+ if (!(old instanceof PackageDescriptor)) {
+ throw new DescriptorValidationException(file,
+ '\"' + name + "\" is already defined (as something other than a "
+ + "package) in file \"" + old.getFile().getName() + "\".");
+ }
+ }
+ }
+
+ /** A (GenericDescriptor, int) pair, used as a map key. */
+ private static final class DescriptorIntPair {
+ private final GenericDescriptor descriptor;
+ private final int number;
+
+ DescriptorIntPair(final GenericDescriptor descriptor, final int number) {
+ this.descriptor = descriptor;
+ this.number = number;
+ }
+
+ @Override
+ public int hashCode() {
+ return descriptor.hashCode() * ((1 << 16) - 1) + number;
+ }
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof DescriptorIntPair)) {
+ return false;
+ }
+ final DescriptorIntPair other = (DescriptorIntPair)obj;
+ return descriptor == other.descriptor && number == other.number;
+ }
+ }
+
+ /**
+ * Adds a field to the fieldsByNumber table. Throws an exception if a
+ * field with hte same containing type and number already exists.
+ */
+ void addFieldByNumber(final FieldDescriptor field)
+ throws DescriptorValidationException {
+ final DescriptorIntPair key =
+ new DescriptorIntPair(field.getContainingType(), field.getNumber());
+ final FieldDescriptor old = fieldsByNumber.put(key, field);
+ if (old != null) {
+ fieldsByNumber.put(key, old);
+ throw new DescriptorValidationException(field,
+ "Field number " + field.getNumber() +
+ "has already been used in \"" +
+ field.getContainingType().getFullName() +
+ "\" by field \"" + old.getName() + "\".");
+ }
+ }
+
+ /**
+ * Adds an enum value to the enumValuesByNumber table. If an enum value
+ * with the same type and number already exists, does nothing. (This is
+ * allowed; the first value define with the number takes precedence.)
+ */
+ void addEnumValueByNumber(final EnumValueDescriptor value) {
+ final DescriptorIntPair key =
+ new DescriptorIntPair(value.getType(), value.getNumber());
+ final EnumValueDescriptor old = enumValuesByNumber.put(key, value);
+ if (old != null) {
+ enumValuesByNumber.put(key, old);
+ // Not an error: Multiple enum values may have the same number, but
+ // we only want the first one in the map.
+ }
+ }
+
+ /**
+ * Verifies that the descriptor's name is valid (i.e. it contains only
+ * letters, digits, and underscores, and does not start with a digit).
+ */
+ static void validateSymbolName(final GenericDescriptor descriptor)
+ throws DescriptorValidationException {
+ final String name = descriptor.getName();
+ if (name.length() == 0) {
+ throw new DescriptorValidationException(descriptor, "Missing name.");
+ } else {
+ boolean valid = true;
+ for (int i = 0; i < name.length(); i++) {
+ final char c = name.charAt(i);
+ // Non-ASCII characters are not valid in protobuf identifiers, even
+ // if they are letters or digits.
+ if (c >= 128) {
+ valid = false;
+ }
+ // First character must be letter or _. Subsequent characters may
+ // be letters, numbers, or digits.
+ if (Character.isLetter(c) || c == '_' ||
+ (Character.isDigit(c) && i > 0)) {
+ // Valid
+ } else {
+ valid = false;
+ }
+ }
+ if (!valid) {
+ throw new DescriptorValidationException(descriptor,
+ '\"' + name + "\" is not a valid identifier.");
+ }
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/DynamicMessage.java b/java/src/main/java/com/google/protobuf/DynamicMessage.java
new file mode 100644
index 0000000..c106b66
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/DynamicMessage.java
@@ -0,0 +1,438 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * An implementation of {@link Message} that can represent arbitrary types,
+ * given a {@link Descriptors.Descriptor}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class DynamicMessage extends AbstractMessage {
+ private final Descriptor type;
+ private final FieldSet<FieldDescriptor> fields;
+ private final UnknownFieldSet unknownFields;
+ private int memoizedSize = -1;
+
+ /**
+ * Construct a {@code DynamicMessage} using the given {@code FieldSet}.
+ */
+ private DynamicMessage(Descriptor type, FieldSet<FieldDescriptor> fields,
+ UnknownFieldSet unknownFields) {
+ this.type = type;
+ this.fields = fields;
+ this.unknownFields = unknownFields;
+ }
+
+ /**
+ * Get a {@code DynamicMessage} representing the default instance of the
+ * given type.
+ */
+ public static DynamicMessage getDefaultInstance(Descriptor type) {
+ return new DynamicMessage(type, FieldSet.<FieldDescriptor>emptySet(),
+ UnknownFieldSet.getDefaultInstance());
+ }
+
+ /** Parse a message of the given type from the given input stream. */
+ public static DynamicMessage parseFrom(Descriptor type,
+ CodedInputStream input)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input).buildParsed();
+ }
+
+ /** Parse a message of the given type from the given input stream. */
+ public static DynamicMessage parseFrom(
+ Descriptor type,
+ CodedInputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, ByteString data)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, ByteString data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, byte[] data)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data).buildParsed();
+ }
+
+ /** Parse {@code data} as a message of the given type and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, byte[] data,
+ ExtensionRegistry extensionRegistry)
+ throws InvalidProtocolBufferException {
+ return newBuilder(type).mergeFrom(data, extensionRegistry).buildParsed();
+ }
+
+ /** Parse a message of the given type from {@code input} and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, InputStream input)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input).buildParsed();
+ }
+
+ /** Parse a message of the given type from {@code input} and return it. */
+ public static DynamicMessage parseFrom(Descriptor type, InputStream input,
+ ExtensionRegistry extensionRegistry)
+ throws IOException {
+ return newBuilder(type).mergeFrom(input, extensionRegistry).buildParsed();
+ }
+
+ /** Construct a {@link Message.Builder} for the given type. */
+ public static Builder newBuilder(Descriptor type) {
+ return new Builder(type);
+ }
+
+ /**
+ * Construct a {@link Message.Builder} for a message of the same type as
+ * {@code prototype}, and initialize it with {@code prototype}'s contents.
+ */
+ public static Builder newBuilder(Message prototype) {
+ return new Builder(prototype.getDescriptorForType()).mergeFrom(prototype);
+ }
+
+ // -----------------------------------------------------------------
+ // Implementation of Message interface.
+
+ public Descriptor getDescriptorForType() {
+ return type;
+ }
+
+ public DynamicMessage getDefaultInstanceForType() {
+ return getDefaultInstance(type);
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return fields.getAllFields();
+ }
+
+ public boolean hasField(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.hasField(field);
+ }
+
+ public Object getField(FieldDescriptor field) {
+ verifyContainingType(field);
+ Object result = fields.getField(field);
+ if (result == null) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ result = getDefaultInstance(field.getMessageType());
+ } else {
+ result = field.getDefaultValue();
+ }
+ }
+ return result;
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ verifyContainingType(field);
+ return fields.getRepeatedField(field, index);
+ }
+
+ public UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ private static boolean isInitialized(Descriptor type,
+ FieldSet<FieldDescriptor> fields) {
+ // Check that all required fields are present.
+ for (final FieldDescriptor field : type.getFields()) {
+ if (field.isRequired()) {
+ if (!fields.hasField(field)) {
+ return false;
+ }
+ }
+ }
+
+ // Check that embedded messages are initialized.
+ return fields.isInitialized();
+ }
+
+ public boolean isInitialized() {
+ return isInitialized(type, fields);
+ }
+
+ public void writeTo(CodedOutputStream output) throws IOException {
+ if (type.getOptions().getMessageSetWireFormat()) {
+ fields.writeMessageSetTo(output);
+ unknownFields.writeAsMessageSetTo(output);
+ } else {
+ fields.writeTo(output);
+ unknownFields.writeTo(output);
+ }
+ }
+
+ public int getSerializedSize() {
+ int size = memoizedSize;
+ if (size != -1) return size;
+
+ if (type.getOptions().getMessageSetWireFormat()) {
+ size = fields.getMessageSetSerializedSize();
+ size += unknownFields.getSerializedSizeAsMessageSet();
+ } else {
+ size = fields.getSerializedSize();
+ size += unknownFields.getSerializedSize();
+ }
+
+ memoizedSize = size;
+ return size;
+ }
+
+ public Builder newBuilderForType() {
+ return new Builder(type);
+ }
+
+ public Builder toBuilder() {
+ return newBuilderForType().mergeFrom(this);
+ }
+
+ /** Verifies that the field is a field of this message. */
+ private void verifyContainingType(FieldDescriptor field) {
+ if (field.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+
+ // =================================================================
+
+ /**
+ * Builder for {@link DynamicMessage}s.
+ */
+ public static final class Builder extends AbstractMessage.Builder<Builder> {
+ private final Descriptor type;
+ private FieldSet<FieldDescriptor> fields;
+ private UnknownFieldSet unknownFields;
+
+ /** Construct a {@code Builder} for the given type. */
+ private Builder(Descriptor type) {
+ this.type = type;
+ this.fields = FieldSet.newFieldSet();
+ this.unknownFields = UnknownFieldSet.getDefaultInstance();
+ }
+
+ // ---------------------------------------------------------------
+ // Implementation of Message.Builder interface.
+
+ public Builder clear() {
+ if (fields == null) {
+ throw new IllegalStateException("Cannot call clear() after build().");
+ }
+ fields.clear();
+ return this;
+ }
+
+ public Builder mergeFrom(Message other) {
+ if (other instanceof DynamicMessage) {
+ // This should be somewhat faster than calling super.mergeFrom().
+ DynamicMessage otherDynamicMessage = (DynamicMessage) other;
+ if (otherDynamicMessage.type != type) {
+ throw new IllegalArgumentException(
+ "mergeFrom(Message) can only merge messages of the same type.");
+ }
+ fields.mergeFrom(otherDynamicMessage.fields);
+ mergeUnknownFields(otherDynamicMessage.unknownFields);
+ return this;
+ } else {
+ return super.mergeFrom(other);
+ }
+ }
+
+ public DynamicMessage build() {
+ // If fields == null, we'll throw an appropriate exception later.
+ if (fields != null && !isInitialized()) {
+ throw newUninitializedMessageException(
+ new DynamicMessage(type, fields, unknownFields));
+ }
+ return buildPartial();
+ }
+
+ /**
+ * Helper for DynamicMessage.parseFrom() methods to call. Throws
+ * {@link InvalidProtocolBufferException} instead of
+ * {@link UninitializedMessageException}.
+ */
+ private DynamicMessage buildParsed() throws InvalidProtocolBufferException {
+ if (!isInitialized()) {
+ throw newUninitializedMessageException(
+ new DynamicMessage(type, fields, unknownFields))
+ .asInvalidProtocolBufferException();
+ }
+ return buildPartial();
+ }
+
+ public DynamicMessage buildPartial() {
+ if (fields == null) {
+ throw new IllegalStateException(
+ "build() has already been called on this Builder.");
+ }
+ fields.makeImmutable();
+ DynamicMessage result =
+ new DynamicMessage(type, fields, unknownFields);
+ fields = null;
+ unknownFields = null;
+ return result;
+ }
+
+ public Builder clone() {
+ Builder result = new Builder(type);
+ result.fields.mergeFrom(fields);
+ return result;
+ }
+
+ public boolean isInitialized() {
+ return DynamicMessage.isInitialized(type, fields);
+ }
+
+ public Descriptor getDescriptorForType() {
+ return type;
+ }
+
+ public DynamicMessage getDefaultInstanceForType() {
+ return getDefaultInstance(type);
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return fields.getAllFields();
+ }
+
+ public Builder newBuilderForField(FieldDescriptor field) {
+ verifyContainingType(field);
+
+ if (field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "newBuilderForField is only valid for fields with message type.");
+ }
+
+ return new Builder(field.getMessageType());
+ }
+
+ public boolean hasField(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.hasField(field);
+ }
+
+ public Object getField(FieldDescriptor field) {
+ verifyContainingType(field);
+ Object result = fields.getField(field);
+ if (result == null) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ result = getDefaultInstance(field.getMessageType());
+ } else {
+ result = field.getDefaultValue();
+ }
+ }
+ return result;
+ }
+
+ public Builder setField(FieldDescriptor field, Object value) {
+ verifyContainingType(field);
+ fields.setField(field, value);
+ return this;
+ }
+
+ public Builder clearField(FieldDescriptor field) {
+ verifyContainingType(field);
+ fields.clearField(field);
+ return this;
+ }
+
+ public int getRepeatedFieldCount(FieldDescriptor field) {
+ verifyContainingType(field);
+ return fields.getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(FieldDescriptor field, int index) {
+ verifyContainingType(field);
+ return fields.getRepeatedField(field, index);
+ }
+
+ public Builder setRepeatedField(FieldDescriptor field,
+ int index, Object value) {
+ verifyContainingType(field);
+ fields.setRepeatedField(field, index, value);
+ return this;
+ }
+
+ public Builder addRepeatedField(FieldDescriptor field, Object value) {
+ verifyContainingType(field);
+ fields.addRepeatedField(field, value);
+ return this;
+ }
+
+ public UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+ this.unknownFields = unknownFields;
+ return this;
+ }
+
+ public Builder mergeUnknownFields(UnknownFieldSet unknownFields) {
+ this.unknownFields =
+ UnknownFieldSet.newBuilder(this.unknownFields)
+ .mergeFrom(unknownFields)
+ .build();
+ return this;
+ }
+
+ /** Verifies that the field is a field of this message. */
+ private void verifyContainingType(FieldDescriptor field) {
+ if (field.getContainingType() != type) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistry.java b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
new file mode 100644
index 0000000..87bbd6e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ExtensionRegistry.java
@@ -0,0 +1,261 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * A table of known extensions, searchable by name or field number. When
+ * parsing a protocol message that might have extensions, you must provide
+ * an {@code ExtensionRegistry} in which you have registered any extensions
+ * that you want to be able to parse. Otherwise, those extensions will just
+ * be treated like unknown fields.
+ *
+ * <p>For example, if you had the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * Then you might write code like:
+ *
+ * <pre>
+ * ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ * registry.add(MyProto.bar);
+ * MyProto.Foo message = MyProto.Foo.parseFrom(input, registry);
+ * </pre>
+ *
+ * <p>Background:
+ *
+ * <p>You might wonder why this is necessary. Two alternatives might come to
+ * mind. First, you might imagine a system where generated extensions are
+ * automatically registered when their containing classes are loaded. This
+ * is a popular technique, but is bad design; among other things, it creates a
+ * situation where behavior can change depending on what classes happen to be
+ * loaded. It also introduces a security vulnerability, because an
+ * unprivileged class could cause its code to be called unexpectedly from a
+ * privileged class by registering itself as an extension of the right type.
+ *
+ * <p>Another option you might consider is lazy parsing: do not parse an
+ * extension until it is first requested, at which point the caller must
+ * provide a type to use. This introduces a different set of problems. First,
+ * it would require a mutex lock any time an extension was accessed, which
+ * would be slow. Second, corrupt data would not be detected until first
+ * access, at which point it would be much harder to deal with it. Third, it
+ * could violate the expectation that message objects are immutable, since the
+ * type provided could be any arbitrary message class. An unprivileged user
+ * could take advantage of this to inject a mutable object into a message
+ * belonging to privileged code and create mischief.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class ExtensionRegistry extends ExtensionRegistryLite {
+ /** Construct a new, empty instance. */
+ public static ExtensionRegistry newInstance() {
+ return new ExtensionRegistry();
+ }
+
+ /** Get the unmodifiable singleton empty instance. */
+ public static ExtensionRegistry getEmptyRegistry() {
+ return EMPTY;
+ }
+
+ /** Returns an unmodifiable view of the registry. */
+ @Override
+ public ExtensionRegistry getUnmodifiable() {
+ return new ExtensionRegistry(this);
+ }
+
+ /** A (Descriptor, Message) pair, returned by lookup methods. */
+ public static final class ExtensionInfo {
+ /** The extension's descriptor. */
+ public final FieldDescriptor descriptor;
+
+ /**
+ * A default instance of the extension's type, if it has a message type.
+ * Otherwise, {@code null}.
+ */
+ public final Message defaultInstance;
+
+ private ExtensionInfo(final FieldDescriptor descriptor) {
+ this.descriptor = descriptor;
+ defaultInstance = null;
+ }
+ private ExtensionInfo(final FieldDescriptor descriptor,
+ final Message defaultInstance) {
+ this.descriptor = descriptor;
+ this.defaultInstance = defaultInstance;
+ }
+ }
+
+ /**
+ * Find an extension by fully-qualified field name, in the proto namespace.
+ * I.e. {@code result.descriptor.fullName()} will match {@code fullName} if
+ * a match is found.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findExtensionByName(final String fullName) {
+ return extensionsByName.get(fullName);
+ }
+
+ /**
+ * Find an extension by containing type and field number.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ public ExtensionInfo findExtensionByNumber(final Descriptor containingType,
+ final int fieldNumber) {
+ return extensionsByNumber.get(
+ new DescriptorIntPair(containingType, fieldNumber));
+ }
+
+ /** Add an extension from a generated file to the registry. */
+ public void add(final GeneratedMessage.GeneratedExtension<?, ?> extension) {
+ if (extension.getDescriptor().getJavaType() ==
+ FieldDescriptor.JavaType.MESSAGE) {
+ add(new ExtensionInfo(extension.getDescriptor(),
+ extension.getMessageDefaultInstance()));
+ } else {
+ add(new ExtensionInfo(extension.getDescriptor(), null));
+ }
+ }
+
+ /** Add a non-message-type extension to the registry by descriptor. */
+ public void add(final FieldDescriptor type) {
+ if (type.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() must be provided a default instance when " +
+ "adding an embedded message extension.");
+ }
+ add(new ExtensionInfo(type, null));
+ }
+
+ /** Add a message-type extension to the registry by descriptor. */
+ public void add(final FieldDescriptor type, final Message defaultInstance) {
+ if (type.getJavaType() != FieldDescriptor.JavaType.MESSAGE) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() provided a default instance for a " +
+ "non-message extension.");
+ }
+ add(new ExtensionInfo(type, defaultInstance));
+ }
+
+ // =================================================================
+ // Private stuff.
+
+ private ExtensionRegistry() {
+ this.extensionsByName = new HashMap<String, ExtensionInfo>();
+ this.extensionsByNumber = new HashMap<DescriptorIntPair, ExtensionInfo>();
+ }
+
+ private ExtensionRegistry(ExtensionRegistry other) {
+ super(other);
+ this.extensionsByName = Collections.unmodifiableMap(other.extensionsByName);
+ this.extensionsByNumber =
+ Collections.unmodifiableMap(other.extensionsByNumber);
+ }
+
+ private final Map<String, ExtensionInfo> extensionsByName;
+ private final Map<DescriptorIntPair, ExtensionInfo> extensionsByNumber;
+
+ private ExtensionRegistry(boolean empty) {
+ super(ExtensionRegistryLite.getEmptyRegistry());
+ this.extensionsByName = Collections.<String, ExtensionInfo>emptyMap();
+ this.extensionsByNumber =
+ Collections.<DescriptorIntPair, ExtensionInfo>emptyMap();
+ }
+ private static final ExtensionRegistry EMPTY = new ExtensionRegistry(true);
+
+ private void add(final ExtensionInfo extension) {
+ if (!extension.descriptor.isExtension()) {
+ throw new IllegalArgumentException(
+ "ExtensionRegistry.add() was given a FieldDescriptor for a regular " +
+ "(non-extension) field.");
+ }
+
+ extensionsByName.put(extension.descriptor.getFullName(), extension);
+ extensionsByNumber.put(
+ new DescriptorIntPair(extension.descriptor.getContainingType(),
+ extension.descriptor.getNumber()),
+ extension);
+
+ final FieldDescriptor field = extension.descriptor;
+ if (field.getContainingType().getOptions().getMessageSetWireFormat() &&
+ field.getType() == FieldDescriptor.Type.MESSAGE &&
+ field.isOptional() &&
+ field.getExtensionScope() == field.getMessageType()) {
+ // This is an extension of a MessageSet type defined within the extension
+ // type's own scope. For backwards-compatibility, allow it to be looked
+ // up by type name.
+ extensionsByName.put(field.getMessageType().getFullName(), extension);
+ }
+ }
+
+ /** A (GenericDescriptor, int) pair, used as a map key. */
+ private static final class DescriptorIntPair {
+ private final Descriptor descriptor;
+ private final int number;
+
+ DescriptorIntPair(final Descriptor descriptor, final int number) {
+ this.descriptor = descriptor;
+ this.number = number;
+ }
+
+ @Override
+ public int hashCode() {
+ return descriptor.hashCode() * ((1 << 16) - 1) + number;
+ }
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof DescriptorIntPair)) {
+ return false;
+ }
+ final DescriptorIntPair other = (DescriptorIntPair)obj;
+ return descriptor == other.descriptor && number == other.number;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java b/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
new file mode 100644
index 0000000..d5288dd
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ExtensionRegistryLite.java
@@ -0,0 +1,169 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Equivalent to {@link ExtensionRegistry} but supports only "lite" types.
+ * <p>
+ * If all of your types are lite types, then you only need to use
+ * {@code ExtensionRegistryLite}. Similarly, if all your types are regular
+ * types, then you only need {@link ExtensionRegistry}. Typically it does not
+ * make sense to mix the two, since if you have any regular types in your
+ * program, you then require the full runtime and lose all the benefits of
+ * the lite runtime, so you might as well make all your types be regular types.
+ * However, in some cases (e.g. when depending on multiple third-patry libraries
+ * where one uses lite types and one uses regular), you may find yourself
+ * wanting to mix the two. In this case things get more complicated.
+ * <p>
+ * There are three factors to consider: Whether the type being extended is
+ * lite, whether the embedded type (in the case of a message-typed extension)
+ * is lite, and whether the extension itself is lite. Since all three are
+ * declared in different files, they could all be different. Here are all
+ * the combinations and which type of registry to use:
+ * <pre>
+ * Extended type Inner type Extension Use registry
+ * =======================================================================
+ * lite lite lite ExtensionRegistryLite
+ * lite regular lite ExtensionRegistry
+ * regular regular regular ExtensionRegistry
+ * all other combinations not supported
+ * </pre>
+ * <p>
+ * Note that just as regular types are not allowed to contain lite-type fields,
+ * they are also not allowed to contain lite-type extensions. This is because
+ * regular types must be fully accessible via reflection, which in turn means
+ * that all the inner messages must also support reflection. On the other hand,
+ * since regular types implement the entire lite interface, there is no problem
+ * with embedding regular types inside lite types.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ExtensionRegistryLite {
+ /** Construct a new, empty instance. */
+ public static ExtensionRegistryLite newInstance() {
+ return new ExtensionRegistryLite();
+ }
+
+ /** Get the unmodifiable singleton empty instance. */
+ public static ExtensionRegistryLite getEmptyRegistry() {
+ return EMPTY;
+ }
+
+ /** Returns an unmodifiable view of the registry. */
+ public ExtensionRegistryLite getUnmodifiable() {
+ return new ExtensionRegistryLite(this);
+ }
+
+ /**
+ * Find an extension by containing type and field number.
+ *
+ * @return Information about the extension if found, or {@code null}
+ * otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ public <ContainingType extends MessageLite>
+ GeneratedMessageLite.GeneratedExtension<ContainingType, ?>
+ findLiteExtensionByNumber(
+ final ContainingType containingTypeDefaultInstance,
+ final int fieldNumber) {
+ return (GeneratedMessageLite.GeneratedExtension<ContainingType, ?>)
+ extensionsByNumber.get(
+ new ObjectIntPair(containingTypeDefaultInstance, fieldNumber));
+ }
+
+ /** Add an extension from a lite generated file to the registry. */
+ public final void add(
+ final GeneratedMessageLite.GeneratedExtension<?, ?> extension) {
+ extensionsByNumber.put(
+ new ObjectIntPair(extension.getContainingTypeDefaultInstance(),
+ extension.getNumber()),
+ extension);
+ }
+
+ // =================================================================
+ // Private stuff.
+
+ // Constructors are package-private so that ExtensionRegistry can subclass
+ // this.
+
+ ExtensionRegistryLite() {
+ this.extensionsByNumber =
+ new HashMap<ObjectIntPair,
+ GeneratedMessageLite.GeneratedExtension<?, ?>>();
+ }
+
+ ExtensionRegistryLite(ExtensionRegistryLite other) {
+ if (other == EMPTY) {
+ this.extensionsByNumber = Collections.emptyMap();
+ } else {
+ this.extensionsByNumber =
+ Collections.unmodifiableMap(other.extensionsByNumber);
+ }
+ }
+
+ private final Map<ObjectIntPair,
+ GeneratedMessageLite.GeneratedExtension<?, ?>>
+ extensionsByNumber;
+
+ private ExtensionRegistryLite(boolean empty) {
+ this.extensionsByNumber = Collections.emptyMap();
+ }
+ private static final ExtensionRegistryLite EMPTY =
+ new ExtensionRegistryLite(true);
+
+ /** A (Object, int) pair, used as a map key. */
+ private static final class ObjectIntPair {
+ private final Object object;
+ private final int number;
+
+ ObjectIntPair(final Object object, final int number) {
+ this.object = object;
+ this.number = number;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(object) * ((1 << 16) - 1) + number;
+ }
+ @Override
+ public boolean equals(final Object obj) {
+ if (!(obj instanceof ObjectIntPair)) {
+ return false;
+ }
+ final ObjectIntPair other = (ObjectIntPair)obj;
+ return object == other.object && number == other.number;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/FieldSet.java b/java/src/main/java/com/google/protobuf/FieldSet.java
new file mode 100644
index 0000000..93e55f2
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/FieldSet.java
@@ -0,0 +1,712 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.TreeMap;
+import java.util.List;
+import java.util.Map;
+import java.io.IOException;
+
+/**
+ * A class which represents an arbitrary set of fields of some message type.
+ * This is used to implement {@link DynamicMessage}, and also to represent
+ * extensions in {@link GeneratedMessage}. This class is package-private,
+ * since outside users should probably be using {@link DynamicMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+final class FieldSet<FieldDescriptorType extends
+ FieldSet.FieldDescriptorLite<FieldDescriptorType>> {
+ /**
+ * Interface for a FieldDescriptor or lite extension descriptor. This
+ * prevents FieldSet from depending on {@link Descriptors.FieldDescriptor}.
+ */
+ public interface FieldDescriptorLite<T extends FieldDescriptorLite<T>>
+ extends Comparable<T> {
+ int getNumber();
+ WireFormat.FieldType getLiteType();
+ WireFormat.JavaType getLiteJavaType();
+ boolean isRepeated();
+ boolean isPacked();
+ Internal.EnumLiteMap<?> getEnumType();
+
+ // If getLiteJavaType() == MESSAGE, this merges a message object of the
+ // type into a builder of the type. Returns {@code to}.
+ MessageLite.Builder internalMergeFrom(
+ MessageLite.Builder to, MessageLite from);
+ }
+
+ private Map<FieldDescriptorType, Object> fields;
+
+ /** Construct a new FieldSet. */
+ private FieldSet() {
+ // Use a TreeMap because fields need to be in canonical order when
+ // serializing.
+ // TODO(kenton): Maybe use some sort of sparse array instead? It would
+ // even make sense to store the first 16 or so tags in a flat array
+ // to make DynamicMessage faster.
+ fields = new TreeMap<FieldDescriptorType, Object>();
+ }
+
+ /**
+ * Construct an empty FieldSet. This is only used to initialize
+ * DEFAULT_INSTANCE.
+ */
+ private FieldSet(final boolean dummy) {
+ this.fields = Collections.emptyMap();
+ }
+
+ /** Construct a new FieldSet. */
+ public static <T extends FieldSet.FieldDescriptorLite<T>>
+ FieldSet<T> newFieldSet() {
+ return new FieldSet<T>();
+ }
+
+ /** Get an immutable empty FieldSet. */
+ @SuppressWarnings("unchecked")
+ public static <T extends FieldSet.FieldDescriptorLite<T>>
+ FieldSet<T> emptySet() {
+ return DEFAULT_INSTANCE;
+ }
+ @SuppressWarnings("unchecked")
+ private static final FieldSet DEFAULT_INSTANCE = new FieldSet(true);
+
+ /** Make this FieldSet immutable from this point forward. */
+ @SuppressWarnings("unchecked")
+ public void makeImmutable() {
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ if (entry.getKey().isRepeated()) {
+ final List value = (List)entry.getValue();
+ fields.put(entry.getKey(), Collections.unmodifiableList(value));
+ }
+ }
+ fields = Collections.unmodifiableMap(fields);
+ }
+
+ // =================================================================
+
+ /** See {@link Message.Builder#clear()}. */
+ public void clear() {
+ fields.clear();
+ }
+
+ /**
+ * Get a simple map containing all the fields.
+ */
+ public Map<FieldDescriptorType, Object> getAllFields() {
+ return Collections.unmodifiableMap(fields);
+ }
+
+ /**
+ * Get an iterator to the field map. This iterator should not be leaked
+ * out of the protobuf library as it is not protected from mutation.
+ */
+ public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
+ return fields.entrySet().iterator();
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message#hasField(Descriptors.FieldDescriptor)}.
+ */
+ public boolean hasField(final FieldDescriptorType descriptor) {
+ if (descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "hasField() can only be called on non-repeated fields.");
+ }
+
+ return fields.get(descriptor) != null;
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message#getField(Descriptors.FieldDescriptor)}. This method
+ * returns {@code null} if the field is not set; in this case it is up
+ * to the caller to fetch the field's default value.
+ */
+ public Object getField(final FieldDescriptorType descriptor) {
+ return fields.get(descriptor);
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message.Builder#setField(Descriptors.FieldDescriptor,Object)}.
+ */
+ @SuppressWarnings("unchecked")
+ public void setField(final FieldDescriptorType descriptor,
+ Object value) {
+ if (descriptor.isRepeated()) {
+ if (!(value instanceof List)) {
+ throw new IllegalArgumentException(
+ "Wrong object type used with protocol message reflection.");
+ }
+
+ // Wrap the contents in a new list so that the caller cannot change
+ // the list's contents after setting it.
+ final List newList = new ArrayList();
+ newList.addAll((List)value);
+ for (final Object element : newList) {
+ verifyType(descriptor.getLiteType(), element);
+ }
+ value = newList;
+ } else {
+ verifyType(descriptor.getLiteType(), value);
+ }
+
+ fields.put(descriptor, value);
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message.Builder#clearField(Descriptors.FieldDescriptor)}.
+ */
+ public void clearField(final FieldDescriptorType descriptor) {
+ fields.remove(descriptor);
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}.
+ */
+ public int getRepeatedFieldCount(final FieldDescriptorType descriptor) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "getRepeatedField() can only be called on repeated fields.");
+ }
+
+ final Object value = fields.get(descriptor);
+ if (value == null) {
+ return 0;
+ } else {
+ return ((List) value).size();
+ }
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}.
+ */
+ public Object getRepeatedField(final FieldDescriptorType descriptor,
+ final int index) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "getRepeatedField() can only be called on repeated fields.");
+ }
+
+ final Object value = fields.get(descriptor);
+
+ if (value == null) {
+ throw new IndexOutOfBoundsException();
+ } else {
+ return ((List) value).get(index);
+ }
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message.Builder#setRepeatedField(Descriptors.FieldDescriptor,int,Object)}.
+ */
+ @SuppressWarnings("unchecked")
+ public void setRepeatedField(final FieldDescriptorType descriptor,
+ final int index,
+ final Object value) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "getRepeatedField() can only be called on repeated fields.");
+ }
+
+ final Object list = fields.get(descriptor);
+ if (list == null) {
+ throw new IndexOutOfBoundsException();
+ }
+
+ verifyType(descriptor.getLiteType(), value);
+ ((List) list).set(index, value);
+ }
+
+ /**
+ * Useful for implementing
+ * {@link Message.Builder#addRepeatedField(Descriptors.FieldDescriptor,Object)}.
+ */
+ @SuppressWarnings("unchecked")
+ public void addRepeatedField(final FieldDescriptorType descriptor,
+ final Object value) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "addRepeatedField() can only be called on repeated fields.");
+ }
+
+ verifyType(descriptor.getLiteType(), value);
+
+ final Object existingValue = fields.get(descriptor);
+ List list;
+ if (existingValue == null) {
+ list = new ArrayList();
+ fields.put(descriptor, list);
+ } else {
+ list = (List) existingValue;
+ }
+
+ list.add(value);
+ }
+
+ /**
+ * Verifies that the given object is of the correct type to be a valid
+ * value for the given field. (For repeated fields, this checks if the
+ * object is the right type to be one element of the field.)
+ *
+ * @throws IllegalArgumentException The value is not of the right type.
+ */
+ private static void verifyType(final WireFormat.FieldType type,
+ final Object value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+
+ boolean isValid = false;
+ switch (type.getJavaType()) {
+ case INT: isValid = value instanceof Integer ; break;
+ case LONG: isValid = value instanceof Long ; break;
+ case FLOAT: isValid = value instanceof Float ; break;
+ case DOUBLE: isValid = value instanceof Double ; break;
+ case BOOLEAN: isValid = value instanceof Boolean ; break;
+ case STRING: isValid = value instanceof String ; break;
+ case BYTE_STRING: isValid = value instanceof ByteString; break;
+ case ENUM:
+ // TODO(kenton): Caller must do type checking here, I guess.
+ isValid = value instanceof Internal.EnumLite;
+ break;
+ case MESSAGE:
+ // TODO(kenton): Caller must do type checking here, I guess.
+ isValid = value instanceof MessageLite;
+ break;
+ }
+
+ if (!isValid) {
+ // TODO(kenton): When chaining calls to setField(), it can be hard to
+ // tell from the stack trace which exact call failed, since the whole
+ // chain is considered one line of code. It would be nice to print
+ // more information here, e.g. naming the field. We used to do that.
+ // But we can't now that FieldSet doesn't use descriptors. Maybe this
+ // isn't a big deal, though, since it would only really apply when using
+ // reflection and generally people don't chain reflection setters.
+ throw new IllegalArgumentException(
+ "Wrong object type used with protocol message reflection.");
+ }
+ }
+
+ // =================================================================
+ // Parsing and serialization
+
+ /**
+ * See {@link Message#isInitialized()}. Note: Since {@code FieldSet}
+ * itself does not have any way of knowing about required fields that
+ * aren't actually present in the set, it is up to the caller to check
+ * that all required fields are present.
+ */
+ @SuppressWarnings("unchecked")
+ public boolean isInitialized() {
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ final FieldDescriptorType descriptor = entry.getKey();
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+ if (descriptor.isRepeated()) {
+ for (final MessageLite element:
+ (List<MessageLite>) entry.getValue()) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (!((MessageLite) entry.getValue()).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /**
+ * Given a field type, return the wire type.
+ *
+ * @returns One of the {@code WIRETYPE_} constants defined in
+ * {@link WireFormat}.
+ */
+ static int getWireFormatForFieldType(final WireFormat.FieldType type,
+ boolean isPacked) {
+ if (isPacked) {
+ return WireFormat.WIRETYPE_LENGTH_DELIMITED;
+ } else {
+ return type.getWireType();
+ }
+ }
+
+ /**
+ * Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
+ */
+ @SuppressWarnings("unchecked")
+ public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ other.fields.entrySet()) {
+ final FieldDescriptorType descriptor = entry.getKey();
+ final Object otherValue = entry.getValue();
+
+ if (descriptor.isRepeated()) {
+ Object value = fields.get(descriptor);
+ if (value == null) {
+ // Our list is empty, but we still need to make a defensive copy of
+ // the other list since we don't know if the other FieldSet is still
+ // mutable.
+ fields.put(descriptor, new ArrayList((List) otherValue));
+ } else {
+ // Concatenate the lists.
+ ((List) value).addAll((List) otherValue);
+ }
+ } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
+ Object value = fields.get(descriptor);
+ if (value == null) {
+ fields.put(descriptor, otherValue);
+ } else {
+ // Merge the messages.
+ fields.put(descriptor,
+ descriptor.internalMergeFrom(
+ ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
+ .build());
+ }
+
+ } else {
+ fields.put(descriptor, otherValue);
+ }
+ }
+ }
+
+ // TODO(kenton): Move static parsing and serialization methods into some
+ // other class. Probably WireFormat.
+
+ /**
+ * Read a field of any primitive type from a CodedInputStream. Enums,
+ * groups, and embedded messages are not handled by this method.
+ *
+ * @param input The stream from which to read.
+ * @param type Declared type of the field.
+ * @return An object representing the field's value, of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ public static Object readPrimitiveField(
+ CodedInputStream input,
+ final WireFormat.FieldType type) throws IOException {
+ switch (type) {
+ case DOUBLE : return input.readDouble ();
+ case FLOAT : return input.readFloat ();
+ case INT64 : return input.readInt64 ();
+ case UINT64 : return input.readUInt64 ();
+ case INT32 : return input.readInt32 ();
+ case FIXED64 : return input.readFixed64 ();
+ case FIXED32 : return input.readFixed32 ();
+ case BOOL : return input.readBool ();
+ case STRING : return input.readString ();
+ case BYTES : return input.readBytes ();
+ case UINT32 : return input.readUInt32 ();
+ case SFIXED32: return input.readSFixed32();
+ case SFIXED64: return input.readSFixed64();
+ case SINT32 : return input.readSInt32 ();
+ case SINT64 : return input.readSInt64 ();
+
+ case GROUP:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle nested groups.");
+ case MESSAGE:
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle embedded messages.");
+ case ENUM:
+ // We don't handle enums because we don't know what to do if the
+ // value is not recognized.
+ throw new IllegalArgumentException(
+ "readPrimitiveField() cannot handle enums.");
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
+
+ /** See {@link Message#writeTo(CodedOutputStream)}. */
+ public void writeTo(final CodedOutputStream output)
+ throws IOException {
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ writeField(entry.getKey(), entry.getValue(), output);
+ }
+ }
+
+ /**
+ * Like {@link #writeTo} but uses MessageSet wire format.
+ */
+ public void writeMessageSetTo(final CodedOutputStream output)
+ throws IOException {
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ final FieldDescriptorType descriptor = entry.getKey();
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
+ !descriptor.isRepeated() && !descriptor.isPacked()) {
+ output.writeMessageSetExtension(entry.getKey().getNumber(),
+ (MessageLite) entry.getValue());
+ } else {
+ writeField(descriptor, entry.getValue(), output);
+ }
+ }
+ }
+
+ /**
+ * Write a single tag-value pair to the stream.
+ *
+ * @param output The output stream.
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ private static void writeElement(final CodedOutputStream output,
+ final WireFormat.FieldType type,
+ final int number,
+ final Object value) throws IOException {
+ // Special case for groups, which need a start and end tag; other fields
+ // can just use writeTag() and writeFieldNoTag().
+ if (type == WireFormat.FieldType.GROUP) {
+ output.writeGroup(number, (MessageLite) value);
+ } else {
+ output.writeTag(number, getWireFormatForFieldType(type, false));
+ writeElementNoTag(output, type, value);
+ }
+ }
+
+ /**
+ * Write a field of arbitrary type, without its tag, to the stream.
+ *
+ * @param output The output stream.
+ * @param type The field's type.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ private static void writeElementNoTag(
+ final CodedOutputStream output,
+ final WireFormat.FieldType type,
+ final Object value) throws IOException {
+ switch (type) {
+ case DOUBLE : output.writeDoubleNoTag ((Double ) value); break;
+ case FLOAT : output.writeFloatNoTag ((Float ) value); break;
+ case INT64 : output.writeInt64NoTag ((Long ) value); break;
+ case UINT64 : output.writeUInt64NoTag ((Long ) value); break;
+ case INT32 : output.writeInt32NoTag ((Integer ) value); break;
+ case FIXED64 : output.writeFixed64NoTag ((Long ) value); break;
+ case FIXED32 : output.writeFixed32NoTag ((Integer ) value); break;
+ case BOOL : output.writeBoolNoTag ((Boolean ) value); break;
+ case STRING : output.writeStringNoTag ((String ) value); break;
+ case GROUP : output.writeGroupNoTag ((MessageLite) value); break;
+ case MESSAGE : output.writeMessageNoTag ((MessageLite) value); break;
+ case BYTES : output.writeBytesNoTag ((ByteString ) value); break;
+ case UINT32 : output.writeUInt32NoTag ((Integer ) value); break;
+ case SFIXED32: output.writeSFixed32NoTag((Integer ) value); break;
+ case SFIXED64: output.writeSFixed64NoTag((Long ) value); break;
+ case SINT32 : output.writeSInt32NoTag ((Integer ) value); break;
+ case SINT64 : output.writeSInt64NoTag ((Long ) value); break;
+
+ case ENUM:
+ output.writeEnumNoTag(((Internal.EnumLite) value).getNumber());
+ break;
+ }
+ }
+
+ /** Write a single field. */
+ public static void writeField(final FieldDescriptorLite<?> descriptor,
+ final Object value,
+ final CodedOutputStream output)
+ throws IOException {
+ WireFormat.FieldType type = descriptor.getLiteType();
+ int number = descriptor.getNumber();
+ if (descriptor.isRepeated()) {
+ final List valueList = (List)value;
+ if (descriptor.isPacked()) {
+ output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ // Compute the total data size so the length can be written.
+ int dataSize = 0;
+ for (final Object element : valueList) {
+ dataSize += computeElementSizeNoTag(type, element);
+ }
+ output.writeRawVarint32(dataSize);
+ // Write the data itself, without any tags.
+ for (final Object element : valueList) {
+ writeElementNoTag(output, type, element);
+ }
+ } else {
+ for (final Object element : valueList) {
+ writeElement(output, type, number, element);
+ }
+ }
+ } else {
+ writeElement(output, type, number, value);
+ }
+ }
+
+ /**
+ * See {@link Message#getSerializedSize()}. It's up to the caller to cache
+ * the resulting size if desired.
+ */
+ public int getSerializedSize() {
+ int size = 0;
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ size += computeFieldSize(entry.getKey(), entry.getValue());
+ }
+ return size;
+ }
+
+ /**
+ * Like {@link #getSerializedSize} but uses MessageSet wire format.
+ */
+ public int getMessageSetSerializedSize() {
+ int size = 0;
+ for (final Map.Entry<FieldDescriptorType, Object> entry:
+ fields.entrySet()) {
+ final FieldDescriptorType descriptor = entry.getKey();
+ if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
+ !descriptor.isRepeated() && !descriptor.isPacked()) {
+ size += CodedOutputStream.computeMessageSetExtensionSize(
+ entry.getKey().getNumber(), (MessageLite) entry.getValue());
+ } else {
+ size += computeFieldSize(descriptor, entry.getValue());
+ }
+ }
+ return size;
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * single tag/value pair of arbitrary type.
+ *
+ * @param type The field's type.
+ * @param number The field's number.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ private static int computeElementSize(
+ final WireFormat.FieldType type,
+ final int number, final Object value) {
+ int tagSize = CodedOutputStream.computeTagSize(number);
+ if (type == WireFormat.FieldType.GROUP) {
+ tagSize *= 2;
+ }
+ return tagSize + computeElementSizeNoTag(type, value);
+ }
+
+ /**
+ * Compute the number of bytes that would be needed to encode a
+ * particular value of arbitrary type, excluding tag.
+ *
+ * @param type The field's type.
+ * @param value Object representing the field's value. Must be of the exact
+ * type which would be returned by
+ * {@link Message#getField(Descriptors.FieldDescriptor)} for
+ * this field.
+ */
+ private static int computeElementSizeNoTag(
+ final WireFormat.FieldType type, final Object value) {
+ switch (type) {
+ // Note: Minor violation of 80-char limit rule here because this would
+ // actually be harder to read if we wrapped the lines.
+ case DOUBLE : return CodedOutputStream.computeDoubleSizeNoTag ((Double )value);
+ case FLOAT : return CodedOutputStream.computeFloatSizeNoTag ((Float )value);
+ case INT64 : return CodedOutputStream.computeInt64SizeNoTag ((Long )value);
+ case UINT64 : return CodedOutputStream.computeUInt64SizeNoTag ((Long )value);
+ case INT32 : return CodedOutputStream.computeInt32SizeNoTag ((Integer )value);
+ case FIXED64 : return CodedOutputStream.computeFixed64SizeNoTag ((Long )value);
+ case FIXED32 : return CodedOutputStream.computeFixed32SizeNoTag ((Integer )value);
+ case BOOL : return CodedOutputStream.computeBoolSizeNoTag ((Boolean )value);
+ case STRING : return CodedOutputStream.computeStringSizeNoTag ((String )value);
+ case GROUP : return CodedOutputStream.computeGroupSizeNoTag ((MessageLite)value);
+ case MESSAGE : return CodedOutputStream.computeMessageSizeNoTag ((MessageLite)value);
+ case BYTES : return CodedOutputStream.computeBytesSizeNoTag ((ByteString )value);
+ case UINT32 : return CodedOutputStream.computeUInt32SizeNoTag ((Integer )value);
+ case SFIXED32: return CodedOutputStream.computeSFixed32SizeNoTag((Integer )value);
+ case SFIXED64: return CodedOutputStream.computeSFixed64SizeNoTag((Long )value);
+ case SINT32 : return CodedOutputStream.computeSInt32SizeNoTag ((Integer )value);
+ case SINT64 : return CodedOutputStream.computeSInt64SizeNoTag ((Long )value);
+
+ case ENUM:
+ return CodedOutputStream.computeEnumSizeNoTag(
+ ((Internal.EnumLite) value).getNumber());
+ }
+
+ throw new RuntimeException(
+ "There is no way to get here, but the compiler thinks otherwise.");
+ }
+
+ /**
+ * Compute the number of bytes needed to encode a particular field.
+ */
+ public static int computeFieldSize(final FieldDescriptorLite<?> descriptor,
+ final Object value) {
+ WireFormat.FieldType type = descriptor.getLiteType();
+ int number = descriptor.getNumber();
+ if (descriptor.isRepeated()) {
+ if (descriptor.isPacked()) {
+ int dataSize = 0;
+ for (final Object element : (List)value) {
+ dataSize += computeElementSizeNoTag(type, element);
+ }
+ return dataSize +
+ CodedOutputStream.computeTagSize(number) +
+ CodedOutputStream.computeRawVarint32Size(dataSize);
+ } else {
+ int size = 0;
+ for (final Object element : (List)value) {
+ size += computeElementSize(type, number, element);
+ }
+ return size;
+ }
+ } else {
+ return computeElementSize(type, number, value);
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessage.java b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
new file mode 100644
index 0000000..4994faa
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessage.java
@@ -0,0 +1,1318 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * All generated protocol message classes extend this class. This class
+ * implements most of the Message and Builder interfaces using Java reflection.
+ * Users can ignore this class and pretend that generated messages implement
+ * the Message interface directly.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessage extends AbstractMessage {
+ protected GeneratedMessage() {}
+
+ private UnknownFieldSet unknownFields = UnknownFieldSet.getDefaultInstance();
+
+ /**
+ * Get the FieldAccessorTable for this type. We can't have the message
+ * class pass this in to the constructor because of bootstrapping trouble
+ * with DescriptorProtos.
+ */
+ protected abstract FieldAccessorTable internalGetFieldAccessorTable();
+
+ public Descriptor getDescriptorForType() {
+ return internalGetFieldAccessorTable().descriptor;
+ }
+
+ /** Internal helper which returns a mutable map. */
+ private Map<FieldDescriptor, Object> getAllFieldsMutable() {
+ final TreeMap<FieldDescriptor, Object> result =
+ new TreeMap<FieldDescriptor, Object>();
+ final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
+ for (final FieldDescriptor field : descriptor.getFields()) {
+ if (field.isRepeated()) {
+ final List value = (List) getField(field);
+ if (!value.isEmpty()) {
+ result.put(field, value);
+ }
+ } else {
+ if (hasField(field)) {
+ result.put(field, getField(field));
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ for (final FieldDescriptor field : getDescriptorForType().getFields()) {
+ // Check that all required fields are present.
+ if (field.isRequired()) {
+ if (!hasField(field)) {
+ return false;
+ }
+ }
+ // Check that embedded messages are initialized.
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ if (field.isRepeated()) {
+ @SuppressWarnings("unchecked") final
+ List<Message> messageList = (List<Message>) getField(field);
+ for (final Message element : messageList) {
+ if (!element.isInitialized()) {
+ return false;
+ }
+ }
+ } else {
+ if (hasField(field) && !((Message) getField(field)).isInitialized()) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return Collections.unmodifiableMap(getAllFieldsMutable());
+ }
+
+ public boolean hasField(final FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).has(this);
+ }
+
+ public Object getField(final FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).get(this);
+ }
+
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field)
+ .getRepeatedCount(this);
+ }
+
+ public Object getRepeatedField(final FieldDescriptor field, final int index) {
+ return internalGetFieldAccessorTable().getField(field)
+ .getRepeated(this, index);
+ }
+
+ public final UnknownFieldSet getUnknownFields() {
+ return unknownFields;
+ }
+
+ @SuppressWarnings("unchecked")
+ public abstract static class Builder <BuilderType extends Builder>
+ extends AbstractMessage.Builder<BuilderType> {
+ protected Builder() {}
+
+ // This is implemented here only to work around an apparent bug in the
+ // Java compiler and/or build system. See bug #1898463. The mere presence
+ // of this dummy clone() implementation makes it go away.
+ @Override
+ public BuilderType clone() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
+ }
+
+ /**
+ * Get the message being built. We don't just pass this to the
+ * constructor because it becomes null when build() is called.
+ */
+ protected abstract GeneratedMessage internalGetResult();
+
+ /**
+ * Get the FieldAccessorTable for this type. We can't have the message
+ * class pass this in to the constructor because of bootstrapping trouble
+ * with DescriptorProtos.
+ */
+ private FieldAccessorTable internalGetFieldAccessorTable() {
+ return internalGetResult().internalGetFieldAccessorTable();
+ }
+
+ public Descriptor getDescriptorForType() {
+ return internalGetFieldAccessorTable().descriptor;
+ }
+
+ public Map<FieldDescriptor, Object> getAllFields() {
+ return internalGetResult().getAllFields();
+ }
+
+ public Message.Builder newBuilderForField(
+ final FieldDescriptor field) {
+ return internalGetFieldAccessorTable().getField(field).newBuilder();
+ }
+
+ public boolean hasField(final FieldDescriptor field) {
+ return internalGetResult().hasField(field);
+ }
+
+ public Object getField(final FieldDescriptor field) {
+ if (field.isRepeated()) {
+ // The underlying list object is still modifiable at this point.
+ // Make sure not to expose the modifiable list to the caller.
+ return Collections.unmodifiableList(
+ (List) internalGetResult().getField(field));
+ } else {
+ return internalGetResult().getField(field);
+ }
+ }
+
+ public BuilderType setField(final FieldDescriptor field,
+ final Object value) {
+ internalGetFieldAccessorTable().getField(field).set(this, value);
+ return (BuilderType) this;
+ }
+
+ public BuilderType clearField(final FieldDescriptor field) {
+ internalGetFieldAccessorTable().getField(field).clear(this);
+ return (BuilderType) this;
+ }
+
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
+ return internalGetResult().getRepeatedFieldCount(field);
+ }
+
+ public Object getRepeatedField(final FieldDescriptor field,
+ final int index) {
+ return internalGetResult().getRepeatedField(field, index);
+ }
+
+ public BuilderType setRepeatedField(final FieldDescriptor field,
+ final int index, final Object value) {
+ internalGetFieldAccessorTable().getField(field)
+ .setRepeated(this, index, value);
+ return (BuilderType) this;
+ }
+
+ public BuilderType addRepeatedField(final FieldDescriptor field,
+ final Object value) {
+ internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
+ return (BuilderType) this;
+ }
+
+ public final UnknownFieldSet getUnknownFields() {
+ return internalGetResult().unknownFields;
+ }
+
+ public final BuilderType setUnknownFields(
+ final UnknownFieldSet unknownFields) {
+ internalGetResult().unknownFields = unknownFields;
+ return (BuilderType) this;
+ }
+
+ @Override
+ public final BuilderType mergeUnknownFields(
+ final UnknownFieldSet unknownFields) {
+ final GeneratedMessage result = internalGetResult();
+ result.unknownFields =
+ UnknownFieldSet.newBuilder(result.unknownFields)
+ .mergeFrom(unknownFields)
+ .build();
+ return (BuilderType) this;
+ }
+
+ public boolean isInitialized() {
+ return internalGetResult().isInitialized();
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(
+ final CodedInputStream input,
+ final UnknownFieldSet.Builder unknownFields,
+ final ExtensionRegistryLite extensionRegistry,
+ final int tag) throws IOException {
+ return unknownFields.mergeFieldFrom(tag, input);
+ }
+ }
+
+ // =================================================================
+ // Extensions-related stuff
+
+ /**
+ * Generated message classes for message types that contain extension ranges
+ * subclass this.
+ *
+ * <p>This class implements type-safe accessors for extensions. They
+ * implement all the same operations that you can do with normal fields --
+ * e.g. "has", "get", and "getCount" -- but for extensions. The extensions
+ * are identified using instances of the class {@link GeneratedExtension};
+ * the protocol compiler generates a static instance of this class for every
+ * extension in its input. Through the magic of generics, all is made
+ * type-safe.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then you might write code like:
+ *
+ * <pre>
+ * MyProto.Foo foo = getFoo();
+ * int i = foo.getExtension(MyProto.bar);
+ * </pre>
+ *
+ * <p>See also {@link ExtendableBuilder}.
+ */
+ public abstract static class ExtendableMessage<
+ MessageType extends ExtendableMessage>
+ extends GeneratedMessage {
+ protected ExtendableMessage() {}
+ private final FieldSet<FieldDescriptor> extensions = FieldSet.newFieldSet();
+
+ private void verifyExtensionContainingType(
+ final GeneratedExtension<MessageType, ?> extension) {
+ if (extension.getDescriptor().getContainingType() !=
+ getDescriptorForType()) {
+ // This can only happen if someone uses unchecked operations.
+ throw new IllegalArgumentException(
+ "Extension is for type \"" +
+ extension.getDescriptor().getContainingType().getFullName() +
+ "\" which does not match message type \"" +
+ getDescriptorForType().getFullName() + "\".");
+ }
+ }
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ verifyExtensionContainingType(extension);
+ return extensions.hasField(extension.getDescriptor());
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ final GeneratedExtension<MessageType, List<Type>> extension) {
+ verifyExtensionContainingType(extension);
+ final FieldDescriptor descriptor = extension.getDescriptor();
+ return extensions.getRepeatedFieldCount(descriptor);
+ }
+
+ /** Get the value of an extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, Type> extension) {
+ verifyExtensionContainingType(extension);
+ FieldDescriptor descriptor = extension.getDescriptor();
+ final Object value = extensions.getField(descriptor);
+ if (value == null) {
+ if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ return (Type) extension.getMessageDefaultInstance();
+ } else {
+ return (Type) extension.fromReflectionType(
+ descriptor.getDefaultValue());
+ }
+ } else {
+ return (Type) extension.fromReflectionType(value);
+ }
+ }
+
+ /** Get one element of a repeated extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index) {
+ verifyExtensionContainingType(extension);
+ FieldDescriptor descriptor = extension.getDescriptor();
+ return (Type) extension.singularFromReflectionType(
+ extensions.getRepeatedField(descriptor, index));
+ }
+
+ /** Called by subclasses to check if all extensions are initialized. */
+ protected boolean extensionsAreInitialized() {
+ return extensions.isInitialized();
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return super.isInitialized() && extensionsAreInitialized();
+ }
+
+ /**
+ * Used by subclasses to serialize extensions. Extension ranges may be
+ * interleaved with field numbers, but we must write them in canonical
+ * (sorted by field number) order. ExtensionWriter helps us write
+ * individual ranges of extensions at once.
+ */
+ protected class ExtensionWriter {
+ // Imagine how much simpler this code would be if Java iterators had
+ // a way to get the next element without advancing the iterator.
+
+ private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
+ extensions.iterator();
+ private Map.Entry<FieldDescriptor, Object> next;
+ private final boolean messageSetWireFormat;
+
+ private ExtensionWriter(final boolean messageSetWireFormat) {
+ if (iter.hasNext()) {
+ next = iter.next();
+ }
+ this.messageSetWireFormat = messageSetWireFormat;
+ }
+
+ public void writeUntil(final int end, final CodedOutputStream output)
+ throws IOException {
+ while (next != null && next.getKey().getNumber() < end) {
+ FieldDescriptor descriptor = next.getKey();
+ if (messageSetWireFormat && descriptor.getLiteJavaType() ==
+ WireFormat.JavaType.MESSAGE &&
+ !descriptor.isRepeated()) {
+ output.writeMessageSetExtension(descriptor.getNumber(),
+ (Message) next.getValue());
+ } else {
+ FieldSet.writeField(descriptor, next.getValue(), output);
+ }
+ if (iter.hasNext()) {
+ next = iter.next();
+ } else {
+ next = null;
+ }
+ }
+ }
+ }
+
+ protected ExtensionWriter newExtensionWriter() {
+ return new ExtensionWriter(false);
+ }
+ protected ExtensionWriter newMessageSetExtensionWriter() {
+ return new ExtensionWriter(true);
+ }
+
+ /** Called by subclasses to compute the size of extensions. */
+ protected int extensionsSerializedSize() {
+ return extensions.getSerializedSize();
+ }
+ protected int extensionsSerializedSizeAsMessageSet() {
+ return extensions.getMessageSetSerializedSize();
+ }
+
+ // ---------------------------------------------------------------
+ // Reflection
+
+ @Override
+ public Map<FieldDescriptor, Object> getAllFields() {
+ final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
+ result.putAll(extensions.getAllFields());
+ return Collections.unmodifiableMap(result);
+ }
+
+ @Override
+ public boolean hasField(final FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.hasField(field);
+ } else {
+ return super.hasField(field);
+ }
+ }
+
+ @Override
+ public Object getField(final FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ final Object value = extensions.getField(field);
+ if (value == null) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ // Lacking an ExtensionRegistry, we have no way to determine the
+ // extension's real type, so we return a DynamicMessage.
+ return DynamicMessage.getDefaultInstance(field.getMessageType());
+ } else {
+ return field.getDefaultValue();
+ }
+ } else {
+ return value;
+ }
+ } else {
+ return super.getField(field);
+ }
+ }
+
+ @Override
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.getRepeatedFieldCount(field);
+ } else {
+ return super.getRepeatedFieldCount(field);
+ }
+ }
+
+ @Override
+ public Object getRepeatedField(final FieldDescriptor field,
+ final int index) {
+ if (field.isExtension()) {
+ verifyContainingType(field);
+ return extensions.getRepeatedField(field, index);
+ } else {
+ return super.getRepeatedField(field, index);
+ }
+ }
+
+ private void verifyContainingType(final FieldDescriptor field) {
+ if (field.getContainingType() != getDescriptorForType()) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ }
+ }
+ }
+
+ /**
+ * Generated message builders for message types that contain extension ranges
+ * subclass this.
+ *
+ * <p>This class implements type-safe accessors for extensions. They
+ * implement all the same operations that you can do with normal fields --
+ * e.g. "get", "set", and "add" -- but for extensions. The extensions are
+ * identified using instances of the class {@link GeneratedExtension}; the
+ * protocol compiler generates a static instance of this class for every
+ * extension in its input. Through the magic of generics, all is made
+ * type-safe.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then you might write code like:
+ *
+ * <pre>
+ * MyProto.Foo foo =
+ * MyProto.Foo.newBuilder()
+ * .setExtension(MyProto.bar, 123)
+ * .build();
+ * </pre>
+ *
+ * <p>See also {@link ExtendableMessage}.
+ */
+ @SuppressWarnings("unchecked")
+ public abstract static class ExtendableBuilder<
+ MessageType extends ExtendableMessage,
+ BuilderType extends ExtendableBuilder>
+ extends Builder<BuilderType> {
+ protected ExtendableBuilder() {}
+
+ // This is implemented here only to work around an apparent bug in the
+ // Java compiler and/or build system. See bug #1898463. The mere presence
+ // of this dummy clone() implementation makes it go away.
+ @Override
+ public BuilderType clone() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
+ }
+
+ @Override
+ protected abstract ExtendableMessage<MessageType> internalGetResult();
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ return internalGetResult().hasExtension(extension);
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ final GeneratedExtension<MessageType, List<Type>> extension) {
+ return internalGetResult().getExtensionCount(extension);
+ }
+
+ /** Get the value of an extension. */
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, Type> extension) {
+ return internalGetResult().getExtension(extension);
+ }
+
+ /** Get one element of a repeated extension. */
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index) {
+ return internalGetResult().getExtension(extension, index);
+ }
+
+ /** Set the value of an extension. */
+ public final <Type> BuilderType setExtension(
+ final GeneratedExtension<MessageType, Type> extension,
+ final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ final FieldDescriptor descriptor = extension.getDescriptor();
+ message.extensions.setField(descriptor,
+ extension.toReflectionType(value));
+ return (BuilderType) this;
+ }
+
+ /** Set the value of one element of a repeated extension. */
+ public final <Type> BuilderType setExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index, final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ final FieldDescriptor descriptor = extension.getDescriptor();
+ message.extensions.setRepeatedField(
+ descriptor, index,
+ extension.singularToReflectionType(value));
+ return (BuilderType) this;
+ }
+
+ /** Append a value to a repeated extension. */
+ public final <Type> BuilderType addExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ final FieldDescriptor descriptor = extension.getDescriptor();
+ message.extensions.addRepeatedField(
+ descriptor, extension.singularToReflectionType(value));
+ return (BuilderType) this;
+ }
+
+ /** Clear an extension. */
+ public final <Type> BuilderType clearExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.clearField(extension.getDescriptor());
+ return (BuilderType) this;
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field or an extension.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ @Override
+ protected boolean parseUnknownField(
+ final CodedInputStream input,
+ final UnknownFieldSet.Builder unknownFields,
+ final ExtensionRegistryLite extensionRegistry,
+ final int tag) throws IOException {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ return AbstractMessage.Builder.mergeFieldFrom(
+ input, unknownFields, extensionRegistry, this, tag);
+ }
+
+ // ---------------------------------------------------------------
+ // Reflection
+
+ // We don't have to override the get*() methods here because they already
+ // just forward to the underlying message.
+
+ @Override
+ public BuilderType setField(final FieldDescriptor field,
+ final Object value) {
+ if (field.isExtension()) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.setField(field, value);
+ return (BuilderType) this;
+ } else {
+ return super.setField(field, value);
+ }
+ }
+
+ @Override
+ public BuilderType clearField(final FieldDescriptor field) {
+ if (field.isExtension()) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.clearField(field);
+ return (BuilderType) this;
+ } else {
+ return super.clearField(field);
+ }
+ }
+
+ @Override
+ public BuilderType setRepeatedField(final FieldDescriptor field,
+ final int index, final Object value) {
+ if (field.isExtension()) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.setRepeatedField(field, index, value);
+ return (BuilderType) this;
+ } else {
+ return super.setRepeatedField(field, index, value);
+ }
+ }
+
+ @Override
+ public BuilderType addRepeatedField(final FieldDescriptor field,
+ final Object value) {
+ if (field.isExtension()) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyContainingType(field);
+ message.extensions.addRepeatedField(field, value);
+ return (BuilderType) this;
+ } else {
+ return super.addRepeatedField(field, value);
+ }
+ }
+
+ protected final void mergeExtensionFields(final ExtendableMessage other) {
+ internalGetResult().extensions.mergeFrom(other.extensions);
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** For use by generated code only. */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, Type>
+ newGeneratedExtension(final FieldDescriptor descriptor,
+ final Class<Type> type) {
+ if (descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "Must call newRepeatedGeneratedExtension() for repeated types.");
+ }
+ return new GeneratedExtension<ContainingType, Type>(descriptor, type);
+ }
+
+ /** For use by generated code only. */
+ public static <ContainingType extends Message, Type>
+ GeneratedExtension<ContainingType, List<Type>>
+ newRepeatedGeneratedExtension(
+ final FieldDescriptor descriptor, final Class<Type> type) {
+ if (!descriptor.isRepeated()) {
+ throw new IllegalArgumentException(
+ "Must call newGeneratedExtension() for non-repeated types.");
+ }
+ return new GeneratedExtension<ContainingType, List<Type>>(descriptor, type);
+ }
+
+ /**
+ * Type used to represent generated extensions. The protocol compiler
+ * generates a static singleton instance of this class for each extension.
+ *
+ * <p>For example, imagine you have the {@code .proto} file:
+ *
+ * <pre>
+ * option java_class = "MyProto";
+ *
+ * message Foo {
+ * extensions 1000 to max;
+ * }
+ *
+ * extend Foo {
+ * optional int32 bar;
+ * }
+ * </pre>
+ *
+ * <p>Then, {@code MyProto.Foo.bar} has type
+ * {@code GeneratedExtension<MyProto.Foo, Integer>}.
+ *
+ * <p>In general, users should ignore the details of this type, and simply use
+ * these static singletons as parameters to the extension accessors defined
+ * in {@link ExtendableMessage} and {@link ExtendableBuilder}.
+ */
+ public static final class GeneratedExtension<
+ ContainingType extends Message, Type> {
+ // TODO(kenton): Find ways to avoid using Java reflection within this
+ // class. Also try to avoid suppressing unchecked warnings.
+
+ private GeneratedExtension(final FieldDescriptor descriptor,
+ final Class type) {
+ if (!descriptor.isExtension()) {
+ throw new IllegalArgumentException(
+ "GeneratedExtension given a regular (non-extension) field.");
+ }
+
+ this.descriptor = descriptor;
+ this.type = type;
+
+ switch (descriptor.getJavaType()) {
+ case MESSAGE:
+ enumValueOf = null;
+ enumGetValueDescriptor = null;
+ messageDefaultInstance =
+ (Message) invokeOrDie(getMethodOrDie(type, "getDefaultInstance"),
+ null);
+ break;
+ case ENUM:
+ enumValueOf = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ enumGetValueDescriptor = getMethodOrDie(type, "getValueDescriptor");
+ messageDefaultInstance = null;
+ break;
+ default:
+ enumValueOf = null;
+ enumGetValueDescriptor = null;
+ messageDefaultInstance = null;
+ break;
+ }
+ }
+
+ private final FieldDescriptor descriptor;
+ private final Class type;
+ private final Method enumValueOf;
+ private final Method enumGetValueDescriptor;
+ private final Message messageDefaultInstance;
+
+ public FieldDescriptor getDescriptor() { return descriptor; }
+
+ /**
+ * If the extension is an embedded message or group, returns the default
+ * instance of the message.
+ */
+ @SuppressWarnings("unchecked")
+ public Message getMessageDefaultInstance() {
+ return messageDefaultInstance;
+ }
+
+ /**
+ * Convert from the type used by the reflection accessors to the type used
+ * by native accessors. E.g., for enums, the reflection accessors use
+ * EnumValueDescriptors but the native accessors use the generated enum
+ * type.
+ */
+ @SuppressWarnings("unchecked")
+ private Object fromReflectionType(final Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE ||
+ descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ // Must convert the whole list.
+ final List result = new ArrayList();
+ for (final Object element : (List) value) {
+ result.add(singularFromReflectionType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularFromReflectionType(value);
+ }
+ }
+
+ /**
+ * Like {@link #fromReflectionType(Object)}, but if the type is a repeated
+ * type, this converts a single element.
+ */
+ private Object singularFromReflectionType(final Object value) {
+ switch (descriptor.getJavaType()) {
+ case MESSAGE:
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // It seems the copy of the embedded message stored inside the
+ // extended message is not of the exact type the user was
+ // expecting. This can happen if a user defines a
+ // GeneratedExtension manually and gives it a different type.
+ // This should not happen in normal use. But, to be nice, we'll
+ // copy the message to whatever type the caller was expecting.
+ return messageDefaultInstance.newBuilderForType()
+ .mergeFrom((Message) value).build();
+ }
+ case ENUM:
+ return invokeOrDie(enumValueOf, null, (EnumValueDescriptor) value);
+ default:
+ return value;
+ }
+ }
+
+ /**
+ * Convert from the type used by the native accessors to the type used
+ * by reflection accessors. E.g., for enums, the reflection accessors use
+ * EnumValueDescriptors but the native accessors use the generated enum
+ * type.
+ */
+ @SuppressWarnings("unchecked")
+ private Object toReflectionType(final Object value) {
+ if (descriptor.isRepeated()) {
+ if (descriptor.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ // Must convert the whole list.
+ final List result = new ArrayList();
+ for (final Object element : (List) value) {
+ result.add(singularToReflectionType(element));
+ }
+ return result;
+ } else {
+ return value;
+ }
+ } else {
+ return singularToReflectionType(value);
+ }
+ }
+
+ /**
+ * Like {@link #toReflectionType(Object)}, but if the type is a repeated
+ * type, this converts a single element.
+ */
+ private Object singularToReflectionType(final Object value) {
+ switch (descriptor.getJavaType()) {
+ case ENUM:
+ return invokeOrDie(enumGetValueDescriptor, value);
+ default:
+ return value;
+ }
+ }
+ }
+
+ // =================================================================
+
+ /** Calls Class.getMethod and throws a RuntimeException if it fails. */
+ @SuppressWarnings("unchecked")
+ private static Method getMethodOrDie(
+ final Class clazz, final String name, final Class... params) {
+ try {
+ return clazz.getMethod(name, params);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(
+ "Generated message class \"" + clazz.getName() +
+ "\" missing method \"" + name + "\".", e);
+ }
+ }
+
+ /** Calls invoke and throws a RuntimeException if it fails. */
+ private static Object invokeOrDie(
+ final Method method, final Object object, final Object... params) {
+ try {
+ return method.invoke(object, params);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(
+ "Couldn't use Java reflection to implement protocol message " +
+ "reflection.", e);
+ } catch (InvocationTargetException e) {
+ final Throwable cause = e.getCause();
+ if (cause instanceof RuntimeException) {
+ throw (RuntimeException) cause;
+ } else if (cause instanceof Error) {
+ throw (Error) cause;
+ } else {
+ throw new RuntimeException(
+ "Unexpected exception thrown by generated accessor method.", cause);
+ }
+ }
+ }
+
+ /**
+ * Users should ignore this class. This class provides the implementation
+ * with access to the fields of a message object using Java reflection.
+ */
+ public static final class FieldAccessorTable {
+
+ /**
+ * Construct a FieldAccessorTable for a particular message class. Only
+ * one FieldAccessorTable should ever be constructed per class.
+ *
+ * @param descriptor The type's descriptor.
+ * @param camelCaseNames The camelcase names of all fields in the message.
+ * These are used to derive the accessor method names.
+ * @param messageClass The message type.
+ * @param builderClass The builder type.
+ */
+ public FieldAccessorTable(
+ final Descriptor descriptor,
+ final String[] camelCaseNames,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ this.descriptor = descriptor;
+ fields = new FieldAccessor[descriptor.getFields().size()];
+
+ for (int i = 0; i < fields.length; i++) {
+ final FieldDescriptor field = descriptor.getFields().get(i);
+ if (field.isRepeated()) {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields[i] = new RepeatedMessageFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ fields[i] = new RepeatedEnumFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else {
+ fields[i] = new RepeatedFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ }
+ } else {
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ fields[i] = new SingularMessageFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
+ fields[i] = new SingularEnumFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ } else {
+ fields[i] = new SingularFieldAccessor(
+ field, camelCaseNames[i], messageClass, builderClass);
+ }
+ }
+ }
+ }
+
+ private final Descriptor descriptor;
+ private final FieldAccessor[] fields;
+
+ /** Get the FieldAccessor for a particular field. */
+ private FieldAccessor getField(final FieldDescriptor field) {
+ if (field.getContainingType() != descriptor) {
+ throw new IllegalArgumentException(
+ "FieldDescriptor does not match message type.");
+ } else if (field.isExtension()) {
+ // If this type had extensions, it would subclass ExtendableMessage,
+ // which overrides the reflection interface to handle extensions.
+ throw new IllegalArgumentException(
+ "This type does not have extensions.");
+ }
+ return fields[field.getIndex()];
+ }
+
+ /**
+ * Abstract interface that provides access to a single field. This is
+ * implemented differently depending on the field type and cardinality.
+ */
+ private interface FieldAccessor {
+ Object get(GeneratedMessage message);
+ void set(Builder builder, Object value);
+ Object getRepeated(GeneratedMessage message, int index);
+ void setRepeated(Builder builder,
+ int index, Object value);
+ void addRepeated(Builder builder, Object value);
+ boolean has(GeneratedMessage message);
+ int getRepeatedCount(GeneratedMessage message);
+ void clear(Builder builder);
+ Message.Builder newBuilder();
+ }
+
+ // ---------------------------------------------------------------
+
+ private static class SingularFieldAccessor implements FieldAccessor {
+ SingularFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
+ type = getMethod.getReturnType();
+ setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
+ hasMethod =
+ getMethodOrDie(messageClass, "has" + camelCaseName);
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ }
+
+ // Note: We use Java reflection to call public methods rather than
+ // access private fields directly as this avoids runtime security
+ // checks.
+ protected final Class type;
+ protected final Method getMethod;
+ protected final Method setMethod;
+ protected final Method hasMethod;
+ protected final Method clearMethod;
+
+ public Object get(final GeneratedMessage message) {
+ return invokeOrDie(getMethod, message);
+ }
+ public void set(final Builder builder, final Object value) {
+ invokeOrDie(setMethod, builder, value);
+ }
+ public Object getRepeated(final GeneratedMessage message,
+ final int index) {
+ throw new UnsupportedOperationException(
+ "getRepeatedField() called on a singular field.");
+ }
+ public void setRepeated(final Builder builder,
+ final int index, final Object value) {
+ throw new UnsupportedOperationException(
+ "setRepeatedField() called on a singular field.");
+ }
+ public void addRepeated(final Builder builder, final Object value) {
+ throw new UnsupportedOperationException(
+ "addRepeatedField() called on a singular field.");
+ }
+ public boolean has(final GeneratedMessage message) {
+ return (Boolean) invokeOrDie(hasMethod, message);
+ }
+ public int getRepeatedCount(final GeneratedMessage message) {
+ throw new UnsupportedOperationException(
+ "getRepeatedFieldSize() called on a singular field.");
+ }
+ public void clear(final Builder builder) {
+ invokeOrDie(clearMethod, builder);
+ }
+ public Message.Builder newBuilder() {
+ throw new UnsupportedOperationException(
+ "newBuilderForField() called on a non-Message type.");
+ }
+ }
+
+ private static class RepeatedFieldAccessor implements FieldAccessor {
+ RepeatedFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ getMethod = getMethodOrDie(messageClass,
+ "get" + camelCaseName + "List");
+
+ getRepeatedMethod =
+ getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
+ type = getRepeatedMethod.getReturnType();
+ setRepeatedMethod =
+ getMethodOrDie(builderClass, "set" + camelCaseName,
+ Integer.TYPE, type);
+ addRepeatedMethod =
+ getMethodOrDie(builderClass, "add" + camelCaseName, type);
+ getCountMethod =
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
+
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
+ }
+
+ protected final Class type;
+ protected final Method getMethod;
+ protected final Method getRepeatedMethod;
+ protected final Method setRepeatedMethod;
+ protected final Method addRepeatedMethod;
+ protected final Method getCountMethod;
+ protected final Method clearMethod;
+
+ public Object get(final GeneratedMessage message) {
+ return invokeOrDie(getMethod, message);
+ }
+ public void set(final Builder builder, final Object value) {
+ // Add all the elements individually. This serves two purposes:
+ // 1) Verifies that each element has the correct type.
+ // 2) Insures that the caller cannot modify the list later on and
+ // have the modifications be reflected in the message.
+ clear(builder);
+ for (final Object element : (List) value) {
+ addRepeated(builder, element);
+ }
+ }
+ public Object getRepeated(final GeneratedMessage message,
+ final int index) {
+ return invokeOrDie(getRepeatedMethod, message, index);
+ }
+ public void setRepeated(final Builder builder,
+ final int index, final Object value) {
+ invokeOrDie(setRepeatedMethod, builder, index, value);
+ }
+ public void addRepeated(final Builder builder, final Object value) {
+ invokeOrDie(addRepeatedMethod, builder, value);
+ }
+ public boolean has(final GeneratedMessage message) {
+ throw new UnsupportedOperationException(
+ "hasField() called on a singular field.");
+ }
+ public int getRepeatedCount(final GeneratedMessage message) {
+ return (Integer) invokeOrDie(getCountMethod, message);
+ }
+ public void clear(final Builder builder) {
+ invokeOrDie(clearMethod, builder);
+ }
+ public Message.Builder newBuilder() {
+ throw new UnsupportedOperationException(
+ "newBuilderForField() called on a non-Message type.");
+ }
+ }
+
+ // ---------------------------------------------------------------
+
+ private static final class SingularEnumFieldAccessor
+ extends SingularFieldAccessor {
+ SingularEnumFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ valueOfMethod = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ getValueDescriptorMethod =
+ getMethodOrDie(type, "getValueDescriptor");
+ }
+
+ private Method valueOfMethod;
+ private Method getValueDescriptorMethod;
+
+ @Override
+ public Object get(final GeneratedMessage message) {
+ return invokeOrDie(getValueDescriptorMethod, super.get(message));
+ }
+ @Override
+ public void set(final Builder builder, final Object value) {
+ super.set(builder, invokeOrDie(valueOfMethod, null, value));
+ }
+ }
+
+ private static final class RepeatedEnumFieldAccessor
+ extends RepeatedFieldAccessor {
+ RepeatedEnumFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ valueOfMethod = getMethodOrDie(type, "valueOf",
+ EnumValueDescriptor.class);
+ getValueDescriptorMethod =
+ getMethodOrDie(type, "getValueDescriptor");
+ }
+
+ private final Method valueOfMethod;
+ private final Method getValueDescriptorMethod;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object get(final GeneratedMessage message) {
+ final List newList = new ArrayList();
+ for (final Object element : (List) super.get(message)) {
+ newList.add(invokeOrDie(getValueDescriptorMethod, element));
+ }
+ return Collections.unmodifiableList(newList);
+ }
+ @Override
+ public Object getRepeated(final GeneratedMessage message,
+ final int index) {
+ return invokeOrDie(getValueDescriptorMethod,
+ super.getRepeated(message, index));
+ }
+ @Override
+ public void setRepeated(final Builder builder,
+ final int index, final Object value) {
+ super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
+ value));
+ }
+ @Override
+ public void addRepeated(final Builder builder, final Object value) {
+ super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
+ }
+ }
+
+ // ---------------------------------------------------------------
+
+ private static final class SingularMessageFieldAccessor
+ extends SingularFieldAccessor {
+ SingularMessageFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
+ }
+
+ private final Method newBuilderMethod;
+
+ private Object coerceType(final Object value) {
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // The value is not the exact right message type. However, if it
+ // is an alternative implementation of the same type -- e.g. a
+ // DynamicMessage -- we should accept it. In this case we can make
+ // a copy of the message.
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message) value).build();
+ }
+ }
+
+ @Override
+ public void set(final Builder builder, final Object value) {
+ super.set(builder, coerceType(value));
+ }
+ @Override
+ public Message.Builder newBuilder() {
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+ }
+ }
+
+ private static final class RepeatedMessageFieldAccessor
+ extends RepeatedFieldAccessor {
+ RepeatedMessageFieldAccessor(
+ final FieldDescriptor descriptor, final String camelCaseName,
+ final Class<? extends GeneratedMessage> messageClass,
+ final Class<? extends Builder> builderClass) {
+ super(descriptor, camelCaseName, messageClass, builderClass);
+
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
+ }
+
+ private final Method newBuilderMethod;
+
+ private Object coerceType(final Object value) {
+ if (type.isInstance(value)) {
+ return value;
+ } else {
+ // The value is not the exact right message type. However, if it
+ // is an alternative implementation of the same type -- e.g. a
+ // DynamicMessage -- we should accept it. In this case we can make
+ // a copy of the message.
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
+ .mergeFrom((Message) value).build();
+ }
+ }
+
+ @Override
+ public void setRepeated(final Builder builder,
+ final int index, final Object value) {
+ super.setRepeated(builder, index, coerceType(value));
+ }
+ @Override
+ public void addRepeated(final Builder builder, final Object value) {
+ super.addRepeated(builder, coerceType(value));
+ }
+ @Override
+ public Message.Builder newBuilder() {
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
new file mode 100644
index 0000000..c68414b
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/GeneratedMessageLite.java
@@ -0,0 +1,539 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Lite version of {@link GeneratedMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public abstract class GeneratedMessageLite extends AbstractMessageLite {
+ protected GeneratedMessageLite() {}
+
+ @SuppressWarnings("unchecked")
+ public abstract static class Builder<MessageType extends GeneratedMessageLite,
+ BuilderType extends Builder>
+ extends AbstractMessageLite.Builder<BuilderType> {
+ protected Builder() {}
+
+ // This is implemented here only to work around an apparent bug in the
+ // Java compiler and/or build system. See bug #1898463. The mere presence
+ // of this dummy clone() implementation makes it go away.
+ @Override
+ public BuilderType clone() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
+ }
+
+ /** All subclasses implement this. */
+ public abstract BuilderType mergeFrom(MessageType message);
+
+ // Defined here for return type covariance.
+ public abstract MessageType getDefaultInstanceForType();
+
+ /**
+ * Get the message being built. We don't just pass this to the
+ * constructor because it becomes null when build() is called.
+ */
+ protected abstract MessageType internalGetResult();
+
+ /**
+ * Called by subclasses to parse an unknown field.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ protected boolean parseUnknownField(
+ final CodedInputStream input,
+ final ExtensionRegistryLite extensionRegistry,
+ final int tag) throws IOException {
+ return input.skipField(tag);
+ }
+ }
+
+ // =================================================================
+ // Extensions-related stuff
+
+ /**
+ * Lite equivalent of {@link GeneratedMessage.ExtendableMessage}.
+ */
+ public abstract static class ExtendableMessage<
+ MessageType extends ExtendableMessage<MessageType>>
+ extends GeneratedMessageLite {
+ protected ExtendableMessage() {}
+ private final FieldSet<ExtensionDescriptor> extensions =
+ FieldSet.newFieldSet();
+
+ private void verifyExtensionContainingType(
+ final GeneratedExtension<MessageType, ?> extension) {
+ if (extension.getContainingTypeDefaultInstance() !=
+ getDefaultInstanceForType()) {
+ // This can only happen if someone uses unchecked operations.
+ throw new IllegalArgumentException(
+ "This extension is for a different message type. Please make " +
+ "sure that you are not suppressing any generics type warnings.");
+ }
+ }
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ verifyExtensionContainingType(extension);
+ return extensions.hasField(extension.descriptor);
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ final GeneratedExtension<MessageType, List<Type>> extension) {
+ verifyExtensionContainingType(extension);
+ return extensions.getRepeatedFieldCount(extension.descriptor);
+ }
+
+ /** Get the value of an extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, Type> extension) {
+ verifyExtensionContainingType(extension);
+ final Object value = extensions.getField(extension.descriptor);
+ if (value == null) {
+ return extension.defaultValue;
+ } else {
+ return (Type) value;
+ }
+ }
+
+ /** Get one element of a repeated extension. */
+ @SuppressWarnings("unchecked")
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index) {
+ verifyExtensionContainingType(extension);
+ return (Type) extensions.getRepeatedField(extension.descriptor, index);
+ }
+
+ /** Called by subclasses to check if all extensions are initialized. */
+ protected boolean extensionsAreInitialized() {
+ return extensions.isInitialized();
+ }
+
+ /**
+ * Used by subclasses to serialize extensions. Extension ranges may be
+ * interleaved with field numbers, but we must write them in canonical
+ * (sorted by field number) order. ExtensionWriter helps us write
+ * individual ranges of extensions at once.
+ */
+ protected class ExtensionWriter {
+ // Imagine how much simpler this code would be if Java iterators had
+ // a way to get the next element without advancing the iterator.
+
+ private final Iterator<Map.Entry<ExtensionDescriptor, Object>> iter =
+ extensions.iterator();
+ private Map.Entry<ExtensionDescriptor, Object> next;
+ private final boolean messageSetWireFormat;
+
+ private ExtensionWriter(boolean messageSetWireFormat) {
+ if (iter.hasNext()) {
+ next = iter.next();
+ }
+ this.messageSetWireFormat = messageSetWireFormat;
+ }
+
+ public void writeUntil(final int end, final CodedOutputStream output)
+ throws IOException {
+ while (next != null && next.getKey().getNumber() < end) {
+ ExtensionDescriptor extension = next.getKey();
+ if (messageSetWireFormat && extension.getLiteJavaType() ==
+ WireFormat.JavaType.MESSAGE &&
+ !extension.isRepeated()) {
+ output.writeMessageSetExtension(extension.getNumber(),
+ (MessageLite) next.getValue());
+ } else {
+ FieldSet.writeField(extension, next.getValue(), output);
+ }
+ if (iter.hasNext()) {
+ next = iter.next();
+ } else {
+ next = null;
+ }
+ }
+ }
+ }
+
+ protected ExtensionWriter newExtensionWriter() {
+ return new ExtensionWriter(false);
+ }
+ protected ExtensionWriter newMessageSetExtensionWriter() {
+ return new ExtensionWriter(true);
+ }
+
+ /** Called by subclasses to compute the size of extensions. */
+ protected int extensionsSerializedSize() {
+ return extensions.getSerializedSize();
+ }
+ protected int extensionsSerializedSizeAsMessageSet() {
+ return extensions.getMessageSetSerializedSize();
+ }
+ }
+
+ /**
+ * Lite equivalent of {@link GeneratedMessage.ExtendableBuilder}.
+ */
+ @SuppressWarnings("unchecked")
+ public abstract static class ExtendableBuilder<
+ MessageType extends ExtendableMessage<MessageType>,
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
+ extends Builder<MessageType, BuilderType> {
+ protected ExtendableBuilder() {}
+
+ // This is implemented here only to work around an apparent bug in the
+ // Java compiler and/or build system. See bug #1898463. The mere presence
+ // of this dummy clone() implementation makes it go away.
+ @Override
+ public BuilderType clone() {
+ throw new UnsupportedOperationException(
+ "This is supposed to be overridden by subclasses.");
+ }
+
+ @Override
+ protected abstract MessageType internalGetResult();
+
+ /** Check if a singular extension is present. */
+ public final boolean hasExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ return internalGetResult().hasExtension(extension);
+ }
+
+ /** Get the number of elements in a repeated extension. */
+ public final <Type> int getExtensionCount(
+ final GeneratedExtension<MessageType, List<Type>> extension) {
+ return internalGetResult().getExtensionCount(extension);
+ }
+
+ /** Get the value of an extension. */
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, Type> extension) {
+ return internalGetResult().getExtension(extension);
+ }
+
+ /** Get one element of a repeated extension. */
+ public final <Type> Type getExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index) {
+ return internalGetResult().getExtension(extension, index);
+ }
+
+ /** Set the value of an extension. */
+ public final <Type> BuilderType setExtension(
+ final GeneratedExtension<MessageType, Type> extension,
+ final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.setField(extension.descriptor, value);
+ return (BuilderType) this;
+ }
+
+ /** Set the value of one element of a repeated extension. */
+ public final <Type> BuilderType setExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final int index, final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.setRepeatedField(extension.descriptor, index, value);
+ return (BuilderType) this;
+ }
+
+ /** Append a value to a repeated extension. */
+ public final <Type> BuilderType addExtension(
+ final GeneratedExtension<MessageType, List<Type>> extension,
+ final Type value) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.addRepeatedField(extension.descriptor, value);
+ return (BuilderType) this;
+ }
+
+ /** Clear an extension. */
+ public final <Type> BuilderType clearExtension(
+ final GeneratedExtension<MessageType, ?> extension) {
+ final ExtendableMessage<MessageType> message = internalGetResult();
+ message.verifyExtensionContainingType(extension);
+ message.extensions.clearField(extension.descriptor);
+ return (BuilderType) this;
+ }
+
+ /**
+ * Called by subclasses to parse an unknown field or an extension.
+ * @return {@code true} unless the tag is an end-group tag.
+ */
+ @Override
+ protected boolean parseUnknownField(
+ final CodedInputStream input,
+ final ExtensionRegistryLite extensionRegistry,
+ final int tag) throws IOException {
+ final FieldSet<ExtensionDescriptor> extensions =
+ internalGetResult().extensions;
+
+ final int wireType = WireFormat.getTagWireType(tag);
+ final int fieldNumber = WireFormat.getTagFieldNumber(tag);
+
+ final GeneratedExtension<MessageType, ?> extension =
+ extensionRegistry.findLiteExtensionByNumber(
+ getDefaultInstanceForType(), fieldNumber);
+
+ if (extension == null || wireType !=
+ FieldSet.getWireFormatForFieldType(
+ extension.descriptor.getLiteType(),
+ extension.descriptor.isPacked())) {
+ // Unknown field or wrong wire type. Skip.
+ return input.skipField(tag);
+ }
+
+ if (extension.descriptor.isPacked()) {
+ final int length = input.readRawVarint32();
+ final int limit = input.pushLimit(length);
+ if (extension.descriptor.getLiteType() == WireFormat.FieldType.ENUM) {
+ while (input.getBytesUntilLimit() > 0) {
+ final int rawValue = input.readEnum();
+ final Object value =
+ extension.descriptor.getEnumType().findValueByNumber(rawValue);
+ if (value == null) {
+ // If the number isn't recognized as a valid value for this
+ // enum, drop it (don't even add it to unknownFields).
+ return true;
+ }
+ extensions.addRepeatedField(extension.descriptor, value);
+ }
+ } else {
+ while (input.getBytesUntilLimit() > 0) {
+ final Object value =
+ FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType());
+ extensions.addRepeatedField(extension.descriptor, value);
+ }
+ }
+ input.popLimit(limit);
+ } else {
+ final Object value;
+ switch (extension.descriptor.getLiteJavaType()) {
+ case MESSAGE: {
+ MessageLite.Builder subBuilder = null;
+ if (!extension.descriptor.isRepeated()) {
+ MessageLite existingValue =
+ (MessageLite) extensions.getField(extension.descriptor);
+ if (existingValue != null) {
+ subBuilder = existingValue.toBuilder();
+ }
+ }
+ if (subBuilder == null) {
+ subBuilder = extension.messageDefaultInstance.newBuilderForType();
+ }
+ if (extension.descriptor.getLiteType() ==
+ WireFormat.FieldType.GROUP) {
+ input.readGroup(extension.getNumber(),
+ subBuilder, extensionRegistry);
+ } else {
+ input.readMessage(subBuilder, extensionRegistry);
+ }
+ value = subBuilder.build();
+ break;
+ }
+ case ENUM:
+ final int rawValue = input.readEnum();
+ value = extension.descriptor.getEnumType()
+ .findValueByNumber(rawValue);
+ // If the number isn't recognized as a valid value for this enum,
+ // drop it.
+ if (value == null) {
+ return true;
+ }
+ break;
+ default:
+ value = FieldSet.readPrimitiveField(input,
+ extension.descriptor.getLiteType());
+ break;
+ }
+
+ if (extension.descriptor.isRepeated()) {
+ extensions.addRepeatedField(extension.descriptor, value);
+ } else {
+ extensions.setField(extension.descriptor, value);
+ }
+ }
+
+ return true;
+ }
+
+ protected final void mergeExtensionFields(final MessageType other) {
+ internalGetResult().extensions.mergeFrom(other.extensions);
+ }
+ }
+
+ // -----------------------------------------------------------------
+
+ /** For use by generated code only. */
+ public static <ContainingType extends MessageLite, Type>
+ GeneratedExtension<ContainingType, Type>
+ newGeneratedExtension(
+ final ContainingType containingTypeDefaultInstance,
+ final Type defaultValue,
+ final MessageLite messageDefaultInstance,
+ final Internal.EnumLiteMap<?> enumTypeMap,
+ final int number,
+ final WireFormat.FieldType type) {
+ return new GeneratedExtension<ContainingType, Type>(
+ containingTypeDefaultInstance, defaultValue, messageDefaultInstance,
+ new ExtensionDescriptor(enumTypeMap, number, type,
+ false /* isRepeated */, false /* isPacked */));
+ }
+
+ /** For use by generated code only. */
+ public static <ContainingType extends MessageLite, Type>
+ GeneratedExtension<ContainingType, List<Type>>
+ newRepeatedGeneratedExtension(
+ final ContainingType containingTypeDefaultInstance,
+ final MessageLite messageDefaultInstance,
+ final Internal.EnumLiteMap<?> enumTypeMap,
+ final int number,
+ final WireFormat.FieldType type,
+ final boolean isPacked) {
+ return new GeneratedExtension<ContainingType, List<Type>>(
+ containingTypeDefaultInstance, Collections.<Type>emptyList(),
+ messageDefaultInstance,
+ new ExtensionDescriptor(
+ enumTypeMap, number, type, true /* isRepeated */, isPacked));
+ }
+
+ private static final class ExtensionDescriptor
+ implements FieldSet.FieldDescriptorLite<
+ ExtensionDescriptor> {
+ private ExtensionDescriptor(
+ final Internal.EnumLiteMap<?> enumTypeMap,
+ final int number,
+ final WireFormat.FieldType type,
+ final boolean isRepeated,
+ final boolean isPacked) {
+ this.enumTypeMap = enumTypeMap;
+ this.number = number;
+ this.type = type;
+ this.isRepeated = isRepeated;
+ this.isPacked = isPacked;
+ }
+
+ private final Internal.EnumLiteMap<?> enumTypeMap;
+ private final int number;
+ private final WireFormat.FieldType type;
+ private final boolean isRepeated;
+ private final boolean isPacked;
+
+ public int getNumber() {
+ return number;
+ }
+
+ public WireFormat.FieldType getLiteType() {
+ return type;
+ }
+
+ public WireFormat.JavaType getLiteJavaType() {
+ return type.getJavaType();
+ }
+
+ public boolean isRepeated() {
+ return isRepeated;
+ }
+
+ public boolean isPacked() {
+ return isPacked;
+ }
+
+ public Internal.EnumLiteMap<?> getEnumType() {
+ return enumTypeMap;
+ }
+
+ @SuppressWarnings("unchecked")
+ public MessageLite.Builder internalMergeFrom(
+ MessageLite.Builder to, MessageLite from) {
+ return ((Builder) to).mergeFrom((GeneratedMessageLite) from);
+ }
+
+ public int compareTo(ExtensionDescriptor other) {
+ return number - other.number;
+ }
+ }
+
+ /**
+ * Lite equivalent to {@link GeneratedMessage.GeneratedExtension}.
+ *
+ * Users should ignore the contents of this class and only use objects of
+ * this type as parameters to extension accessors and ExtensionRegistry.add().
+ */
+ public static final class GeneratedExtension<
+ ContainingType extends MessageLite, Type> {
+ private GeneratedExtension(
+ final ContainingType containingTypeDefaultInstance,
+ final Type defaultValue,
+ final MessageLite messageDefaultInstance,
+ final ExtensionDescriptor descriptor) {
+ this.containingTypeDefaultInstance = containingTypeDefaultInstance;
+ this.defaultValue = defaultValue;
+ this.messageDefaultInstance = messageDefaultInstance;
+ this.descriptor = descriptor;
+ }
+
+ private final ContainingType containingTypeDefaultInstance;
+ private final Type defaultValue;
+ private final MessageLite messageDefaultInstance;
+ private final ExtensionDescriptor descriptor;
+
+ /**
+ * Default instance of the type being extended, used to identify that type.
+ */
+ public ContainingType getContainingTypeDefaultInstance() {
+ return containingTypeDefaultInstance;
+ }
+
+ /** Get the field number. */
+ public int getNumber() {
+ return descriptor.getNumber();
+ }
+
+ /**
+ * If the extension is an embedded message, this is the default instance of
+ * that type.
+ */
+ public MessageLite getMessageDefaultInstance() {
+ return messageDefaultInstance;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Internal.java b/java/src/main/java/com/google/protobuf/Internal.java
new file mode 100644
index 0000000..965465e
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Internal.java
@@ -0,0 +1,121 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.UnsupportedEncodingException;
+
+/**
+ * The classes contained within are used internally by the Protocol Buffer
+ * library and generated message implementations. They are public only because
+ * those generated messages do not reside in the {@code protobuf} package.
+ * Others should not use this class directly.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class Internal {
+ /**
+ * Helper called by generated code to construct default values for string
+ * fields.
+ * <p>
+ * The protocol compiler does not actually contain a UTF-8 decoder -- it
+ * just pushes UTF-8-encoded text around without touching it. The one place
+ * where this presents a problem is when generating Java string literals.
+ * Unicode characters in the string literal would normally need to be encoded
+ * using a Unicode escape sequence, which would require decoding them.
+ * To get around this, protoc instead embeds the UTF-8 bytes into the
+ * generated code and leaves it to the runtime library to decode them.
+ * <p>
+ * It gets worse, though. If protoc just generated a byte array, like:
+ * new byte[] {0x12, 0x34, 0x56, 0x78}
+ * Java actually generates *code* which allocates an array and then fills
+ * in each value. This is much less efficient than just embedding the bytes
+ * directly into the bytecode. To get around this, we need another
+ * work-around. String literals are embedded directly, so protoc actually
+ * generates a string literal corresponding to the bytes. The easiest way
+ * to do this is to use the ISO-8859-1 character set, which corresponds to
+ * the first 256 characters of the Unicode range. Protoc can then use
+ * good old CEscape to generate the string.
+ * <p>
+ * So we have a string literal which represents a set of bytes which
+ * represents another string. This function -- stringDefaultValue --
+ * converts from the generated string to the string we actually want. The
+ * generated code calls this automatically.
+ */
+ public static String stringDefaultValue(String bytes) {
+ try {
+ return new String(bytes.getBytes("ISO-8859-1"), "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // both of the above character sets.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Helper called by generated code to construct default values for bytes
+ * fields.
+ * <p>
+ * This is a lot like {@link #stringDefaultValue}, but for bytes fields.
+ * In this case we only need the second of the two hacks -- allowing us to
+ * embed raw bytes as a string literal with ISO-8859-1 encoding.
+ */
+ public static ByteString bytesDefaultValue(String bytes) {
+ try {
+ return ByteString.copyFrom(bytes.getBytes("ISO-8859-1"));
+ } catch (UnsupportedEncodingException e) {
+ // This should never happen since all JVMs are required to implement
+ // ISO-8859-1.
+ throw new IllegalStateException(
+ "Java VM does not support a standard character set.", e);
+ }
+ }
+
+ /**
+ * Interface for an enum value or value descriptor, to be used in FieldSet.
+ * The lite library stores enum values directly in FieldSets but the full
+ * library stores EnumValueDescriptors in order to better support reflection.
+ */
+ public interface EnumLite {
+ int getNumber();
+ }
+
+ /**
+ * Interface for an object which maps integers to {@link EnumLite}s.
+ * {@link Descriptors.EnumDescriptor} implements this interface by mapping
+ * numbers to {@link Descriptors.EnumValueDescriptor}s. Additionally,
+ * every generated enum type has a static method internalGetValueMap() which
+ * returns an implementation of this type that maps numbers to enum values.
+ */
+ public interface EnumLiteMap<T extends EnumLite> {
+ T findValueByNumber(int number);
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.java
new file mode 100644
index 0000000..90f7ffb
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/InvalidProtocolBufferException.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;
+
+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 InvalidProtocolBufferException extends IOException {
+ private static final long serialVersionUID = -1616151763072450476L;
+
+ public InvalidProtocolBufferException(final String description) {
+ super(description);
+ }
+
+ static InvalidProtocolBufferException truncatedMessage() {
+ return new InvalidProtocolBufferException(
+ "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 InvalidProtocolBufferException negativeSize() {
+ return new InvalidProtocolBufferException(
+ "CodedInputStream encountered an embedded string or message " +
+ "which claimed to have negative size.");
+ }
+
+ static InvalidProtocolBufferException malformedVarint() {
+ return new InvalidProtocolBufferException(
+ "CodedInputStream encountered a malformed varint.");
+ }
+
+ static InvalidProtocolBufferException invalidTag() {
+ return new InvalidProtocolBufferException(
+ "Protocol message contained an invalid tag (zero).");
+ }
+
+ static InvalidProtocolBufferException invalidEndTag() {
+ return new InvalidProtocolBufferException(
+ "Protocol message end-group tag did not match expected tag.");
+ }
+
+ static InvalidProtocolBufferException invalidWireType() {
+ return new InvalidProtocolBufferException(
+ "Protocol message tag had invalid wire type.");
+ }
+
+ static InvalidProtocolBufferException recursionLimitExceeded() {
+ return new InvalidProtocolBufferException(
+ "Protocol message had too many levels of nesting. May be malicious. " +
+ "Use CodedInputStream.setRecursionLimit() to increase the depth limit.");
+ }
+
+ static InvalidProtocolBufferException sizeLimitExceeded() {
+ return new InvalidProtocolBufferException(
+ "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/Message.java b/java/src/main/java/com/google/protobuf/Message.java
new file mode 100644
index 0000000..c11abdc
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Message.java
@@ -0,0 +1,305 @@
+// 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.
+
+// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
+// mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Map;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ * <p>
+ * See also {@link MessageLite}, which defines most of the methods that typical
+ * users care about. {@link Message} adds to it methods that are not available
+ * in the "lite" runtime. The biggest added features are introspection and
+ * reflection -- i.e., getting descriptors for the message type and accessing
+ * the field values dynamically.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface Message extends MessageLite {
+ /**
+ * Get the message's type's descriptor. This differs from the
+ * {@code getDescriptor()} method of generated message classes in that
+ * this method is an abstract method of the {@code Message} interface
+ * whereas {@code getDescriptor()} is a static method of a specific class.
+ * They return the same thing.
+ */
+ Descriptors.Descriptor getDescriptorForType();
+
+ // (From MessageLite, re-declared here only for return type covariance.)
+ Message getDefaultInstanceForType();
+
+ /**
+ * Returns a collection of all the fields in this message which are set
+ * and their corresponding values. A singular ("required" or "optional")
+ * field is set iff hasField() returns true for that field. A "repeated"
+ * field is set iff getRepeatedFieldSize() is greater than zero. The
+ * values are exactly what would be returned by calling
+ * {@link #getField(Descriptors.FieldDescriptor)} for each field. The map
+ * is guaranteed to be a sorted map, so iterating over it will return fields
+ * in order by field number.
+ */
+ Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+ /**
+ * Returns true if the given field is set. This is exactly equivalent to
+ * calling the generated "has" accessor method corresponding to the field.
+ * @throws IllegalArgumentException The field is a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ boolean hasField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Obtains the value of the given field, or the default value if it is
+ * not set. For primitive fields, the boxed primitive value is returned.
+ * For enum fields, the EnumValueDescriptor for the value is returend. For
+ * embedded message fields, the sub-message is returned. For repeated
+ * fields, a java.util.List is returned.
+ */
+ Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets the number of elements of a repeated field. This is exactly
+ * equivalent to calling the generated "Count" accessor method corresponding
+ * to the field.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /**
+ * Gets an element of a repeated field. For primitive fields, the boxed
+ * primitive value is returned. For enum fields, the EnumValueDescriptor
+ * for the value is returend. For embedded message fields, the sub-message
+ * is returned.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+ /** Get the {@link UnknownFieldSet} for this message. */
+ UnknownFieldSet getUnknownFields();
+
+ // -----------------------------------------------------------------
+ // Comparison and hashing
+
+ /**
+ * Compares the specified object with this message for equality. Returns
+ * <tt>true</tt> if the given object is a message of the same type (as
+ * defined by {@code getDescriptorForType()}) and has identical values for
+ * all of its fields.
+ *
+ * @param other object to be compared for equality with this message
+ * @return <tt>true</tt> if the specified object is equal to this message
+ */
+ @Override
+ boolean equals(Object other);
+
+ /**
+ * Returns the hash code value for this message. The hash code of a message
+ * is defined to be <tt>getDescriptor().hashCode() ^ map.hashCode()</tt>,
+ * where <tt>map</tt> is a map of field numbers to field values.
+ *
+ * @return the hash code value for this message
+ * @see Map#hashCode()
+ */
+ @Override
+ int hashCode();
+
+ // -----------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Converts the message to a string in protocol buffer text format. This is
+ * just a trivial wrapper around {@link TextFormat#printToString(Message)}.
+ */
+ @Override
+ String toString();
+
+ // =================================================================
+ // Builders
+
+ // (From MessageLite, re-declared here only for return type covariance.)
+ Builder newBuilderForType();
+ Builder toBuilder();
+
+ /**
+ * Abstract interface implemented by Protocol Message builders.
+ */
+ interface Builder extends MessageLite.Builder {
+ // (From MessageLite.Builder, re-declared here only for return type
+ // covariance.)
+ Builder clear();
+
+ /**
+ * Merge {@code other} into the message being built. {@code other} must
+ * have the exact same type as {@code this} (i.e.
+ * {@code getDescriptorForType() == other.getDescriptorForType()}).
+ *
+ * Merging occurs as follows. For each field:<br>
+ * * For singular primitive fields, if the field is set in {@code other},
+ * then {@code other}'s value overwrites the value in this message.<br>
+ * * For singular message fields, if the field is set in {@code other},
+ * it is merged into the corresponding sub-message of this message
+ * using the same merging rules.<br>
+ * * For repeated fields, the elements in {@code other} are concatenated
+ * with the elements in this message.
+ *
+ * This is equivalent to the {@code Message::MergeFrom} method in C++.
+ */
+ Builder mergeFrom(Message other);
+
+ // (From MessageLite.Builder, re-declared here only for return type
+ // covariance.)
+ Message build();
+ Message buildPartial();
+ Builder clone();
+ Builder mergeFrom(CodedInputStream input) throws IOException;
+ Builder mergeFrom(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+
+ /**
+ * Get the message's type's descriptor.
+ * See {@link Message#getDescriptorForType()}.
+ */
+ Descriptors.Descriptor getDescriptorForType();
+
+ // (From MessageLite.Builder, re-declared here only for return type
+ // covariance.)
+ Message getDefaultInstanceForType();
+
+ /**
+ * Like {@link Message#getAllFields()}. The returned map may or may not
+ * reflect future changes to the builder. Either way, the returned map is
+ * itself unmodifiable.
+ */
+ Map<Descriptors.FieldDescriptor, Object> getAllFields();
+
+ /**
+ * Create a Builder for messages of the appropriate type for the given
+ * field. Messages built with this can then be passed to setField(),
+ * setRepeatedField(), or addRepeatedField().
+ */
+ Builder newBuilderForField(Descriptors.FieldDescriptor field);
+
+ /** Like {@link Message#hasField(Descriptors.FieldDescriptor)} */
+ boolean hasField(Descriptors.FieldDescriptor field);
+
+ /** Like {@link Message#getField(Descriptors.FieldDescriptor)} */
+ Object getField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Sets a field to the given value. The value must be of the correct type
+ * for this field, i.e. the same type that
+ * {@link Message#getField(Descriptors.FieldDescriptor)} would return.
+ */
+ Builder setField(Descriptors.FieldDescriptor field, Object value);
+
+ /**
+ * Clears the field. This is exactly equivalent to calling the generated
+ * "clear" accessor method corresponding to the field.
+ */
+ Builder clearField(Descriptors.FieldDescriptor field);
+
+ /**
+ * Like {@link Message#getRepeatedFieldCount(Descriptors.FieldDescriptor)}
+ */
+ int getRepeatedFieldCount(Descriptors.FieldDescriptor field);
+
+ /**
+ * Like {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)}
+ */
+ Object getRepeatedField(Descriptors.FieldDescriptor field, int index);
+
+ /**
+ * Sets an element of a repeated field to the given value. The value must
+ * be of the correct type for this field, i.e. the same type that
+ * {@link Message#getRepeatedField(Descriptors.FieldDescriptor,int)} would
+ * return.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Builder setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value);
+
+ /**
+ * Like {@code setRepeatedField}, but appends the value as a new element.
+ * @throws IllegalArgumentException The field is not a repeated field, or
+ * {@code field.getContainingType() != getDescriptorForType()}.
+ */
+ Builder addRepeatedField(Descriptors.FieldDescriptor field, Object value);
+
+ /** Get the {@link UnknownFieldSet} for this message. */
+ UnknownFieldSet getUnknownFields();
+
+ /** Set the {@link UnknownFieldSet} for this message. */
+ Builder setUnknownFields(UnknownFieldSet unknownFields);
+
+ /**
+ * Merge some unknown fields into the {@link UnknownFieldSet} for this
+ * message.
+ */
+ Builder mergeUnknownFields(UnknownFieldSet unknownFields);
+
+ // ---------------------------------------------------------------
+ // Convenience methods.
+
+ // (From MessageLite.Builder, re-declared here only for return type
+ // covariance.)
+ Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
+ Builder mergeFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+ Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+ Builder mergeFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException;
+ Builder mergeFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+ Builder mergeFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+ Builder mergeFrom(InputStream input) throws IOException;
+ Builder mergeFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+ Builder mergeDelimitedFrom(InputStream input)
+ throws IOException;
+ Builder mergeDelimitedFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/MessageLite.java b/java/src/main/java/com/google/protobuf/MessageLite.java
new file mode 100644
index 0000000..3ebe9bb
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/MessageLite.java
@@ -0,0 +1,331 @@
+// 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.
+
+// TODO(kenton): Use generics? E.g. Builder<BuilderType extends Builder>, then
+// mergeFrom*() could return BuilderType for better type-safety.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Abstract interface implemented by Protocol Message objects.
+ *
+ * <p>This interface is implemented by all protocol message objects. Non-lite
+ * messages additionally implement the Message interface, which is a subclass
+ * of MessageLite. Use MessageLite instead when you only need the subset of
+ * features which it supports -- namely, nothing that uses descriptors or
+ * reflection. You can instruct the protocol compiler to generate classes
+ * which implement only MessageLite, not the full Message interface, by adding
+ * the follow line to the .proto file:
+ * <pre>
+ * option optimize_for = LITE_RUNTIME;
+ * </pre>
+ *
+ * <p>This is particularly useful on resource-constrained systems where the
+ * full protocol buffers runtime library is too big.
+ *
+ * <p>Note that on non-constrained systems (e.g. servers) when you need to link
+ * in lots of protocol definitions, a better way to reduce total code footprint
+ * is to use {@code optimize_for = CODE_SIZE}. This will make the generated
+ * code smaller while still supporting all the same features (at the expense of
+ * speed). {@code optimize_for = LITE_RUNTIME} is best when you only have a
+ * small number of message types linked into your binary, in which case the
+ * size of the protocol buffers runtime itself is the biggest problem.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface MessageLite {
+ /**
+ * Get an instance of the type with all fields set to their default values.
+ * This may or may not be a singleton. This differs from the
+ * {@code getDefaultInstance()} method of generated message classes in that
+ * this method is an abstract method of the {@code MessageLite} interface
+ * whereas {@code getDefaultInstance()} is a static method of a specific
+ * class. They return the same thing.
+ */
+ MessageLite getDefaultInstanceForType();
+
+ /**
+ * Returns true if all required fields in the message and all embedded
+ * messages are set, false otherwise.
+ */
+ boolean isInitialized();
+
+ /**
+ * Serializes the message and writes it to {@code output}. This does not
+ * flush or close the stream.
+ */
+ void writeTo(CodedOutputStream output) throws IOException;
+
+ /**
+ * Get the number of bytes required to encode this message. The result
+ * is only computed on the first call and memoized after that.
+ */
+ int getSerializedSize();
+
+ // -----------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Serializes the message to a {@code ByteString} and returns it. This is
+ * just a trivial wrapper around
+ * {@link #writeTo(CodedOutputStream)}.
+ */
+ ByteString toByteString();
+
+ /**
+ * Serializes the message to a {@code byte} array and returns it. This is
+ * just a trivial wrapper around
+ * {@link #writeTo(CodedOutputStream)}.
+ */
+ byte[] toByteArray();
+
+ /**
+ * Serializes the message and writes it to {@code output}. This is just a
+ * trivial wrapper around {@link #writeTo(CodedOutputStream)}. This does
+ * not flush or close the stream.
+ * <p>
+ * NOTE: Protocol Buffers are not self-delimiting. Therefore, if you write
+ * any more data to the stream after the message, you must somehow ensure
+ * that the parser on the receiving end does not interpret this as being
+ * part of the protocol message. This can be done e.g. by writing the size
+ * of the message before the data, then making sure to limit the input to
+ * that size on the receiving end (e.g. by wrapping the InputStream in one
+ * which limits the input). Alternatively, just use
+ * {@link #writeDelimitedTo(OutputStream)}.
+ */
+ void writeTo(OutputStream output) throws IOException;
+
+ /**
+ * Like {@link #writeTo(OutputStream)}, but writes the size of the message
+ * as a varint before writing the data. This allows more data to be written
+ * to the stream after the message without the need to delimit the message
+ * data yourself. Use {@link Builder#mergeDelimitedFrom(InputStream)} (or
+ * the static method {@code YourMessageType.parseDelimitedFrom(InputStream)})
+ * to parse messages written by this method.
+ */
+ void writeDelimitedTo(OutputStream output) throws IOException;
+
+ // =================================================================
+ // Builders
+
+ /**
+ * Constructs a new builder for a message of the same type as this message.
+ */
+ Builder newBuilderForType();
+
+ /**
+ * Constructs a builder initialized with the current message. Use this to
+ * derive a new message from the current one.
+ */
+ Builder toBuilder();
+
+ /**
+ * Abstract interface implemented by Protocol Message builders.
+ */
+ interface Builder extends Cloneable {
+ /** Resets all fields to their default values. */
+ Builder clear();
+
+ /**
+ * Construct the final message. Once this is called, the Builder is no
+ * longer valid, and calling any other method will result in undefined
+ * behavior and may throw a NullPointerException. If you need to continue
+ * working with the builder after calling {@code build()}, {@code clone()}
+ * it first.
+ * @throws UninitializedMessageException The message is missing one or more
+ * required fields (i.e. {@link #isInitialized()} returns false).
+ * Use {@link #buildPartial()} to bypass this check.
+ */
+ MessageLite build();
+
+ /**
+ * Like {@link #build()}, but does not throw an exception if the message
+ * is missing required fields. Instead, a partial message is returned.
+ * Once this is called, the Builder is no longer valid, and calling any
+ * will result in undefined behavior and may throw a NullPointerException.
+ *
+ * If you need to continue working with the builder after calling
+ * {@code buildPartial()}, {@code clone()} it first.
+ */
+ MessageLite buildPartial();
+
+ /**
+ * Clones the Builder.
+ * @see Object#clone()
+ */
+ Builder clone();
+
+ /**
+ * Returns true if all required fields in the message and all embedded
+ * messages are set, false otherwise.
+ */
+ boolean isInitialized();
+
+ /**
+ * Parses a message of this type from the input and merges it with this
+ * message, as if using {@link Builder#mergeFrom(MessageLite)}.
+ *
+ * <p>Warning: This does not verify that all required fields are present in
+ * the input message. If you call {@link #build()} without setting all
+ * required fields, it will throw an {@link UninitializedMessageException},
+ * which is a {@code RuntimeException} and thus might not be caught. There
+ * are a few good ways to deal with this:
+ * <ul>
+ * <li>Call {@link #isInitialized()} to verify that all required fields
+ * are set before building.
+ * <li>Parse the message separately using one of the static
+ * {@code parseFrom} methods, then use {@link #mergeFrom(MessageLite)}
+ * to merge it with this one. {@code parseFrom} will throw an
+ * {@link InvalidProtocolBufferException} (an {@code IOException})
+ * if some required fields are missing.
+ * <li>Use {@code buildPartial()} to build, which ignores missing
+ * required fields.
+ * </ul>
+ *
+ * <p>Note: The caller should call
+ * {@link CodedInputStream#checkLastTagWas(int)} after calling this to
+ * verify that the last tag seen was the appropriate end-group tag,
+ * or zero for EOF.
+ */
+ Builder mergeFrom(CodedInputStream input) throws IOException;
+
+ /**
+ * Like {@link Builder#mergeFrom(CodedInputStream)}, but also
+ * parses extensions. The extensions that you want to be able to parse
+ * must be registered in {@code extensionRegistry}. Extensions not in
+ * the registry will be treated as unknown fields.
+ */
+ Builder mergeFrom(CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+
+ /**
+ * Get the message's type's default instance.
+ * See {@link MessageLite#getDefaultInstanceForType()}.
+ */
+ MessageLite getDefaultInstanceForType();
+
+ // ---------------------------------------------------------------
+ // Convenience methods.
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ Builder mergeFrom(ByteString data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ Builder mergeFrom(byte[] data) throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ Builder mergeFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse {@code data} as a message of this type and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException;
+
+ /**
+ * Parse a message of this type from {@code input} and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}. Note that this method always
+ * reads the <i>entire</i> input (unless it throws an exception). If you
+ * want it to stop earlier, you will need to wrap your input in some
+ * wrapper stream that limits reading. Or, use
+ * {@link MessageLite#writeDelimitedTo(OutputStream)} to write your message
+ * and {@link #mergeDelimitedFrom(InputStream)} to read it.
+ * <p>
+ * Despite usually reading the entire input, this does not close the stream.
+ */
+ Builder mergeFrom(InputStream input) throws IOException;
+
+ /**
+ * Parse a message of this type from {@code input} and merge it with the
+ * message being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream,ExtensionRegistry)}.
+ */
+ Builder mergeFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+
+ /**
+ * Like {@link #mergeFrom(InputStream)}, but does not read until EOF.
+ * Instead, the size of the message (encoded as a varint) is read first,
+ * then the message data. Use
+ * {@link MessageLite#writeDelimitedTo(OutputStream)} to write messages in
+ * this format.
+ */
+ Builder mergeDelimitedFrom(InputStream input)
+ throws IOException;
+
+ /**
+ * Like {@link #mergeDelimitedFrom(InputStream)} but supporting extensions.
+ */
+ Builder mergeDelimitedFrom(InputStream input,
+ ExtensionRegistryLite extensionRegistry)
+ throws IOException;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java b/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
new file mode 100644
index 0000000..112400f
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ProtocolMessageEnum.java
@@ -0,0 +1,58 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+/**
+ * Interface of useful methods added to all enums generated by the protocol
+ * compiler.
+ */
+public interface ProtocolMessageEnum extends Internal.EnumLite {
+
+ /**
+ * Return the value's numeric value as defined in the .proto file.
+ */
+ int getNumber();
+
+ /**
+ * Return the value's descriptor, which contains information such as
+ * value name, number, and type.
+ */
+ EnumValueDescriptor getValueDescriptor();
+
+ /**
+ * Return the enum type's descriptor, which contains information
+ * about each defined value, etc.
+ */
+ EnumDescriptor getDescriptorForType();
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcCallback.java b/java/src/main/java/com/google/protobuf/RpcCallback.java
new file mode 100644
index 0000000..841c88a
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcCallback.java
@@ -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.
+
+package com.google.protobuf;
+
+/**
+ * Interface for an RPC callback, normally called when an RPC completes.
+ * {@code ParameterType} is normally the method's response message type.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcCallback<ParameterType> {
+ void run(ParameterType parameter);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcChannel.java b/java/src/main/java/com/google/protobuf/RpcChannel.java
new file mode 100644
index 0000000..204ff18
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcChannel.java
@@ -0,0 +1,65 @@
+// 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;
+
+/**
+ * <p>Abstract interface for an RPC channel. An {@code RpcChannel} represents a
+ * communication line to a {@link Service} which can be used to call that
+ * {@link Service}'s methods. The {@link Service} may be running on another
+ * machine. Normally, you should not call an {@code RpcChannel} directly, but
+ * instead construct a stub {@link Service} wrapping it. Example:
+ *
+ * <pre>
+ * RpcChannel channel = rpcImpl.newChannel("remotehost.example.com:1234");
+ * RpcController controller = rpcImpl.newController();
+ * MyService service = MyService.newStub(channel);
+ * service.myMethod(controller, request, callback);
+ * </pre>
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcChannel {
+ /**
+ * Call the given method of the remote service. This method is similar to
+ * {@code Service.callMethod()} with one important difference: the caller
+ * decides the types of the {@code Message} objects, not the callee. The
+ * request may be of any type as long as
+ * {@code request.getDescriptor() == method.getInputType()}.
+ * The response passed to the callback will be of the same type as
+ * {@code responsePrototype} (which must have
+ * {@code getDescriptor() == method.getOutputType()}).
+ */
+ void callMethod(Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request,
+ Message responsePrototype,
+ RpcCallback<Message> done);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcController.java b/java/src/main/java/com/google/protobuf/RpcController.java
new file mode 100644
index 0000000..a017422
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcController.java
@@ -0,0 +1,112 @@
+// 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;
+
+/**
+ * <p>An {@code RpcController} mediates a single method call. The primary
+ * purpose of the controller is to provide a way to manipulate settings
+ * specific to the RPC implementation and to find out about RPC-level errors.
+ *
+ * <p>The methods provided by the {@code RpcController} interface are intended
+ * to be a "least common denominator" set of features which we expect all
+ * implementations to support. Specific implementations may provide more
+ * advanced features (e.g. deadline propagation).
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface RpcController {
+ // -----------------------------------------------------------------
+ // These calls may be made from the client side only. Their results
+ // are undefined on the server side (may throw RuntimeExceptions).
+
+ /**
+ * Resets the RpcController to its initial state so that it may be reused in
+ * a new call. This can be called from the client side only. It must not
+ * be called while an RPC is in progress.
+ */
+ void reset();
+
+ /**
+ * After a call has finished, returns true if the call failed. The possible
+ * reasons for failure depend on the RPC implementation. {@code failed()}
+ * most only be called on the client side, and must not be called before a
+ * call has finished.
+ */
+ boolean failed();
+
+ /**
+ * If {@code failed()} is {@code true}, returns a human-readable description
+ * of the error.
+ */
+ String errorText();
+
+ /**
+ * Advises the RPC system that the caller desires that the RPC call be
+ * canceled. The RPC system may cancel it immediately, may wait awhile and
+ * then cancel it, or may not even cancel the call at all. If the call is
+ * canceled, the "done" callback will still be called and the RpcController
+ * will indicate that the call failed at that time.
+ */
+ void startCancel();
+
+ // -----------------------------------------------------------------
+ // These calls may be made from the server side only. Their results
+ // are undefined on the client side (may throw RuntimeExceptions).
+
+ /**
+ * Causes {@code failed()} to return true on the client side. {@code reason}
+ * will be incorporated into the message returned by {@code errorText()}.
+ * If you find you need to return machine-readable information about
+ * failures, you should incorporate it into your response protocol buffer
+ * and should NOT call {@code setFailed()}.
+ */
+ void setFailed(String reason);
+
+ /**
+ * If {@code true}, indicates that the client canceled the RPC, so the server
+ * may as well give up on replying to it. This method must be called on the
+ * server side only. The server should still call the final "done" callback.
+ */
+ boolean isCanceled();
+
+ /**
+ * Asks that the given callback be called when the RPC is canceled. The
+ * parameter passed to the callback will always be {@code null}. The
+ * callback will always be called exactly once. If the RPC completes without
+ * being canceled, the callback will be called after completion. If the RPC
+ * has already been canceled when NotifyOnCancel() is called, the callback
+ * will be called immediately.
+ *
+ * <p>{@code notifyOnCancel()} must be called no more than once per request.
+ * It must be called on the server side only.
+ */
+ void notifyOnCancel(RpcCallback<Object> callback);
+}
diff --git a/java/src/main/java/com/google/protobuf/RpcUtil.java b/java/src/main/java/com/google/protobuf/RpcUtil.java
new file mode 100644
index 0000000..b1b959a
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/RpcUtil.java
@@ -0,0 +1,135 @@
+// 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;
+
+/**
+ * Grab-bag of utility functions useful when dealing with RPCs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class RpcUtil {
+ private RpcUtil() {}
+
+ /**
+ * Take an {@code RpcCallback<Message>} and convert it to an
+ * {@code RpcCallback} accepting a specific message type. This is always
+ * type-safe (parameter type contravariance).
+ */
+ @SuppressWarnings("unchecked")
+ public static <Type extends Message> RpcCallback<Type>
+ specializeCallback(final RpcCallback<Message> originalCallback) {
+ return (RpcCallback<Type>)originalCallback;
+ // The above cast works, but only due to technical details of the Java
+ // implementation. A more theoretically correct -- but less efficient --
+ // implementation would be as follows:
+ // return new RpcCallback<Type>() {
+ // public void run(Type parameter) {
+ // originalCallback.run(parameter);
+ // }
+ // };
+ }
+
+ /**
+ * Take an {@code RpcCallback} accepting a specific message type and convert
+ * it to an {@code RpcCallback<Message>}. The generalized callback will
+ * accept any message object which has the same descriptor, and will convert
+ * it to the correct class before calling the original callback. However,
+ * if the generalized callback is given a message with a different descriptor,
+ * an exception will be thrown.
+ */
+ public static <Type extends Message>
+ RpcCallback<Message> generalizeCallback(
+ final RpcCallback<Type> originalCallback,
+ final Class<Type> originalClass,
+ final Type defaultInstance) {
+ return new RpcCallback<Message>() {
+ public void run(final Message parameter) {
+ Type typedParameter;
+ try {
+ typedParameter = originalClass.cast(parameter);
+ } catch (ClassCastException ignored) {
+ typedParameter = copyAsType(defaultInstance, parameter);
+ }
+ originalCallback.run(typedParameter);
+ }
+ };
+ }
+
+ /**
+ * Creates a new message of type "Type" which is a copy of "source". "source"
+ * must have the same descriptor but may be a different class (e.g.
+ * DynamicMessage).
+ */
+ @SuppressWarnings("unchecked")
+ private static <Type extends Message> Type copyAsType(
+ final Type typeDefaultInstance, final Message source) {
+ return (Type)typeDefaultInstance.newBuilderForType()
+ .mergeFrom(source)
+ .build();
+ }
+
+ /**
+ * Creates a callback which can only be called once. This may be useful for
+ * security, when passing a callback to untrusted code: most callbacks do
+ * not expect to be called more than once, so doing so may expose bugs if it
+ * is not prevented.
+ */
+ public static <ParameterType>
+ RpcCallback<ParameterType> newOneTimeCallback(
+ final RpcCallback<ParameterType> originalCallback) {
+ return new RpcCallback<ParameterType>() {
+ private boolean alreadyCalled = false;
+
+ public void run(final ParameterType parameter) {
+ synchronized(this) {
+ if (alreadyCalled) {
+ throw new AlreadyCalledException();
+ }
+ alreadyCalled = true;
+ }
+
+ originalCallback.run(parameter);
+ }
+ };
+ }
+
+ /**
+ * Exception thrown when a one-time callback is called more than once.
+ */
+ public static final class AlreadyCalledException extends RuntimeException {
+ private static final long serialVersionUID = 5469741279507848266L;
+
+ public AlreadyCalledException() {
+ super("This RpcCallback was already called and cannot be called " +
+ "multiple times.");
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/Service.java b/java/src/main/java/com/google/protobuf/Service.java
new file mode 100644
index 0000000..33bcfd3
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/Service.java
@@ -0,0 +1,111 @@
+// 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;
+
+/**
+ * Abstract base interface for protocol-buffer-based RPC services. Services
+ * themselves are abstract classes (implemented either by servers or as
+ * stubs), but they subclass this base interface. The methods of this
+ * interface can be used to call the methods of the service without knowing
+ * its exact type at compile time (analogous to the Message interface).
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public interface Service {
+ /**
+ * Get the {@code ServiceDescriptor} describing this service and its methods.
+ */
+ Descriptors.ServiceDescriptor getDescriptorForType();
+
+ /**
+ * <p>Call a method of the service specified by MethodDescriptor. This is
+ * normally implemented as a simple {@code switch()} that calls the standard
+ * definitions of the service's methods.
+ *
+ * <p>Preconditions:
+ * <ul>
+ * <li>{@code method.getService() == getDescriptorForType()}
+ * <li>{@code request} is of the exact same class as the object returned by
+ * {@code getRequestPrototype(method)}.
+ * <li>{@code controller} is of the correct type for the RPC implementation
+ * being used by this Service. For stubs, the "correct type" depends
+ * on the RpcChannel which the stub is using. Server-side Service
+ * implementations are expected to accept whatever type of
+ * {@code RpcController} the server-side RPC implementation uses.
+ * </ul>
+ *
+ * <p>Postconditions:
+ * <ul>
+ * <li>{@code done} will be called when the method is complete. This may be
+ * before {@code callMethod()} returns or it may be at some point in
+ * the future.
+ * <li>The parameter to {@code done} is the response. It must be of the
+ * exact same type as would be returned by
+ * {@code getResponsePrototype(method)}.
+ * <li>If the RPC failed, the parameter to {@code done} will be
+ * {@code null}. Further details about the failure can be found by
+ * querying {@code controller}.
+ * </ul>
+ */
+ void callMethod(Descriptors.MethodDescriptor method,
+ RpcController controller,
+ Message request,
+ RpcCallback<Message> done);
+
+ /**
+ * <p>{@code callMethod()} requires that the request passed in is of a
+ * particular subclass of {@code Message}. {@code getRequestPrototype()}
+ * gets the default instances of this type for a given method. You can then
+ * call {@code Message.newBuilderForType()} on this instance to
+ * construct a builder to build an object which you can then pass to
+ * {@code callMethod()}.
+ *
+ * <p>Example:
+ * <pre>
+ * MethodDescriptor method =
+ * service.getDescriptorForType().findMethodByName("Foo");
+ * Message request =
+ * stub.getRequestPrototype(method).newBuilderForType()
+ * .mergeFrom(input).build();
+ * service.callMethod(method, request, callback);
+ * </pre>
+ */
+ Message getRequestPrototype(Descriptors.MethodDescriptor method);
+
+ /**
+ * Like {@code getRequestPrototype()}, but gets a prototype of the response
+ * message. {@code getResponsePrototype()} is generally not needed because
+ * the {@code Service} implementation constructs the response message itself,
+ * but it may be useful in some cases to know ahead of time what type of
+ * object will be returned.
+ */
+ Message getResponsePrototype(Descriptors.MethodDescriptor method);
+}
diff --git a/java/src/main/java/com/google/protobuf/ServiceException.java b/java/src/main/java/com/google/protobuf/ServiceException.java
new file mode 100644
index 0000000..c043a77
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/ServiceException.java
@@ -0,0 +1,44 @@
+// 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;
+
+/**
+ * Thrown by blocking RPC methods when a failure occurs.
+ *
+ * @author cpovirk@google.com (Chris Povirk)
+ */
+public final class ServiceException extends Exception {
+ private static final long serialVersionUID = -1219262335729891920L;
+
+ public ServiceException(final String message) {
+ super(message);
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/TextFormat.java b/java/src/main/java/com/google/protobuf/TextFormat.java
new file mode 100644
index 0000000..a855720
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/TextFormat.java
@@ -0,0 +1,1323 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+
+import java.io.IOException;
+import java.nio.CharBuffer;
+import java.math.BigInteger;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Provide ascii text parsing and formatting support for proto2 instances.
+ * The implementation largely follows google/protobuf/text_format.cc.
+ *
+ * @author wenboz@google.com Wenbo Zhu
+ * @author kenton@google.com Kenton Varda
+ */
+public final class TextFormat {
+ private TextFormat() {
+ }
+
+ /**
+ * Outputs a textual representation of the Protocol Message supplied into
+ * the parameter output. (This representation is the new version of the
+ * classic "ProtocolPrinter" output from the original Protocol Buffer system)
+ */
+ public static void print(final Message message, final Appendable output)
+ throws IOException {
+ final TextGenerator generator = new TextGenerator(output);
+ print(message, generator);
+ }
+
+ /** Outputs a textual representation of {@code fields} to {@code output}. */
+ public static void print(final UnknownFieldSet fields,
+ final Appendable output)
+ throws IOException {
+ final TextGenerator generator = new TextGenerator(output);
+ printUnknownFields(fields, generator);
+ }
+
+ /**
+ * Like {@code print()}, but writes directly to a {@code String} and
+ * returns it.
+ */
+ public static String printToString(final Message message) {
+ try {
+ final StringBuilder text = new StringBuilder();
+ print(message, text);
+ return text.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Writing to a StringBuilder threw an IOException (should never " +
+ "happen).", e);
+ }
+ }
+
+ /**
+ * Like {@code print()}, but writes directly to a {@code String} and
+ * returns it.
+ */
+ public static String printToString(final UnknownFieldSet fields) {
+ try {
+ final StringBuilder text = new StringBuilder();
+ print(fields, text);
+ return text.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Writing to a StringBuilder threw an IOException (should never " +
+ "happen).", e);
+ }
+ }
+
+ private static void print(final Message message,
+ final TextGenerator generator)
+ throws IOException {
+ for (final Map.Entry<FieldDescriptor, Object> field :
+ message.getAllFields().entrySet()) {
+ printField(field.getKey(), field.getValue(), generator);
+ }
+ printUnknownFields(message.getUnknownFields(), generator);
+ }
+
+ public static void printField(final FieldDescriptor field,
+ final Object value,
+ final Appendable output)
+ throws IOException {
+ final TextGenerator generator = new TextGenerator(output);
+ printField(field, value, generator);
+ }
+
+ public static String printFieldToString(final FieldDescriptor field,
+ final Object value) {
+ try {
+ final StringBuilder text = new StringBuilder();
+ printField(field, value, text);
+ return text.toString();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Writing to a StringBuilder threw an IOException (should never " +
+ "happen).", e);
+ }
+ }
+
+ private static void printField(final FieldDescriptor field,
+ final Object value,
+ final TextGenerator generator)
+ throws IOException {
+ if (field.isRepeated()) {
+ // Repeated field. Print each element.
+ for (final Object element : (List) value) {
+ printSingleField(field, element, generator);
+ }
+ } else {
+ printSingleField(field, value, generator);
+ }
+ }
+
+ private static void printSingleField(final FieldDescriptor field,
+ final Object value,
+ final TextGenerator generator)
+ throws IOException {
+ if (field.isExtension()) {
+ generator.print("[");
+ // We special-case MessageSet elements for compatibility with proto1.
+ if (field.getContainingType().getOptions().getMessageSetWireFormat()
+ && (field.getType() == FieldDescriptor.Type.MESSAGE)
+ && (field.isOptional())
+ // object equality
+ && (field.getExtensionScope() == field.getMessageType())) {
+ generator.print(field.getMessageType().getFullName());
+ } else {
+ generator.print(field.getFullName());
+ }
+ generator.print("]");
+ } else {
+ if (field.getType() == FieldDescriptor.Type.GROUP) {
+ // Groups must be serialized with their original capitalization.
+ generator.print(field.getMessageType().getName());
+ } else {
+ generator.print(field.getName());
+ }
+ }
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ generator.print(" {\n");
+ generator.indent();
+ } else {
+ generator.print(": ");
+ }
+
+ printFieldValue(field, value, generator);
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ generator.outdent();
+ generator.print("}");
+ }
+ generator.print("\n");
+ }
+
+ private static void printFieldValue(final FieldDescriptor field,
+ final Object value,
+ final TextGenerator generator)
+ throws IOException {
+ switch (field.getType()) {
+ case INT32:
+ case INT64:
+ case SINT32:
+ case SINT64:
+ case SFIXED32:
+ case SFIXED64:
+ case FLOAT:
+ case DOUBLE:
+ case BOOL:
+ // Good old toString() does what we want for these types.
+ generator.print(value.toString());
+ break;
+
+ case UINT32:
+ case FIXED32:
+ generator.print(unsignedToString((Integer) value));
+ break;
+
+ case UINT64:
+ case FIXED64:
+ generator.print(unsignedToString((Long) value));
+ break;
+
+ case STRING:
+ generator.print("\"");
+ generator.print(escapeText((String) value));
+ generator.print("\"");
+ break;
+
+ case BYTES:
+ generator.print("\"");
+ generator.print(escapeBytes((ByteString) value));
+ generator.print("\"");
+ break;
+
+ case ENUM:
+ generator.print(((EnumValueDescriptor) value).getName());
+ break;
+
+ case MESSAGE:
+ case GROUP:
+ print((Message) value, generator);
+ break;
+ }
+ }
+
+ private static void printUnknownFields(final UnknownFieldSet unknownFields,
+ final TextGenerator generator)
+ throws IOException {
+ for (final Map.Entry<Integer, UnknownFieldSet.Field> entry :
+ unknownFields.asMap().entrySet()) {
+ final String prefix = entry.getKey().toString() + ": ";
+ final UnknownFieldSet.Field field = entry.getValue();
+
+ for (final long value : field.getVarintList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(unsignedToString(value));
+ generator.print("\n");
+ }
+ for (final int value : field.getFixed32List()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(String.format((Locale) null, "0x%08x", value));
+ generator.print("\n");
+ }
+ for (final long value : field.getFixed64List()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": ");
+ generator.print(String.format((Locale) null, "0x%016x", value));
+ generator.print("\n");
+ }
+ for (final ByteString value : field.getLengthDelimitedList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(": \"");
+ generator.print(escapeBytes(value));
+ generator.print("\"\n");
+ }
+ for (final UnknownFieldSet value : field.getGroupList()) {
+ generator.print(entry.getKey().toString());
+ generator.print(" {\n");
+ generator.indent();
+ printUnknownFields(value, generator);
+ generator.outdent();
+ generator.print("}\n");
+ }
+ }
+ }
+
+ /** Convert an unsigned 32-bit integer to a string. */
+ private static String unsignedToString(final int value) {
+ if (value >= 0) {
+ return Integer.toString(value);
+ } else {
+ return Long.toString(((long) value) & 0x00000000FFFFFFFFL);
+ }
+ }
+
+ /** Convert an unsigned 64-bit integer to a string. */
+ private static String unsignedToString(final long value) {
+ if (value >= 0) {
+ return Long.toString(value);
+ } else {
+ // Pull off the most-significant bit so that BigInteger doesn't think
+ // the number is negative, then set it again using setBit().
+ return BigInteger.valueOf(value & 0x7FFFFFFFFFFFFFFFL)
+ .setBit(63).toString();
+ }
+ }
+
+ /**
+ * An inner class for writing text to the output stream.
+ */
+ private static final class TextGenerator {
+ private Appendable output;
+ private boolean atStartOfLine = true;
+ private final StringBuilder indent = new StringBuilder();
+
+ private TextGenerator(final Appendable output) {
+ this.output = output;
+ }
+
+ /**
+ * Indent text by two spaces. After calling Indent(), two spaces will be
+ * inserted at the beginning of each line of text. Indent() may be called
+ * multiple times to produce deeper indents.
+ */
+ public void indent() {
+ indent.append(" ");
+ }
+
+ /**
+ * Reduces the current indent level by two spaces, or crashes if the indent
+ * level is zero.
+ */
+ public void outdent() {
+ final int length = indent.length();
+ if (length == 0) {
+ throw new IllegalArgumentException(
+ " Outdent() without matching Indent().");
+ }
+ indent.delete(length - 2, length);
+ }
+
+ /**
+ * Print text to the output stream.
+ */
+ public void print(final CharSequence text) throws IOException {
+ final int size = text.length();
+ int pos = 0;
+
+ for (int i = 0; i < size; i++) {
+ if (text.charAt(i) == '\n') {
+ write(text.subSequence(pos, size), i - pos + 1);
+ pos = i + 1;
+ atStartOfLine = true;
+ }
+ }
+ write(text.subSequence(pos, size), size - pos);
+ }
+
+ private void write(final CharSequence data, final int size)
+ throws IOException {
+ if (size == 0) {
+ return;
+ }
+ if (atStartOfLine) {
+ atStartOfLine = false;
+ output.append(indent);
+ }
+ output.append(data);
+ }
+ }
+
+ // =================================================================
+ // Parsing
+
+ /**
+ * Represents a stream of tokens parsed from a {@code String}.
+ *
+ * <p>The Java standard library provides many classes that you might think
+ * would be useful for implementing this, but aren't. For example:
+ *
+ * <ul>
+ * <li>{@code java.io.StreamTokenizer}: This almost does what we want -- or,
+ * at least, something that would get us close to what we want -- except
+ * for one fatal flaw: It automatically un-escapes strings using Java
+ * escape sequences, which do not include all the escape sequences we
+ * need to support (e.g. '\x').
+ * <li>{@code java.util.Scanner}: This seems like a great way at least to
+ * parse regular expressions out of a stream (so we wouldn't have to load
+ * the entire input into a single string before parsing). Sadly,
+ * {@code Scanner} requires that tokens be delimited with some delimiter.
+ * Thus, although the text "foo:" should parse to two tokens ("foo" and
+ * ":"), {@code Scanner} would recognize it only as a single token.
+ * Furthermore, {@code Scanner} provides no way to inspect the contents
+ * of delimiters, making it impossible to keep track of line and column
+ * numbers.
+ * </ul>
+ *
+ * <p>Luckily, Java's regular expression support does manage to be useful to
+ * us. (Barely: We need {@code Matcher.usePattern()}, which is new in
+ * Java 1.5.) So, we can use that, at least. Unfortunately, this implies
+ * that we need to have the entire input in one contiguous string.
+ */
+ private static final class Tokenizer {
+ private final CharSequence text;
+ private final Matcher matcher;
+ private String currentToken;
+
+ // The character index within this.text at which the current token begins.
+ private int pos = 0;
+
+ // The line and column numbers of the current token.
+ private int line = 0;
+ private int column = 0;
+
+ // The line and column numbers of the previous token (allows throwing
+ // errors *after* consuming).
+ private int previousLine = 0;
+ private int previousColumn = 0;
+
+ // We use possesive quantifiers (*+ and ++) because otherwise the Java
+ // regex matcher has stack overflows on large inputs.
+ private static final Pattern WHITESPACE =
+ Pattern.compile("(\\s|(#.*$))++", Pattern.MULTILINE);
+ private static final Pattern TOKEN = Pattern.compile(
+ "[a-zA-Z_][0-9a-zA-Z_+-]*+|" + // an identifier
+ "[0-9+-][0-9a-zA-Z_.+-]*+|" + // a number
+ "\"([^\"\n\\\\]|\\\\.)*+(\"|\\\\?$)|" + // a double-quoted string
+ "\'([^\"\n\\\\]|\\\\.)*+(\'|\\\\?$)", // a single-quoted string
+ Pattern.MULTILINE);
+
+ private static final Pattern DOUBLE_INFINITY = Pattern.compile(
+ "-?inf(inity)?",
+ Pattern.CASE_INSENSITIVE);
+ private static final Pattern FLOAT_INFINITY = Pattern.compile(
+ "-?inf(inity)?f?",
+ Pattern.CASE_INSENSITIVE);
+ private static final Pattern FLOAT_NAN = Pattern.compile(
+ "nanf?",
+ Pattern.CASE_INSENSITIVE);
+
+ /** Construct a tokenizer that parses tokens from the given text. */
+ private Tokenizer(final CharSequence text) {
+ this.text = text;
+ this.matcher = WHITESPACE.matcher(text);
+ skipWhitespace();
+ nextToken();
+ }
+
+ /** Are we at the end of the input? */
+ public boolean atEnd() {
+ return currentToken.length() == 0;
+ }
+
+ /** Advance to the next token. */
+ public void nextToken() {
+ previousLine = line;
+ previousColumn = column;
+
+ // Advance the line counter to the current position.
+ while (pos < matcher.regionStart()) {
+ if (text.charAt(pos) == '\n') {
+ ++line;
+ column = 0;
+ } else {
+ ++column;
+ }
+ ++pos;
+ }
+
+ // Match the next token.
+ if (matcher.regionStart() == matcher.regionEnd()) {
+ // EOF
+ currentToken = "";
+ } else {
+ matcher.usePattern(TOKEN);
+ if (matcher.lookingAt()) {
+ currentToken = matcher.group();
+ matcher.region(matcher.end(), matcher.regionEnd());
+ } else {
+ // Take one character.
+ currentToken = String.valueOf(text.charAt(pos));
+ matcher.region(pos + 1, matcher.regionEnd());
+ }
+
+ skipWhitespace();
+ }
+ }
+
+ /**
+ * Skip over any whitespace so that the matcher region starts at the next
+ * token.
+ */
+ private void skipWhitespace() {
+ matcher.usePattern(WHITESPACE);
+ if (matcher.lookingAt()) {
+ matcher.region(matcher.end(), matcher.regionEnd());
+ }
+ }
+
+ /**
+ * If the next token exactly matches {@code token}, consume it and return
+ * {@code true}. Otherwise, return {@code false} without doing anything.
+ */
+ public boolean tryConsume(final String token) {
+ if (currentToken.equals(token)) {
+ nextToken();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * If the next token exactly matches {@code token}, consume it. Otherwise,
+ * throw a {@link ParseException}.
+ */
+ public void consume(final String token) throws ParseException {
+ if (!tryConsume(token)) {
+ throw parseException("Expected \"" + token + "\".");
+ }
+ }
+
+ /**
+ * Returns {@code true} if the next token is an integer, but does
+ * not consume it.
+ */
+ public boolean lookingAtInteger() {
+ if (currentToken.length() == 0) {
+ return false;
+ }
+
+ final char c = currentToken.charAt(0);
+ return ('0' <= c && c <= '9') ||
+ c == '-' || c == '+';
+ }
+
+ /**
+ * If the next token is an identifier, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public String consumeIdentifier() throws ParseException {
+ for (int i = 0; i < currentToken.length(); i++) {
+ final char c = currentToken.charAt(i);
+ if (('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ ('0' <= c && c <= '9') ||
+ (c == '_') || (c == '.')) {
+ // OK
+ } else {
+ throw parseException("Expected identifier.");
+ }
+ }
+
+ final String result = currentToken;
+ nextToken();
+ return result;
+ }
+
+ /**
+ * If the next token is a 32-bit signed integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public int consumeInt32() throws ParseException {
+ try {
+ final int result = parseInt32(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 32-bit unsigned integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public int consumeUInt32() throws ParseException {
+ try {
+ final int result = parseUInt32(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 64-bit signed integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public long consumeInt64() throws ParseException {
+ try {
+ final long result = parseInt64(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a 64-bit unsigned integer, consume it and return its
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public long consumeUInt64() throws ParseException {
+ try {
+ final long result = parseUInt64(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw integerParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a double, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public double consumeDouble() throws ParseException {
+ // We need to parse infinity and nan separately because
+ // Double.parseDouble() does not accept "inf", "infinity", or "nan".
+ if (DOUBLE_INFINITY.matcher(currentToken).matches()) {
+ final boolean negative = currentToken.startsWith("-");
+ nextToken();
+ return negative ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
+ }
+ if (currentToken.equalsIgnoreCase("nan")) {
+ nextToken();
+ return Double.NaN;
+ }
+ try {
+ final double result = Double.parseDouble(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw floatParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a float, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public float consumeFloat() throws ParseException {
+ // We need to parse infinity and nan separately because
+ // Float.parseFloat() does not accept "inf", "infinity", or "nan".
+ if (FLOAT_INFINITY.matcher(currentToken).matches()) {
+ final boolean negative = currentToken.startsWith("-");
+ nextToken();
+ return negative ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY;
+ }
+ if (FLOAT_NAN.matcher(currentToken).matches()) {
+ nextToken();
+ return Float.NaN;
+ }
+ try {
+ final float result = Float.parseFloat(currentToken);
+ nextToken();
+ return result;
+ } catch (NumberFormatException e) {
+ throw floatParseException(e);
+ }
+ }
+
+ /**
+ * If the next token is a boolean, consume it and return its value.
+ * Otherwise, throw a {@link ParseException}.
+ */
+ public boolean consumeBoolean() throws ParseException {
+ if (currentToken.equals("true")) {
+ nextToken();
+ return true;
+ } else if (currentToken.equals("false")) {
+ nextToken();
+ return false;
+ } else {
+ throw parseException("Expected \"true\" or \"false\".");
+ }
+ }
+
+ /**
+ * If the next token is a string, consume it and return its (unescaped)
+ * value. Otherwise, throw a {@link ParseException}.
+ */
+ public String consumeString() throws ParseException {
+ return consumeByteString().toStringUtf8();
+ }
+
+ /**
+ * If the next token is a string, consume it, unescape it as a
+ * {@link ByteString}, and return it. Otherwise, throw a
+ * {@link ParseException}.
+ */
+ public ByteString consumeByteString() throws ParseException {
+ final char quote = currentToken.length() > 0 ? currentToken.charAt(0)
+ : '\0';
+ if (quote != '\"' && quote != '\'') {
+ throw parseException("Expected string.");
+ }
+
+ if (currentToken.length() < 2 ||
+ currentToken.charAt(currentToken.length() - 1) != quote) {
+ throw parseException("String missing ending quote.");
+ }
+
+ try {
+ final String escaped =
+ currentToken.substring(1, currentToken.length() - 1);
+ final ByteString result = unescapeBytes(escaped);
+ nextToken();
+ return result;
+ } catch (InvalidEscapeSequenceException e) {
+ throw parseException(e.getMessage());
+ }
+ }
+
+ /**
+ * Returns a {@link ParseException} with the current line and column
+ * numbers in the description, suitable for throwing.
+ */
+ public ParseException parseException(final String description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new ParseException(
+ (line + 1) + ":" + (column + 1) + ": " + description);
+ }
+
+ /**
+ * Returns a {@link ParseException} with the line and column numbers of
+ * the previous token in the description, suitable for throwing.
+ */
+ public ParseException parseExceptionPreviousToken(
+ final String description) {
+ // Note: People generally prefer one-based line and column numbers.
+ return new ParseException(
+ (previousLine + 1) + ":" + (previousColumn + 1) + ": " + description);
+ }
+
+ /**
+ * Constructs an appropriate {@link ParseException} for the given
+ * {@code NumberFormatException} when trying to parse an integer.
+ */
+ private ParseException integerParseException(
+ final NumberFormatException e) {
+ return parseException("Couldn't parse integer: " + e.getMessage());
+ }
+
+ /**
+ * Constructs an appropriate {@link ParseException} for the given
+ * {@code NumberFormatException} when trying to parse a float or double.
+ */
+ private ParseException floatParseException(final NumberFormatException e) {
+ return parseException("Couldn't parse number: " + e.getMessage());
+ }
+ }
+
+ /** Thrown when parsing an invalid text format message. */
+ public static class ParseException extends IOException {
+ private static final long serialVersionUID = 3196188060225107702L;
+
+ public ParseException(final String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public static void merge(final Readable input,
+ final Message.Builder builder)
+ throws IOException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}.
+ */
+ public static void merge(final CharSequence input,
+ final Message.Builder builder)
+ throws ParseException {
+ merge(input, ExtensionRegistry.getEmptyRegistry(), builder);
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public static void merge(final Readable input,
+ final ExtensionRegistry extensionRegistry,
+ final Message.Builder builder)
+ throws IOException {
+ // Read the entire input to a String then parse that.
+
+ // If StreamTokenizer were not quite so crippled, or if there were a kind
+ // of Reader that could read in chunks that match some particular regex,
+ // or if we wanted to write a custom Reader to tokenize our stream, then
+ // we would not have to read to one big String. Alas, none of these is
+ // the case. Oh well.
+
+ merge(toStringBuilder(input), extensionRegistry, builder);
+ }
+
+ private static final int BUFFER_SIZE = 4096;
+
+ // TODO(chrisn): See if working around java.io.Reader#read(CharBuffer)
+ // overhead is worthwhile
+ private static StringBuilder toStringBuilder(final Readable input)
+ throws IOException {
+ final StringBuilder text = new StringBuilder();
+ final CharBuffer buffer = CharBuffer.allocate(BUFFER_SIZE);
+ while (true) {
+ final int n = input.read(buffer);
+ if (n == -1) {
+ break;
+ }
+ buffer.flip();
+ text.append(buffer, 0, n);
+ }
+ return text;
+ }
+
+ /**
+ * Parse a text-format message from {@code input} and merge the contents
+ * into {@code builder}. Extensions will be recognized if they are
+ * registered in {@code extensionRegistry}.
+ */
+ public static void merge(final CharSequence input,
+ final ExtensionRegistry extensionRegistry,
+ final Message.Builder builder)
+ throws ParseException {
+ final Tokenizer tokenizer = new Tokenizer(input);
+
+ while (!tokenizer.atEnd()) {
+ mergeField(tokenizer, extensionRegistry, builder);
+ }
+ }
+
+ /**
+ * Parse a single field from {@code tokenizer} and merge it into
+ * {@code builder}.
+ */
+ private static void mergeField(final Tokenizer tokenizer,
+ final ExtensionRegistry extensionRegistry,
+ final Message.Builder builder)
+ throws ParseException {
+ FieldDescriptor field;
+ final Descriptor type = builder.getDescriptorForType();
+ ExtensionRegistry.ExtensionInfo extension = null;
+
+ if (tokenizer.tryConsume("[")) {
+ // An extension.
+ final StringBuilder name =
+ new StringBuilder(tokenizer.consumeIdentifier());
+ while (tokenizer.tryConsume(".")) {
+ name.append('.');
+ name.append(tokenizer.consumeIdentifier());
+ }
+
+ extension = extensionRegistry.findExtensionByName(name.toString());
+
+ if (extension == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" not found in the ExtensionRegistry.");
+ } else if (extension.descriptor.getContainingType() != type) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Extension \"" + name + "\" does not extend message type \"" +
+ type.getFullName() + "\".");
+ }
+
+ tokenizer.consume("]");
+
+ field = extension.descriptor;
+ } else {
+ final String name = tokenizer.consumeIdentifier();
+ field = type.findFieldByName(name);
+
+ // Group names are expected to be capitalized as they appear in the
+ // .proto file, which actually matches their type names, not their field
+ // names.
+ if (field == null) {
+ // Explicitly specify US locale so that this code does not break when
+ // executing in Turkey.
+ final String lowerName = name.toLowerCase(Locale.US);
+ field = type.findFieldByName(lowerName);
+ // If the case-insensitive match worked but the field is NOT a group,
+ if (field != null && field.getType() != FieldDescriptor.Type.GROUP) {
+ field = null;
+ }
+ }
+ // Again, special-case group names as described above.
+ if (field != null && field.getType() == FieldDescriptor.Type.GROUP &&
+ !field.getMessageType().getName().equals(name)) {
+ field = null;
+ }
+
+ if (field == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Message type \"" + type.getFullName() +
+ "\" has no field named \"" + name + "\".");
+ }
+ }
+
+ Object value = null;
+
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
+ tokenizer.tryConsume(":"); // optional
+
+ final String endToken;
+ if (tokenizer.tryConsume("<")) {
+ endToken = ">";
+ } else {
+ tokenizer.consume("{");
+ endToken = "}";
+ }
+
+ final Message.Builder subBuilder;
+ if (extension == null) {
+ subBuilder = builder.newBuilderForField(field);
+ } else {
+ subBuilder = extension.defaultInstance.newBuilderForType();
+ }
+
+ while (!tokenizer.tryConsume(endToken)) {
+ if (tokenizer.atEnd()) {
+ throw tokenizer.parseException(
+ "Expected \"" + endToken + "\".");
+ }
+ mergeField(tokenizer, extensionRegistry, subBuilder);
+ }
+
+ value = subBuilder.build();
+
+ } else {
+ tokenizer.consume(":");
+
+ switch (field.getType()) {
+ case INT32:
+ case SINT32:
+ case SFIXED32:
+ value = tokenizer.consumeInt32();
+ break;
+
+ case INT64:
+ case SINT64:
+ case SFIXED64:
+ value = tokenizer.consumeInt64();
+ break;
+
+ case UINT32:
+ case FIXED32:
+ value = tokenizer.consumeUInt32();
+ break;
+
+ case UINT64:
+ case FIXED64:
+ value = tokenizer.consumeUInt64();
+ break;
+
+ case FLOAT:
+ value = tokenizer.consumeFloat();
+ break;
+
+ case DOUBLE:
+ value = tokenizer.consumeDouble();
+ break;
+
+ case BOOL:
+ value = tokenizer.consumeBoolean();
+ break;
+
+ case STRING:
+ value = tokenizer.consumeString();
+ break;
+
+ case BYTES:
+ value = tokenizer.consumeByteString();
+ break;
+
+ case ENUM:
+ final EnumDescriptor enumType = field.getEnumType();
+
+ if (tokenizer.lookingAtInteger()) {
+ final int number = tokenizer.consumeInt32();
+ value = enumType.findValueByNumber(number);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName() +
+ "\" has no value with number " + number + '.');
+ }
+ } else {
+ final String id = tokenizer.consumeIdentifier();
+ value = enumType.findValueByName(id);
+ if (value == null) {
+ throw tokenizer.parseExceptionPreviousToken(
+ "Enum type \"" + enumType.getFullName() +
+ "\" has no value named \"" + id + "\".");
+ }
+ }
+
+ break;
+
+ case MESSAGE:
+ case GROUP:
+ throw new RuntimeException("Can't get here.");
+ }
+ }
+
+ if (field.isRepeated()) {
+ builder.addRepeatedField(field, value);
+ } else {
+ builder.setField(field, value);
+ }
+ }
+
+ // =================================================================
+ // Utility functions
+ //
+ // Some of these methods are package-private because Descriptors.java uses
+ // them.
+
+ /**
+ * Escapes bytes in the format used in protocol buffer text format, which
+ * is the same as the format used for C string literals. All bytes
+ * that are not printable 7-bit ASCII characters are escaped, as well as
+ * backslash, single-quote, and double-quote characters. Characters for
+ * which no defined short-hand escape sequence is defined will be escaped
+ * using 3-digit octal sequences.
+ */
+ static String escapeBytes(final ByteString input) {
+ final StringBuilder builder = new StringBuilder(input.size());
+ for (int i = 0; i < input.size(); i++) {
+ final byte b = input.byteAt(i);
+ switch (b) {
+ // Java does not recognize \a or \v, apparently.
+ case 0x07: builder.append("\\a" ); break;
+ case '\b': builder.append("\\b" ); break;
+ case '\f': builder.append("\\f" ); break;
+ case '\n': builder.append("\\n" ); break;
+ case '\r': builder.append("\\r" ); break;
+ case '\t': builder.append("\\t" ); break;
+ case 0x0b: builder.append("\\v" ); break;
+ case '\\': builder.append("\\\\"); break;
+ case '\'': builder.append("\\\'"); break;
+ case '"' : builder.append("\\\""); break;
+ default:
+ if (b >= 0x20) {
+ builder.append((char) b);
+ } else {
+ builder.append('\\');
+ builder.append((char) ('0' + ((b >>> 6) & 3)));
+ builder.append((char) ('0' + ((b >>> 3) & 7)));
+ builder.append((char) ('0' + (b & 7)));
+ }
+ break;
+ }
+ }
+ return builder.toString();
+ }
+
+ /**
+ * Un-escape a byte sequence as escaped using
+ * {@link #escapeBytes(ByteString)}. Two-digit hex escapes (starting with
+ * "\x") are also recognized.
+ */
+ static ByteString unescapeBytes(final CharSequence input)
+ throws InvalidEscapeSequenceException {
+ final byte[] result = new byte[input.length()];
+ int pos = 0;
+ for (int i = 0; i < input.length(); i++) {
+ char c = input.charAt(i);
+ if (c == '\\') {
+ if (i + 1 < input.length()) {
+ ++i;
+ c = input.charAt(i);
+ if (isOctal(c)) {
+ // Octal escape.
+ int code = digitValue(c);
+ if (i + 1 < input.length() && isOctal(input.charAt(i + 1))) {
+ ++i;
+ code = code * 8 + digitValue(input.charAt(i));
+ }
+ if (i + 1 < input.length() && isOctal(input.charAt(i + 1))) {
+ ++i;
+ code = code * 8 + digitValue(input.charAt(i));
+ }
+ result[pos++] = (byte)code;
+ } else {
+ switch (c) {
+ case 'a' : result[pos++] = 0x07; break;
+ case 'b' : result[pos++] = '\b'; break;
+ case 'f' : result[pos++] = '\f'; break;
+ case 'n' : result[pos++] = '\n'; break;
+ case 'r' : result[pos++] = '\r'; break;
+ case 't' : result[pos++] = '\t'; break;
+ case 'v' : result[pos++] = 0x0b; break;
+ case '\\': result[pos++] = '\\'; break;
+ case '\'': result[pos++] = '\''; break;
+ case '"' : result[pos++] = '\"'; break;
+
+ case 'x':
+ // hex escape
+ int code = 0;
+ if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
+ ++i;
+ code = digitValue(input.charAt(i));
+ } else {
+ throw new InvalidEscapeSequenceException(
+ "Invalid escape sequence: '\\x' with no digits");
+ }
+ if (i + 1 < input.length() && isHex(input.charAt(i + 1))) {
+ ++i;
+ code = code * 16 + digitValue(input.charAt(i));
+ }
+ result[pos++] = (byte)code;
+ break;
+
+ default:
+ throw new InvalidEscapeSequenceException(
+ "Invalid escape sequence: '\\" + c + '\'');
+ }
+ }
+ } else {
+ throw new InvalidEscapeSequenceException(
+ "Invalid escape sequence: '\\' at end of string.");
+ }
+ } else {
+ result[pos++] = (byte)c;
+ }
+ }
+
+ return ByteString.copyFrom(result, 0, pos);
+ }
+
+ /**
+ * Thrown by {@link TextFormat#unescapeBytes} and
+ * {@link TextFormat#unescapeText} when an invalid escape sequence is seen.
+ */
+ static class InvalidEscapeSequenceException extends IOException {
+ private static final long serialVersionUID = -8164033650142593304L;
+
+ InvalidEscapeSequenceException(final String description) {
+ super(description);
+ }
+ }
+
+ /**
+ * Like {@link #escapeBytes(ByteString)}, but escapes a text string.
+ * Non-ASCII characters are first encoded as UTF-8, then each byte is escaped
+ * individually as a 3-digit octal escape. Yes, it's weird.
+ */
+ static String escapeText(final String input) {
+ return escapeBytes(ByteString.copyFromUtf8(input));
+ }
+
+ /**
+ * Un-escape a text string as escaped using {@link #escapeText(String)}.
+ * Two-digit hex escapes (starting with "\x") are also recognized.
+ */
+ static String unescapeText(final String input)
+ throws InvalidEscapeSequenceException {
+ return unescapeBytes(input).toStringUtf8();
+ }
+
+ /** Is this an octal digit? */
+ private static boolean isOctal(final char c) {
+ return '0' <= c && c <= '7';
+ }
+
+ /** Is this a hex digit? */
+ private static boolean isHex(final char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'f') ||
+ ('A' <= c && c <= 'F');
+ }
+
+ /**
+ * Interpret a character as a digit (in any base up to 36) and return the
+ * numeric value. This is like {@code Character.digit()} but we don't accept
+ * non-ASCII digits.
+ */
+ private static int digitValue(final char c) {
+ if ('0' <= c && c <= '9') {
+ return c - '0';
+ } else if ('a' <= c && c <= 'z') {
+ return c - 'a' + 10;
+ } else {
+ return c - 'A' + 10;
+ }
+ }
+
+ /**
+ * Parse a 32-bit signed integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively.
+ */
+ static int parseInt32(final String text) throws NumberFormatException {
+ return (int) parseInteger(text, true, false);
+ }
+
+ /**
+ * Parse a 32-bit unsigned integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * result is coerced to a (signed) {@code int} when returned since Java has
+ * no unsigned integer type.
+ */
+ static int parseUInt32(final String text) throws NumberFormatException {
+ return (int) parseInteger(text, false, false);
+ }
+
+ /**
+ * Parse a 64-bit signed integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively.
+ */
+ static long parseInt64(final String text) throws NumberFormatException {
+ return parseInteger(text, true, true);
+ }
+
+ /**
+ * Parse a 64-bit unsigned integer from the text. Unlike the Java standard
+ * {@code Integer.parseInt()}, this function recognizes the prefixes "0x"
+ * and "0" to signify hexidecimal and octal numbers, respectively. The
+ * result is coerced to a (signed) {@code long} when returned since Java has
+ * no unsigned long type.
+ */
+ static long parseUInt64(final String text) throws NumberFormatException {
+ return parseInteger(text, false, true);
+ }
+
+ private static long parseInteger(final String text,
+ final boolean isSigned,
+ final boolean isLong)
+ throws NumberFormatException {
+ int pos = 0;
+
+ boolean negative = false;
+ if (text.startsWith("-", pos)) {
+ if (!isSigned) {
+ throw new NumberFormatException("Number must be positive: " + text);
+ }
+ ++pos;
+ negative = true;
+ }
+
+ int radix = 10;
+ if (text.startsWith("0x", pos)) {
+ pos += 2;
+ radix = 16;
+ } else if (text.startsWith("0", pos)) {
+ radix = 8;
+ }
+
+ final String numberText = text.substring(pos);
+
+ long result = 0;
+ if (numberText.length() < 16) {
+ // Can safely assume no overflow.
+ result = Long.parseLong(numberText, radix);
+ if (negative) {
+ result = -result;
+ }
+
+ // Check bounds.
+ // No need to check for 64-bit numbers since they'd have to be 16 chars
+ // or longer to overflow.
+ if (!isLong) {
+ if (isSigned) {
+ if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit signed integer: " + text);
+ }
+ } else {
+ if (result >= (1L << 32) || result < 0) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit unsigned integer: " + text);
+ }
+ }
+ }
+ } else {
+ BigInteger bigValue = new BigInteger(numberText, radix);
+ if (negative) {
+ bigValue = bigValue.negate();
+ }
+
+ // Check bounds.
+ if (!isLong) {
+ if (isSigned) {
+ if (bigValue.bitLength() > 31) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit signed integer: " + text);
+ }
+ } else {
+ if (bigValue.bitLength() > 32) {
+ throw new NumberFormatException(
+ "Number out of range for 32-bit unsigned integer: " + text);
+ }
+ }
+ } else {
+ if (isSigned) {
+ if (bigValue.bitLength() > 63) {
+ throw new NumberFormatException(
+ "Number out of range for 64-bit signed integer: " + text);
+ }
+ } else {
+ if (bigValue.bitLength() > 64) {
+ throw new NumberFormatException(
+ "Number out of range for 64-bit unsigned integer: " + text);
+ }
+ }
+ }
+
+ result = bigValue.longValue();
+ }
+
+ return result;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/UninitializedMessageException.java b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
new file mode 100644
index 0000000..8743c12
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/UninitializedMessageException.java
@@ -0,0 +1,99 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Thrown when attempting to build a protocol message that is missing required
+ * fields. This is a {@code RuntimeException} because it normally represents
+ * a programming error: it happens when some code which constructs a message
+ * fails to set all the fields. {@code parseFrom()} methods <b>do not</b>
+ * throw this; they throw an {@link InvalidProtocolBufferException} if
+ * required fields are missing, because it is not a programming error to
+ * receive an incomplete message. In other words,
+ * {@code UninitializedMessageException} should never be thrown by correct
+ * code, but {@code InvalidProtocolBufferException} might be.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class UninitializedMessageException extends RuntimeException {
+ private static final long serialVersionUID = -7466929953374883507L;
+
+ public UninitializedMessageException(final MessageLite message) {
+ super("Message was missing required fields. (Lite runtime could not " +
+ "determine which fields were missing).");
+ missingFields = null;
+ }
+
+ public UninitializedMessageException(final List<String> missingFields) {
+ super(buildDescription(missingFields));
+ this.missingFields = missingFields;
+ }
+
+ private final List<String> missingFields;
+
+ /**
+ * Get a list of human-readable names of required fields missing from this
+ * message. Each name is a full path to a field, e.g. "foo.bar[5].baz".
+ * Returns null if the lite runtime was used, since it lacks the ability to
+ * find missing fields.
+ */
+ public List<String> getMissingFields() {
+ return Collections.unmodifiableList(missingFields);
+ }
+
+ /**
+ * Converts this exception to an {@link InvalidProtocolBufferException}.
+ * When a parsed message is missing required fields, this should be thrown
+ * instead of {@code UninitializedMessageException}.
+ */
+ public InvalidProtocolBufferException asInvalidProtocolBufferException() {
+ return new InvalidProtocolBufferException(getMessage());
+ }
+
+ /** Construct the description string for this exception. */
+ private static String buildDescription(final List<String> missingFields) {
+ final StringBuilder description =
+ new StringBuilder("Message missing required fields: ");
+ boolean first = true;
+ for (final String field : missingFields) {
+ if (first) {
+ first = false;
+ } else {
+ description.append(", ");
+ }
+ description.append(field);
+ }
+ return description.toString();
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/UnknownFieldSet.java b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
new file mode 100644
index 0000000..7f7e493
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/UnknownFieldSet.java
@@ -0,0 +1,947 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * {@code UnknownFieldSet} is used to keep track of fields which were seen when
+ * parsing a protocol message but whose field numbers or types are unrecognized.
+ * This most frequently occurs when new fields are added to a message type
+ * and then messages containing those feilds are read by old software that was
+ * compiled before the new types were added.
+ *
+ * <p>Every {@link Message} contains an {@code UnknownFieldSet} (and every
+ * {@link Message.Builder} contains an {@link Builder}).
+ *
+ * <p>Most users will never need to use this class.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public final class UnknownFieldSet implements MessageLite {
+ private UnknownFieldSet() {}
+
+ /** Create a new {@link Builder}. */
+ public static Builder newBuilder() {
+ return Builder.create();
+ }
+
+ /**
+ * Create a new {@link Builder} and initialize it to be a copy
+ * of {@code copyFrom}.
+ */
+ public static Builder newBuilder(final UnknownFieldSet copyFrom) {
+ return newBuilder().mergeFrom(copyFrom);
+ }
+
+ /** Get an empty {@code UnknownFieldSet}. */
+ public static UnknownFieldSet getDefaultInstance() {
+ return defaultInstance;
+ }
+ public UnknownFieldSet getDefaultInstanceForType() {
+ return defaultInstance;
+ }
+ private static final UnknownFieldSet defaultInstance =
+ new UnknownFieldSet(Collections.<Integer, Field>emptyMap());
+
+ /**
+ * Construct an {@code UnknownFieldSet} around the given map. The map is
+ * expected to be immutable.
+ */
+ private UnknownFieldSet(final Map<Integer, Field> fields) {
+ this.fields = fields;
+ }
+ private Map<Integer, Field> fields;
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ return (other instanceof UnknownFieldSet) &&
+ fields.equals(((UnknownFieldSet) other).fields);
+ }
+
+ @Override
+ public int hashCode() {
+ return fields.hashCode();
+ }
+
+ /** Get a map of fields in the set by number. */
+ public Map<Integer, Field> asMap() {
+ return fields;
+ }
+
+ /** Check if the given field number is present in the set. */
+ public boolean hasField(final int number) {
+ return fields.containsKey(number);
+ }
+
+ /**
+ * Get a field by number. Returns an empty field if not present. Never
+ * returns {@code null}.
+ */
+ public Field getField(final int number) {
+ final Field result = fields.get(number);
+ return (result == null) ? Field.getDefaultInstance() : result;
+ }
+
+ /** Serializes the set and writes it to {@code output}. */
+ public void writeTo(final CodedOutputStream output) throws IOException {
+ for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ entry.getValue().writeTo(entry.getKey(), output);
+ }
+ }
+
+ /**
+ * Converts the set to a string in protocol buffer text format. This is
+ * just a trivial wrapper around
+ * {@link TextFormat#printToString(UnknownFieldSet)}.
+ */
+ @Override
+ public String toString() {
+ return TextFormat.printToString(this);
+ }
+
+ /**
+ * Serializes the message to a {@code ByteString} and returns it. This is
+ * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public ByteString toByteString() {
+ try {
+ final ByteString.CodedBuilder out =
+ ByteString.newCodedBuilder(getSerializedSize());
+ writeTo(out.getCodedOutput());
+ return out.build();
+ } catch (final IOException e) {
+ throw new RuntimeException(
+ "Serializing to a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Serializes the message to a {@code byte} array and returns it. This is
+ * just a trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public byte[] toByteArray() {
+ try {
+ final byte[] result = new byte[getSerializedSize()];
+ final CodedOutputStream output = CodedOutputStream.newInstance(result);
+ writeTo(output);
+ output.checkNoSpaceLeft();
+ return result;
+ } catch (final IOException e) {
+ throw new RuntimeException(
+ "Serializing to a byte array threw an IOException " +
+ "(should never happen).", e);
+ }
+ }
+
+ /**
+ * Serializes the message and writes it to {@code output}. This is just a
+ * trivial wrapper around {@link #writeTo(CodedOutputStream)}.
+ */
+ public void writeTo(final OutputStream output) throws IOException {
+ final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ public void writeDelimitedTo(OutputStream output) throws IOException {
+ final CodedOutputStream codedOutput = CodedOutputStream.newInstance(output);
+ codedOutput.writeRawVarint32(getSerializedSize());
+ writeTo(codedOutput);
+ codedOutput.flush();
+ }
+
+ /** Get the number of bytes required to encode this set. */
+ public int getSerializedSize() {
+ int result = 0;
+ for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ result += entry.getValue().getSerializedSize(entry.getKey());
+ }
+ return result;
+ }
+
+ /**
+ * Serializes the set and writes it to {@code output} using
+ * {@code MessageSet} wire format.
+ */
+ public void writeAsMessageSetTo(final CodedOutputStream output)
+ throws IOException {
+ for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ entry.getValue().writeAsMessageSetExtensionTo(
+ entry.getKey(), output);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this set using
+ * {@code MessageSet} wire format.
+ */
+ public int getSerializedSizeAsMessageSet() {
+ int result = 0;
+ for (final Map.Entry<Integer, Field> entry : fields.entrySet()) {
+ result += entry.getValue().getSerializedSizeAsMessageSetExtension(
+ entry.getKey());
+ }
+ return result;
+ }
+
+ public boolean isInitialized() {
+ // UnknownFieldSets do not have required fields, so they are always
+ // initialized.
+ return true;
+ }
+
+ /** Parse an {@code UnknownFieldSet} from the given input stream. */
+ public static UnknownFieldSet parseFrom(final CodedInputStream input)
+ throws IOException {
+ return newBuilder().mergeFrom(input).build();
+ }
+
+ /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+ public static UnknownFieldSet parseFrom(final ByteString data)
+ throws InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).build();
+ }
+
+ /** Parse {@code data} as an {@code UnknownFieldSet} and return it. */
+ public static UnknownFieldSet parseFrom(final byte[] data)
+ throws InvalidProtocolBufferException {
+ return newBuilder().mergeFrom(data).build();
+ }
+
+ /** Parse an {@code UnknownFieldSet} from {@code input} and return it. */
+ public static UnknownFieldSet parseFrom(final InputStream input)
+ throws IOException {
+ return newBuilder().mergeFrom(input).build();
+ }
+
+ public Builder newBuilderForType() {
+ return newBuilder();
+ }
+
+ public Builder toBuilder() {
+ return newBuilder().mergeFrom(this);
+ }
+
+ /**
+ * Builder for {@link UnknownFieldSet}s.
+ *
+ * <p>Note that this class maintains {@link Field.Builder}s for all fields
+ * in the set. Thus, adding one element to an existing {@link Field} does not
+ * require making a copy. This is important for efficient parsing of
+ * unknown repeated fields. However, it implies that {@link Field}s cannot
+ * be constructed independently, nor can two {@link UnknownFieldSet}s share
+ * the same {@code Field} object.
+ *
+ * <p>Use {@link UnknownFieldSet#newBuilder()} to construct a {@code Builder}.
+ */
+ public static final class Builder implements MessageLite.Builder {
+ // This constructor should never be called directly (except from 'create').
+ private Builder() {}
+
+ private Map<Integer, Field> fields;
+
+ // Optimization: We keep around a builder for the last field that was
+ // modified so that we can efficiently add to it multiple times in a
+ // row (important when parsing an unknown repeated field).
+ private int lastFieldNumber;
+ private Field.Builder lastField;
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.reinitialize();
+ return builder;
+ }
+
+ /**
+ * Get a field builder for the given field number which includes any
+ * values that already exist.
+ */
+ private Field.Builder getFieldBuilder(final int number) {
+ if (lastField != null) {
+ if (number == lastFieldNumber) {
+ return lastField;
+ }
+ // Note: addField() will reset lastField and lastFieldNumber.
+ addField(lastFieldNumber, lastField.build());
+ }
+ if (number == 0) {
+ return null;
+ } else {
+ final Field existing = fields.get(number);
+ lastFieldNumber = number;
+ lastField = Field.newBuilder();
+ if (existing != null) {
+ lastField.mergeFrom(existing);
+ }
+ return lastField;
+ }
+ }
+
+ /**
+ * Build the {@link UnknownFieldSet} and return it.
+ *
+ * <p>Once {@code build()} has been called, the {@code Builder} will no
+ * longer be usable. Calling any method after {@code build()} will result
+ * in undefined behavior and can cause a {@code NullPointerException} to be
+ * thrown.
+ */
+ public UnknownFieldSet build() {
+ getFieldBuilder(0); // Force lastField to be built.
+ final UnknownFieldSet result;
+ if (fields.isEmpty()) {
+ result = getDefaultInstance();
+ } else {
+ result = new UnknownFieldSet(Collections.unmodifiableMap(fields));
+ }
+ fields = null;
+ return result;
+ }
+
+ public UnknownFieldSet buildPartial() {
+ // No required fields, so this is the same as build().
+ return build();
+ }
+
+ @Override
+ public Builder clone() {
+ getFieldBuilder(0); // Force lastField to be built.
+ return UnknownFieldSet.newBuilder().mergeFrom(
+ new UnknownFieldSet(fields));
+ }
+
+ public UnknownFieldSet getDefaultInstanceForType() {
+ return UnknownFieldSet.getDefaultInstance();
+ }
+
+ private void reinitialize() {
+ fields = Collections.emptyMap();
+ lastFieldNumber = 0;
+ lastField = null;
+ }
+
+ /** Reset the builder to an empty set. */
+ public Builder clear() {
+ reinitialize();
+ return this;
+ }
+
+ /**
+ * Merge the fields from {@code other} into this set. If a field number
+ * exists in both sets, {@code other}'s values for that field will be
+ * appended to the values in this set.
+ */
+ public Builder mergeFrom(final UnknownFieldSet other) {
+ if (other != getDefaultInstance()) {
+ for (final Map.Entry<Integer, Field> entry : other.fields.entrySet()) {
+ mergeField(entry.getKey(), entry.getValue());
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Add a field to the {@code UnknownFieldSet}. If a field with the same
+ * number already exists, the two are merged.
+ */
+ public Builder mergeField(final int number, final Field field) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ if (hasField(number)) {
+ getFieldBuilder(number).mergeFrom(field);
+ } else {
+ // Optimization: We could call getFieldBuilder(number).mergeFrom(field)
+ // in this case, but that would create a copy of the Field object.
+ // We'd rather reuse the one passed to us, so call addField() instead.
+ addField(number, field);
+ }
+ return this;
+ }
+
+ /**
+ * Convenience method for merging a new field containing a single varint
+ * value. This is used in particular when an unknown enum value is
+ * encountered.
+ */
+ public Builder mergeVarintField(final int number, final int value) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ getFieldBuilder(number).addVarint(value);
+ return this;
+ }
+
+ /** Check if the given field number is present in the set. */
+ public boolean hasField(final int number) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ return number == lastFieldNumber || fields.containsKey(number);
+ }
+
+ /**
+ * Add a field to the {@code UnknownFieldSet}. If a field with the same
+ * number already exists, it is removed.
+ */
+ public Builder addField(final int number, final Field field) {
+ if (number == 0) {
+ throw new IllegalArgumentException("Zero is not a valid field number.");
+ }
+ if (lastField != null && lastFieldNumber == number) {
+ // Discard this.
+ lastField = null;
+ lastFieldNumber = 0;
+ }
+ if (fields.isEmpty()) {
+ fields = new TreeMap<Integer,Field>();
+ }
+ fields.put(number, field);
+ return this;
+ }
+
+ /**
+ * Get all present {@code Field}s as an immutable {@code Map}. If more
+ * fields are added, the changes may or may not be reflected in this map.
+ */
+ public Map<Integer, Field> asMap() {
+ getFieldBuilder(0); // Force lastField to be built.
+ return Collections.unmodifiableMap(fields);
+ }
+
+ /**
+ * Parse an entire message from {@code input} and merge its fields into
+ * this set.
+ */
+ public Builder mergeFrom(final CodedInputStream input) throws IOException {
+ while (true) {
+ final int tag = input.readTag();
+ if (tag == 0 || !mergeFieldFrom(tag, input)) {
+ break;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Parse a single field from {@code input} and merge it into this set.
+ * @param tag The field's tag number, which was already parsed.
+ * @return {@code false} if the tag is an engroup tag.
+ */
+ public boolean mergeFieldFrom(final int tag, final CodedInputStream input)
+ throws IOException {
+ final int number = WireFormat.getTagFieldNumber(tag);
+ switch (WireFormat.getTagWireType(tag)) {
+ case WireFormat.WIRETYPE_VARINT:
+ getFieldBuilder(number).addVarint(input.readInt64());
+ return true;
+ case WireFormat.WIRETYPE_FIXED64:
+ getFieldBuilder(number).addFixed64(input.readFixed64());
+ return true;
+ case WireFormat.WIRETYPE_LENGTH_DELIMITED:
+ getFieldBuilder(number).addLengthDelimited(input.readBytes());
+ return true;
+ case WireFormat.WIRETYPE_START_GROUP:
+ final Builder subBuilder = newBuilder();
+ input.readGroup(number, subBuilder,
+ ExtensionRegistry.getEmptyRegistry());
+ getFieldBuilder(number).addGroup(subBuilder.build());
+ return true;
+ case WireFormat.WIRETYPE_END_GROUP:
+ return false;
+ case WireFormat.WIRETYPE_FIXED32:
+ getFieldBuilder(number).addFixed32(input.readFixed32());
+ return true;
+ default:
+ throw InvalidProtocolBufferException.invalidWireType();
+ }
+ }
+
+ /**
+ * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(final ByteString data)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input = data.newCodedInput();
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return this;
+ } catch (final InvalidProtocolBufferException e) {
+ throw e;
+ } catch (final IOException e) {
+ throw new RuntimeException(
+ "Reading from a ByteString threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Parse {@code data} as an {@code UnknownFieldSet} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(final byte[] data)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input = CodedInputStream.newInstance(data);
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return this;
+ } catch (final InvalidProtocolBufferException e) {
+ throw e;
+ } catch (final IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ /**
+ * Parse an {@code UnknownFieldSet} from {@code input} and merge it with the
+ * set being built. This is just a small wrapper around
+ * {@link #mergeFrom(CodedInputStream)}.
+ */
+ public Builder mergeFrom(final InputStream input) throws IOException {
+ final CodedInputStream codedInput = CodedInputStream.newInstance(input);
+ mergeFrom(codedInput);
+ codedInput.checkLastTagWas(0);
+ return this;
+ }
+
+ public Builder mergeDelimitedFrom(InputStream input)
+ throws IOException {
+ final int size = CodedInputStream.readRawVarint32(input);
+ final InputStream limitedInput =
+ new AbstractMessage.Builder.LimitedInputStream(input, size);
+ return mergeFrom(limitedInput, null);
+ }
+
+ public Builder mergeDelimitedFrom(
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry) throws IOException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(input);
+ }
+
+ public Builder mergeFrom(
+ CodedInputStream input,
+ ExtensionRegistryLite extensionRegistry) throws IOException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(input);
+ }
+
+ public Builder mergeFrom(
+ ByteString data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(data);
+ }
+
+ public Builder mergeFrom(byte[] data, int off, int len)
+ throws InvalidProtocolBufferException {
+ try {
+ final CodedInputStream input =
+ CodedInputStream.newInstance(data, off, len);
+ mergeFrom(input);
+ input.checkLastTagWas(0);
+ return this;
+ } catch (InvalidProtocolBufferException e) {
+ throw e;
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Reading from a byte array threw an IOException (should " +
+ "never happen).", e);
+ }
+ }
+
+ public Builder mergeFrom(
+ byte[] data,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(data);
+ }
+
+ public Builder mergeFrom(
+ byte[] data, int off, int len,
+ ExtensionRegistryLite extensionRegistry)
+ throws InvalidProtocolBufferException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(data, off, len);
+ }
+
+ public Builder mergeFrom(
+ InputStream input,
+ ExtensionRegistryLite extensionRegistry) throws IOException {
+ // UnknownFieldSet has no extensions.
+ return mergeFrom(input);
+ }
+
+ public boolean isInitialized() {
+ // UnknownFieldSets do not have required fields, so they are always
+ // initialized.
+ return true;
+ }
+ }
+
+ /**
+ * Represents a single field in an {@code UnknownFieldSet}.
+ *
+ * <p>A {@code Field} consists of five lists of values. The lists correspond
+ * to the five "wire types" used in the protocol buffer binary format.
+ * The wire type of each field can be determined from the encoded form alone,
+ * without knowing the field's declared type. So, we are able to parse
+ * unknown values at least this far and separate them. Normally, only one
+ * of the five lists will contain any values, since it is impossible to
+ * define a valid message type that declares two different types for the
+ * same field number. However, the code is designed to allow for the case
+ * where the same unknown field number is encountered using multiple different
+ * wire types.
+ *
+ * <p>{@code Field} is an immutable class. To construct one, you must use a
+ * {@link Builder}.
+ *
+ * @see UnknownFieldSet
+ */
+ public static final class Field {
+ private Field() {}
+
+ /** Construct a new {@link Builder}. */
+ public static Builder newBuilder() {
+ return Builder.create();
+ }
+
+ /**
+ * Construct a new {@link Builder} and initialize it to a copy of
+ * {@code copyFrom}.
+ */
+ public static Builder newBuilder(final Field copyFrom) {
+ return newBuilder().mergeFrom(copyFrom);
+ }
+
+ /** Get an empty {@code Field}. */
+ public static Field getDefaultInstance() {
+ return fieldDefaultInstance;
+ }
+ private static final Field fieldDefaultInstance = newBuilder().build();
+
+ /** Get the list of varint values for this field. */
+ public List<Long> getVarintList() { return varint; }
+
+ /** Get the list of fixed32 values for this field. */
+ public List<Integer> getFixed32List() { return fixed32; }
+
+ /** Get the list of fixed64 values for this field. */
+ public List<Long> getFixed64List() { return fixed64; }
+
+ /** Get the list of length-delimited values for this field. */
+ public List<ByteString> getLengthDelimitedList() { return lengthDelimited; }
+
+ /**
+ * Get the list of embedded group values for this field. These are
+ * represented using {@link UnknownFieldSet}s rather than {@link Message}s
+ * since the group's type is presumably unknown.
+ */
+ public List<UnknownFieldSet> getGroupList() { return group; }
+
+ @Override
+ public boolean equals(final Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Field)) {
+ return false;
+ }
+ return Arrays.equals(getIdentityArray(),
+ ((Field) other).getIdentityArray());
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(getIdentityArray());
+ }
+
+ /**
+ * Returns the array of objects to be used to uniquely identify this
+ * {@link Field} instance.
+ */
+ private Object[] getIdentityArray() {
+ return new Object[] {
+ varint,
+ fixed32,
+ fixed64,
+ lengthDelimited,
+ group};
+ }
+
+ /**
+ * Serializes the field, including field number, and writes it to
+ * {@code output}.
+ */
+ public void writeTo(final int fieldNumber, final CodedOutputStream output)
+ throws IOException {
+ for (final long value : varint) {
+ output.writeUInt64(fieldNumber, value);
+ }
+ for (final int value : fixed32) {
+ output.writeFixed32(fieldNumber, value);
+ }
+ for (final long value : fixed64) {
+ output.writeFixed64(fieldNumber, value);
+ }
+ for (final ByteString value : lengthDelimited) {
+ output.writeBytes(fieldNumber, value);
+ }
+ for (final UnknownFieldSet value : group) {
+ output.writeGroup(fieldNumber, value);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this field, including field
+ * number.
+ */
+ public int getSerializedSize(final int fieldNumber) {
+ int result = 0;
+ for (final long value : varint) {
+ result += CodedOutputStream.computeUInt64Size(fieldNumber, value);
+ }
+ for (final int value : fixed32) {
+ result += CodedOutputStream.computeFixed32Size(fieldNumber, value);
+ }
+ for (final long value : fixed64) {
+ result += CodedOutputStream.computeFixed64Size(fieldNumber, value);
+ }
+ for (final ByteString value : lengthDelimited) {
+ result += CodedOutputStream.computeBytesSize(fieldNumber, value);
+ }
+ for (final UnknownFieldSet value : group) {
+ result += CodedOutputStream.computeGroupSize(fieldNumber, value);
+ }
+ return result;
+ }
+
+ /**
+ * Serializes the field, including field number, and writes it to
+ * {@code output}, using {@code MessageSet} wire format.
+ */
+ public void writeAsMessageSetExtensionTo(
+ final int fieldNumber,
+ final CodedOutputStream output)
+ throws IOException {
+ for (final ByteString value : lengthDelimited) {
+ output.writeRawMessageSetExtension(fieldNumber, value);
+ }
+ }
+
+ /**
+ * Get the number of bytes required to encode this field, including field
+ * number, using {@code MessageSet} wire format.
+ */
+ public int getSerializedSizeAsMessageSetExtension(final int fieldNumber) {
+ int result = 0;
+ for (final ByteString value : lengthDelimited) {
+ result += CodedOutputStream.computeRawMessageSetExtensionSize(
+ fieldNumber, value);
+ }
+ return result;
+ }
+
+ private List<Long> varint;
+ private List<Integer> fixed32;
+ private List<Long> fixed64;
+ private List<ByteString> lengthDelimited;
+ private List<UnknownFieldSet> group;
+
+ /**
+ * Used to build a {@link Field} within an {@link UnknownFieldSet}.
+ *
+ * <p>Use {@link Field#newBuilder()} to construct a {@code Builder}.
+ */
+ public static final class Builder {
+ // This constructor should never be called directly (except from 'create').
+ private Builder() {}
+
+ private static Builder create() {
+ Builder builder = new Builder();
+ builder.result = new Field();
+ return builder;
+ }
+
+ private Field result;
+
+ /**
+ * Build the field. After {@code build()} has been called, the
+ * {@code Builder} is no longer usable. Calling any other method will
+ * result in undefined behavior and can cause a
+ * {@code NullPointerException} to be thrown.
+ */
+ public Field build() {
+ if (result.varint == null) {
+ result.varint = Collections.emptyList();
+ } else {
+ result.varint = Collections.unmodifiableList(result.varint);
+ }
+ if (result.fixed32 == null) {
+ result.fixed32 = Collections.emptyList();
+ } else {
+ result.fixed32 = Collections.unmodifiableList(result.fixed32);
+ }
+ if (result.fixed64 == null) {
+ result.fixed64 = Collections.emptyList();
+ } else {
+ result.fixed64 = Collections.unmodifiableList(result.fixed64);
+ }
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = Collections.emptyList();
+ } else {
+ result.lengthDelimited =
+ Collections.unmodifiableList(result.lengthDelimited);
+ }
+ if (result.group == null) {
+ result.group = Collections.emptyList();
+ } else {
+ result.group = Collections.unmodifiableList(result.group);
+ }
+
+ final Field returnMe = result;
+ result = null;
+ return returnMe;
+ }
+
+ /** Discard the field's contents. */
+ public Builder clear() {
+ result = new Field();
+ return this;
+ }
+
+ /**
+ * Merge the values in {@code other} into this field. For each list
+ * of values, {@code other}'s values are append to the ones in this
+ * field.
+ */
+ public Builder mergeFrom(final Field other) {
+ if (!other.varint.isEmpty()) {
+ if (result.varint == null) {
+ result.varint = new ArrayList<Long>();
+ }
+ result.varint.addAll(other.varint);
+ }
+ if (!other.fixed32.isEmpty()) {
+ if (result.fixed32 == null) {
+ result.fixed32 = new ArrayList<Integer>();
+ }
+ result.fixed32.addAll(other.fixed32);
+ }
+ if (!other.fixed64.isEmpty()) {
+ if (result.fixed64 == null) {
+ result.fixed64 = new ArrayList<Long>();
+ }
+ result.fixed64.addAll(other.fixed64);
+ }
+ if (!other.lengthDelimited.isEmpty()) {
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = new ArrayList<ByteString>();
+ }
+ result.lengthDelimited.addAll(other.lengthDelimited);
+ }
+ if (!other.group.isEmpty()) {
+ if (result.group == null) {
+ result.group = new ArrayList<UnknownFieldSet>();
+ }
+ result.group.addAll(other.group);
+ }
+ return this;
+ }
+
+ /** Add a varint value. */
+ public Builder addVarint(final long value) {
+ if (result.varint == null) {
+ result.varint = new ArrayList<Long>();
+ }
+ result.varint.add(value);
+ return this;
+ }
+
+ /** Add a fixed32 value. */
+ public Builder addFixed32(final int value) {
+ if (result.fixed32 == null) {
+ result.fixed32 = new ArrayList<Integer>();
+ }
+ result.fixed32.add(value);
+ return this;
+ }
+
+ /** Add a fixed64 value. */
+ public Builder addFixed64(final long value) {
+ if (result.fixed64 == null) {
+ result.fixed64 = new ArrayList<Long>();
+ }
+ result.fixed64.add(value);
+ return this;
+ }
+
+ /** Add a length-delimited value. */
+ public Builder addLengthDelimited(final ByteString value) {
+ if (result.lengthDelimited == null) {
+ result.lengthDelimited = new ArrayList<ByteString>();
+ }
+ result.lengthDelimited.add(value);
+ return this;
+ }
+
+ /** Add an embedded group. */
+ public Builder addGroup(final UnknownFieldSet value) {
+ if (result.group == null) {
+ result.group = new ArrayList<UnknownFieldSet>();
+ }
+ result.group.add(value);
+ return this;
+ }
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/WireFormat.java b/java/src/main/java/com/google/protobuf/WireFormat.java
new file mode 100644
index 0000000..3b0bdcd
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/WireFormat.java
@@ -0,0 +1,153 @@
+// 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;
+
+/**
+ * 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 WireFormat {
+ // Do not allow instantiation.
+ private WireFormat() {}
+
+ 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;
+ }
+
+ /**
+ * Lite equivalent to {@link Descriptors.FieldDescriptor.JavaType}. This is
+ * only here to support the lite runtime and should not be used by users.
+ */
+ public enum JavaType {
+ INT(0),
+ LONG(0L),
+ FLOAT(0F),
+ DOUBLE(0D),
+ BOOLEAN(false),
+ STRING(""),
+ BYTE_STRING(ByteString.EMPTY),
+ ENUM(null),
+ MESSAGE(null);
+
+ JavaType(final Object defaultDefault) {
+ this.defaultDefault = defaultDefault;
+ }
+
+ /**
+ * The default default value for fields of this type, if it's a primitive
+ * type.
+ */
+ Object getDefaultDefault() {
+ return defaultDefault;
+ }
+
+ private final Object defaultDefault;
+ }
+
+ /**
+ * Lite equivalent to {@link Descriptors.FieldDescriptor.Type}. This is
+ * only here to support the lite runtime and should not be used by users.
+ */
+ public enum FieldType {
+ DOUBLE (JavaType.DOUBLE , WIRETYPE_FIXED64 ),
+ FLOAT (JavaType.FLOAT , WIRETYPE_FIXED32 ),
+ INT64 (JavaType.LONG , WIRETYPE_VARINT ),
+ UINT64 (JavaType.LONG , WIRETYPE_VARINT ),
+ INT32 (JavaType.INT , WIRETYPE_VARINT ),
+ FIXED64 (JavaType.LONG , WIRETYPE_FIXED64 ),
+ FIXED32 (JavaType.INT , WIRETYPE_FIXED32 ),
+ BOOL (JavaType.BOOLEAN , WIRETYPE_VARINT ),
+ STRING (JavaType.STRING , WIRETYPE_LENGTH_DELIMITED),
+ GROUP (JavaType.MESSAGE , WIRETYPE_START_GROUP ),
+ MESSAGE (JavaType.MESSAGE , WIRETYPE_LENGTH_DELIMITED),
+ BYTES (JavaType.BYTE_STRING, WIRETYPE_LENGTH_DELIMITED),
+ UINT32 (JavaType.INT , WIRETYPE_VARINT ),
+ ENUM (JavaType.ENUM , WIRETYPE_VARINT ),
+ SFIXED32(JavaType.INT , WIRETYPE_FIXED32 ),
+ SFIXED64(JavaType.LONG , WIRETYPE_FIXED64 ),
+ SINT32 (JavaType.INT , WIRETYPE_VARINT ),
+ SINT64 (JavaType.LONG , WIRETYPE_VARINT );
+
+ FieldType(final JavaType javaType, final int wireType) {
+ this.javaType = javaType;
+ this.wireType = wireType;
+ }
+
+ private final JavaType javaType;
+ private final int wireType;
+
+ public JavaType getJavaType() { return javaType; }
+ public int getWireType() { return 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/AbstractMessageTest.java b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
new file mode 100644
index 0000000..2c59fd0
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/AbstractMessageTest.java
@@ -0,0 +1,421 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+
+import junit.framework.TestCase;
+
+import java.util.Map;
+
+/**
+ * Unit test for {@link AbstractMessage}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class AbstractMessageTest extends TestCase {
+ /**
+ * Extends AbstractMessage and wraps some other message object. The methods
+ * of the Message interface which aren't explicitly implemented by
+ * AbstractMessage are forwarded to the wrapped object. This allows us to
+ * test that AbstractMessage's implementations work even if the wrapped
+ * object does not use them.
+ */
+ private static class AbstractMessageWrapper extends AbstractMessage {
+ private final Message wrappedMessage;
+
+ public AbstractMessageWrapper(Message wrappedMessage) {
+ this.wrappedMessage = wrappedMessage;
+ }
+
+ public Descriptors.Descriptor getDescriptorForType() {
+ return wrappedMessage.getDescriptorForType();
+ }
+ public AbstractMessageWrapper getDefaultInstanceForType() {
+ return new AbstractMessageWrapper(
+ wrappedMessage.getDefaultInstanceForType());
+ }
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return wrappedMessage.getAllFields();
+ }
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.hasField(field);
+ }
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.getField(field);
+ }
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ return wrappedMessage.getRepeatedFieldCount(field);
+ }
+ public Object getRepeatedField(
+ Descriptors.FieldDescriptor field, int index) {
+ return wrappedMessage.getRepeatedField(field, index);
+ }
+ public UnknownFieldSet getUnknownFields() {
+ return wrappedMessage.getUnknownFields();
+ }
+ public Builder newBuilderForType() {
+ return new Builder(wrappedMessage.newBuilderForType());
+ }
+ public Builder toBuilder() {
+ return new Builder(wrappedMessage.toBuilder());
+ }
+
+ static class Builder extends AbstractMessage.Builder<Builder> {
+ private final Message.Builder wrappedBuilder;
+
+ public Builder(Message.Builder wrappedBuilder) {
+ this.wrappedBuilder = wrappedBuilder;
+ }
+
+ public AbstractMessageWrapper build() {
+ return new AbstractMessageWrapper(wrappedBuilder.build());
+ }
+ public AbstractMessageWrapper buildPartial() {
+ return new AbstractMessageWrapper(wrappedBuilder.buildPartial());
+ }
+ public Builder clone() {
+ return new Builder(wrappedBuilder.clone());
+ }
+ public boolean isInitialized() {
+ return clone().buildPartial().isInitialized();
+ }
+ public Descriptors.Descriptor getDescriptorForType() {
+ return wrappedBuilder.getDescriptorForType();
+ }
+ public AbstractMessageWrapper getDefaultInstanceForType() {
+ return new AbstractMessageWrapper(
+ wrappedBuilder.getDefaultInstanceForType());
+ }
+ public Map<Descriptors.FieldDescriptor, Object> getAllFields() {
+ return wrappedBuilder.getAllFields();
+ }
+ public Builder newBuilderForField(Descriptors.FieldDescriptor field) {
+ return new Builder(wrappedBuilder.newBuilderForField(field));
+ }
+ public boolean hasField(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.hasField(field);
+ }
+ public Object getField(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.getField(field);
+ }
+ public Builder setField(Descriptors.FieldDescriptor field, Object value) {
+ wrappedBuilder.setField(field, value);
+ return this;
+ }
+ public Builder clearField(Descriptors.FieldDescriptor field) {
+ wrappedBuilder.clearField(field);
+ return this;
+ }
+ public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) {
+ return wrappedBuilder.getRepeatedFieldCount(field);
+ }
+ public Object getRepeatedField(
+ Descriptors.FieldDescriptor field, int index) {
+ return wrappedBuilder.getRepeatedField(field, index);
+ }
+ public Builder setRepeatedField(Descriptors.FieldDescriptor field,
+ int index, Object value) {
+ wrappedBuilder.setRepeatedField(field, index, value);
+ return this;
+ }
+ public Builder addRepeatedField(
+ Descriptors.FieldDescriptor field, Object value) {
+ wrappedBuilder.addRepeatedField(field, value);
+ return this;
+ }
+ public UnknownFieldSet getUnknownFields() {
+ return wrappedBuilder.getUnknownFields();
+ }
+ public Builder setUnknownFields(UnknownFieldSet unknownFields) {
+ wrappedBuilder.setUnknownFields(unknownFields);
+ return this;
+ }
+ }
+ }
+
+ // =================================================================
+
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+
+ public void testClear() throws Exception {
+ AbstractMessageWrapper message =
+ new AbstractMessageWrapper.Builder(
+ TestAllTypes.newBuilder(TestUtil.getAllSet()))
+ .clear().build();
+ TestUtil.assertClear((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testCopy() throws Exception {
+ AbstractMessageWrapper message =
+ new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder())
+ .mergeFrom(TestUtil.getAllSet()).build();
+ TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testSerializedSize() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+ Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+ assertEquals(message.getSerializedSize(),
+ abstractMessage.getSerializedSize());
+ }
+
+ public void testSerialization() throws Exception {
+ Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet());
+
+ TestUtil.assertAllFieldsSet(
+ TestAllTypes.parseFrom(abstractMessage.toByteString()));
+
+ assertEquals(TestUtil.getAllSet().toByteString(),
+ abstractMessage.toByteString());
+ }
+
+ public void testParsing() throws Exception {
+ AbstractMessageWrapper.Builder builder =
+ new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder());
+ AbstractMessageWrapper message =
+ builder.mergeFrom(TestUtil.getAllSet().toByteString()).build();
+ TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage);
+ }
+
+ public void testPackedSerialization() throws Exception {
+ Message abstractMessage =
+ new AbstractMessageWrapper(TestUtil.getPackedSet());
+
+ TestUtil.assertPackedFieldsSet(
+ TestPackedTypes.parseFrom(abstractMessage.toByteString()));
+
+ assertEquals(TestUtil.getPackedSet().toByteString(),
+ abstractMessage.toByteString());
+ }
+
+ public void testPackedParsing() throws Exception {
+ AbstractMessageWrapper.Builder builder =
+ new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder());
+ AbstractMessageWrapper message =
+ builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build();
+ TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage);
+ }
+
+ public void testOptimizedForSize() throws Exception {
+ // We're mostly only checking that this class was compiled successfully.
+ TestOptimizedForSize message =
+ TestOptimizedForSize.newBuilder().setI(1).build();
+ message = TestOptimizedForSize.parseFrom(message.toByteString());
+ assertEquals(2, message.getSerializedSize());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for isInitialized().
+
+ private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ TestRequired.getDefaultInstance();
+ private static final TestRequired TEST_REQUIRED_INITIALIZED =
+ TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+ public void testIsInitialized() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+ AbstractMessageWrapper.Builder abstractBuilder =
+ new AbstractMessageWrapper.Builder(builder);
+
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setA(1);
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setB(1);
+ assertFalse(abstractBuilder.isInitialized());
+ builder.setC(1);
+ assertTrue(abstractBuilder.isInitialized());
+ }
+
+ public void testForeignIsInitialized() throws Exception {
+ TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+ AbstractMessageWrapper.Builder abstractBuilder =
+ new AbstractMessageWrapper.Builder(builder);
+
+ assertTrue(abstractBuilder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(abstractBuilder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+ assertTrue(abstractBuilder.isInitialized());
+
+ builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(abstractBuilder.isInitialized());
+
+ builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(abstractBuilder.isInitialized());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for mergeFrom
+
+ static final TestAllTypes MERGE_SOURCE =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedString("bar")
+ .build();
+
+ static final TestAllTypes MERGE_DEST =
+ TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+ .addRepeatedString("qux")
+ .build();
+
+ static final String MERGE_RESULT_TEXT =
+ "optional_int32: 1\n" +
+ "optional_int64: 2\n" +
+ "optional_string: \"foo\"\n" +
+ "optional_foreign_message {\n" +
+ " c: 3\n" +
+ "}\n" +
+ "repeated_string: \"qux\"\n" +
+ "repeated_string: \"bar\"\n";
+
+ public void testMergeFrom() throws Exception {
+ AbstractMessageWrapper result =
+ new AbstractMessageWrapper.Builder(
+ TestAllTypes.newBuilder(MERGE_DEST))
+ .mergeFrom(MERGE_SOURCE).build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ // -----------------------------------------------------------------
+ // Tests for equals and hashCode
+
+ public void testEqualsAndHashCode() throws Exception {
+ TestAllTypes a = TestUtil.getAllSet();
+ TestAllTypes b = TestAllTypes.newBuilder().build();
+ TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build();
+ TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build();
+ TestAllExtensions e = TestUtil.getAllExtensionsSet();
+ TestAllExtensions f = TestAllExtensions.newBuilder(e)
+ .addExtension(UnittestProto.repeatedInt32Extension, 999).build();
+
+ checkEqualsIsConsistent(a);
+ checkEqualsIsConsistent(b);
+ checkEqualsIsConsistent(c);
+ checkEqualsIsConsistent(d);
+ checkEqualsIsConsistent(e);
+ checkEqualsIsConsistent(f);
+
+ checkNotEqual(a, b);
+ checkNotEqual(a, c);
+ checkNotEqual(a, d);
+ checkNotEqual(a, e);
+ checkNotEqual(a, f);
+
+ checkNotEqual(b, c);
+ checkNotEqual(b, d);
+ checkNotEqual(b, e);
+ checkNotEqual(b, f);
+
+ checkNotEqual(c, d);
+ checkNotEqual(c, e);
+ checkNotEqual(c, f);
+
+ checkNotEqual(d, e);
+ checkNotEqual(d, f);
+
+ checkNotEqual(e, f);
+
+ // Deserializing into the TestEmptyMessage such that every field
+ // is an {@link UnknownFieldSet.Field}.
+ UnittestProto.TestEmptyMessage eUnknownFields =
+ UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+ UnittestProto.TestEmptyMessage fUnknownFields =
+ UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray());
+ checkNotEqual(eUnknownFields, fUnknownFields);
+ checkEqualsIsConsistent(eUnknownFields);
+ checkEqualsIsConsistent(fUnknownFields);
+
+ // Subseqent reconstitutions should be identical
+ UnittestProto.TestEmptyMessage eUnknownFields2 =
+ UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray());
+ checkEqualsIsConsistent(eUnknownFields, eUnknownFields2);
+ }
+
+ /**
+ * Asserts that the given proto has symetric equals and hashCode methods.
+ */
+ private void checkEqualsIsConsistent(Message message) {
+ // Object should be equal to itself.
+ assertEquals(message, message);
+
+ // Object should be equal to a dynamic copy of itself.
+ DynamicMessage dynamic = DynamicMessage.newBuilder(message).build();
+ checkEqualsIsConsistent(message, dynamic);
+ }
+
+ /**
+ * Asserts that the given protos are equal and have the same hash code.
+ */
+ private void checkEqualsIsConsistent(Message message1, Message message2) {
+ assertEquals(message1, message2);
+ assertEquals(message2, message1);
+ assertEquals(message2.hashCode(), message1.hashCode());
+ }
+
+ /**
+ * Asserts that the given protos are not equal and have different hash codes.
+ *
+ * @warning It's valid for non-equal objects to have the same hash code, so
+ * this test is stricter than it needs to be. However, this should happen
+ * relatively rarely.
+ */
+ private void checkNotEqual(Message m1, Message m2) {
+ String equalsError = String.format("%s should not be equal to %s", m1, m2);
+ assertFalse(equalsError, m1.equals(m2));
+ assertFalse(equalsError, m2.equals(m1));
+
+ assertFalse(
+ String.format("%s should have a different hash code from %s", m1, m2),
+ m1.hashCode() == m2.hashCode());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
new file mode 100644
index 0000000..850b8aa
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -0,0 +1,486 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestRecursiveMessage;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.FilterInputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * Unit test for {@link CodedInputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedInputStreamTest extends TestCase {
+ /**
+ * Helper to construct a byte array from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private byte[] bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return bytes;
+ }
+
+ /**
+ * An InputStream which limits the number of bytes it reads at a time.
+ * We use this to make sure that CodedInputStream doesn't screw up when
+ * reading in small blocks.
+ */
+ private static final class SmallBlockInputStream extends FilterInputStream {
+ private final int blockSize;
+
+ public SmallBlockInputStream(byte[] data, int blockSize) {
+ this(new ByteArrayInputStream(data), blockSize);
+ }
+
+ public SmallBlockInputStream(InputStream in, int blockSize) {
+ super(in);
+ this.blockSize = blockSize;
+ }
+
+ public int read(byte[] b) throws IOException {
+ return super.read(b, 0, Math.min(b.length, blockSize));
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ return super.read(b, off, Math.min(len, blockSize));
+ }
+ }
+
+ /**
+ * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+ * checks that the result matches the given value.
+ */
+ private void assertReadVarint(byte[] data, long value) throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals((int)value, input.readRawVarint32());
+
+ input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawVarint64());
+ assertTrue(input.isAtEnd());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals((int)value, input.readRawVarint32());
+
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawVarint64());
+ assertTrue(input.isAtEnd());
+ }
+
+ // Try reading direct from an InputStream. We want to verify that it
+ // doesn't read past the end of the input, so we copy to a new, bigger
+ // array first.
+ byte[] longerData = new byte[data.length + 1];
+ System.arraycopy(data, 0, longerData, 0, data.length);
+ InputStream rawInput = new ByteArrayInputStream(longerData);
+ assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput));
+ assertEquals(1, rawInput.available());
+ }
+
+ /**
+ * Parses the given bytes using readRawVarint32() and readRawVarint64() and
+ * expects them to fail with an InvalidProtocolBufferException whose
+ * description matches the given one.
+ */
+ private void assertReadVarintFailure(
+ InvalidProtocolBufferException expected, byte[] data)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ try {
+ input.readRawVarint32();
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+
+ input = CodedInputStream.newInstance(data);
+ try {
+ input.readRawVarint64();
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+
+ // Make sure we get the same error when reading direct from an InputStream.
+ try {
+ CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(expected.getMessage(), e.getMessage());
+ }
+ }
+
+ /** Tests readRawVarint32() and readRawVarint64(). */
+ public void testReadVarint() throws Exception {
+ assertReadVarint(bytes(0x00), 0);
+ assertReadVarint(bytes(0x01), 1);
+ assertReadVarint(bytes(0x7f), 127);
+ // 14882
+ assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+ // 2961488830
+ assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x0bL << 28));
+
+ // 64-bit
+ // 7256456126
+ assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x1bL << 28));
+ // 41256202580718336
+ assertReadVarint(
+ bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+ (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ // 11964378330978735131
+ assertReadVarint(
+ bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+ (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+ (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+
+ // Failures
+ assertReadVarintFailure(
+ InvalidProtocolBufferException.malformedVarint(),
+ bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x00));
+ assertReadVarintFailure(
+ InvalidProtocolBufferException.truncatedMessage(),
+ bytes(0x80));
+ }
+
+ /**
+ * Parses the given bytes using readRawLittleEndian32() and checks
+ * that the result matches the given value.
+ */
+ private void assertReadLittleEndian32(byte[] data, int value)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawLittleEndian32());
+ assertTrue(input.isAtEnd());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawLittleEndian32());
+ assertTrue(input.isAtEnd());
+ }
+ }
+
+ /**
+ * Parses the given bytes using readRawLittleEndian64() and checks
+ * that the result matches the given value.
+ */
+ private void assertReadLittleEndian64(byte[] data, long value)
+ throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(data);
+ assertEquals(value, input.readRawLittleEndian64());
+ assertTrue(input.isAtEnd());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(data, blockSize));
+ assertEquals(value, input.readRawLittleEndian64());
+ assertTrue(input.isAtEnd());
+ }
+ }
+
+ /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
+ public void testReadLittleEndian() throws Exception {
+ assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+ assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+ assertReadLittleEndian64(
+ bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+ 0x123456789abcdef0L);
+ assertReadLittleEndian64(
+ bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+ 0x9abcdef012345678L);
+ }
+
+ /** Test decodeZigZag32() and decodeZigZag64(). */
+ public void testDecodeZigZag() throws Exception {
+ assertEquals( 0, CodedInputStream.decodeZigZag32(0));
+ assertEquals(-1, CodedInputStream.decodeZigZag32(1));
+ assertEquals( 1, CodedInputStream.decodeZigZag32(2));
+ assertEquals(-2, CodedInputStream.decodeZigZag32(3));
+ assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
+ assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
+ assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
+ assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
+
+ assertEquals( 0, CodedInputStream.decodeZigZag64(0));
+ assertEquals(-1, CodedInputStream.decodeZigZag64(1));
+ assertEquals( 1, CodedInputStream.decodeZigZag64(2));
+ assertEquals(-2, CodedInputStream.decodeZigZag64(3));
+ assertEquals(0x000000003FFFFFFFL,
+ CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
+ assertEquals(0xFFFFFFFFC0000000L,
+ CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
+ assertEquals(0x000000007FFFFFFFL,
+ CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
+ assertEquals(0xFFFFFFFF80000000L,
+ CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
+ assertEquals(0x7FFFFFFFFFFFFFFFL,
+ CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
+ assertEquals(0x8000000000000000L,
+ CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
+ }
+
+ /** Tests reading and parsing a whole message with every field type. */
+ public void testReadWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ byte[] rawBytes = message.toByteArray();
+ assertEquals(rawBytes.length, message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+ TestUtil.assertAllFieldsSet(message2);
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+ message2 = TestAllTypes.parseFrom(
+ new SmallBlockInputStream(rawBytes, blockSize));
+ TestUtil.assertAllFieldsSet(message2);
+ }
+ }
+
+ /** Tests skipField(). */
+ public void testSkipWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+ byte[] rawBytes = message.toByteArray();
+
+ // Create two parallel inputs. Parse one as unknown fields while using
+ // skipField() to skip each field on the other. Expect the same tags.
+ CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
+ CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
+ UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
+
+ while (true) {
+ int tag = input1.readTag();
+ assertEquals(tag, input2.readTag());
+ if (tag == 0) {
+ break;
+ }
+ unknownFields.mergeFieldFrom(tag, input1);
+ input2.skipField(tag);
+ }
+ }
+
+ /**
+ * Test that a bug in skipRawBytes() has been fixed: if the skip skips
+ * exactly up to a limit, this should not break things.
+ */
+ public void testSkipRawBytesBug() throws Exception {
+ byte[] rawBytes = new byte[] { 1, 2 };
+ CodedInputStream input = CodedInputStream.newInstance(rawBytes);
+
+ int limit = input.pushLimit(1);
+ input.skipRawBytes(1);
+ input.popLimit(limit);
+ assertEquals(2, input.readRawByte());
+ }
+
+ public void testReadHugeBlob() throws Exception {
+ // Allocate and initialize a 1MB blob.
+ byte[] blob = new byte[1 << 20];
+ for (int i = 0; i < blob.length; i++) {
+ blob[i] = (byte)i;
+ }
+
+ // Make a message containing it.
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ builder.setOptionalBytes(ByteString.copyFrom(blob));
+ TestAllTypes message = builder.build();
+
+ // Serialize and parse it. Make sure to parse from an InputStream, not
+ // directly from a ByteString, so that CodedInputStream uses buffered
+ // reading.
+ TestAllTypes message2 =
+ TestAllTypes.parseFrom(message.toByteString().newInput());
+
+ assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
+
+ // Make sure all the other fields were parsed correctly.
+ TestAllTypes message3 = TestAllTypes.newBuilder(message2)
+ .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
+ .build();
+ TestUtil.assertAllFieldsSet(message3);
+ }
+
+ public void testReadMaliciouslyLargeBlob() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(0x7FFFFFFF);
+ output.writeRawBytes(new byte[32]); // Pad with a few random bytes.
+ output.flush();
+
+ CodedInputStream input = rawOutput.toByteString().newCodedInput();
+ assertEquals(tag, input.readTag());
+
+ try {
+ input.readBytes();
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ private TestRecursiveMessage makeRecursiveMessage(int depth) {
+ if (depth == 0) {
+ return TestRecursiveMessage.newBuilder().setI(5).build();
+ } else {
+ return TestRecursiveMessage.newBuilder()
+ .setA(makeRecursiveMessage(depth - 1)).build();
+ }
+ }
+
+ private void assertMessageDepth(TestRecursiveMessage message, int depth) {
+ if (depth == 0) {
+ assertFalse(message.hasA());
+ assertEquals(5, message.getI());
+ } else {
+ assertTrue(message.hasA());
+ assertMessageDepth(message.getA(), depth - 1);
+ }
+ }
+
+ public void testMaliciousRecursion() throws Exception {
+ ByteString data64 = makeRecursiveMessage(64).toByteString();
+ ByteString data65 = makeRecursiveMessage(65).toByteString();
+
+ assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64);
+
+ try {
+ TestRecursiveMessage.parseFrom(data65);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+
+ CodedInputStream input = data64.newCodedInput();
+ input.setRecursionLimit(8);
+ try {
+ TestRecursiveMessage.parseFrom(input);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ public void testSizeLimit() throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(
+ TestUtil.getAllSet().toByteString().newInput());
+ input.setSizeLimit(16);
+
+ try {
+ TestAllTypes.parseFrom(input);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ public void testResetSizeCounter() throws Exception {
+ CodedInputStream input = CodedInputStream.newInstance(
+ new SmallBlockInputStream(new byte[256], 8));
+ input.setSizeLimit(16);
+ input.readRawBytes(16);
+
+ try {
+ input.readRawByte();
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+
+ input.resetSizeCounter();
+ input.readRawByte(); // No exception thrown.
+
+ try {
+ input.readRawBytes(16); // Hits limit again.
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ // success.
+ }
+ }
+
+ /**
+ * Tests that if we read an string that contains invalid UTF-8, no exception
+ * is thrown. Instead, the invalid bytes are replaced with the Unicode
+ * "replacement character" U+FFFD.
+ */
+ public void testReadInvalidUtf8() throws Exception {
+ ByteString.Output rawOutput = ByteString.newOutput();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+
+ int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(tag);
+ output.writeRawVarint32(1);
+ output.writeRawBytes(new byte[] { (byte)0x80 });
+ output.flush();
+
+ CodedInputStream input = rawOutput.toByteString().newCodedInput();
+ assertEquals(tag, input.readTag());
+ String text = input.readString();
+ assertEquals(0xfffd, text.charAt(0));
+ }
+
+ public void testReadFromSlice() throws Exception {
+ byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
+ CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
+ for (int i = 3; i < 8; i++) {
+ assertEquals(i, in.readRawByte());
+ }
+ // eof
+ assertEquals(0, in.readTag());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
new file mode 100644
index 0000000..c42b485
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/CodedOutputStreamTest.java
@@ -0,0 +1,304 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Unit test for {@link CodedOutputStream}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class CodedOutputStreamTest extends TestCase {
+ /**
+ * Helper to construct a byte array from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private byte[] bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return bytes;
+ }
+
+ /** Arrays.asList() does not work with arrays of primitives. :( */
+ private List<Byte> toList(byte[] bytes) {
+ List<Byte> result = new ArrayList<Byte>();
+ for (byte b : bytes) {
+ result.add(b);
+ }
+ return result;
+ }
+
+ private void assertEqualBytes(byte[] a, byte[] b) {
+ assertEquals(toList(a), toList(b));
+ }
+
+ /**
+ * Writes the given value using writeRawVarint32() and writeRawVarint64() and
+ * checks that the result matches the given bytes.
+ */
+ private void assertWriteVarint(byte[] data, long value) throws Exception {
+ // Only do 32-bit write if the value fits in 32 bits.
+ if ((value >>> 32) == 0) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint32((int) value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length,
+ CodedOutputStream.computeRawVarint32Size((int) value));
+ }
+
+ {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawVarint64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Also try computing size.
+ assertEquals(data.length,
+ CodedOutputStream.computeRawVarint64Size(value));
+ }
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ // Only do 32-bit write if the value fits in 32 bits.
+ if ((value >>> 32) == 0) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawVarint32((int) value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+
+ {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawVarint64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+ }
+
+ /** Tests writeRawVarint32() and writeRawVarint64(). */
+ public void testWriteVarint() throws Exception {
+ assertWriteVarint(bytes(0x00), 0);
+ assertWriteVarint(bytes(0x01), 1);
+ assertWriteVarint(bytes(0x7f), 127);
+ // 14882
+ assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
+ // 2961488830
+ assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x0bL << 28));
+
+ // 64-bit
+ // 7256456126
+ assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
+ (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
+ (0x1bL << 28));
+ // 41256202580718336
+ assertWriteVarint(
+ bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
+ (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
+ (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
+ // 11964378330978735131
+ assertWriteVarint(
+ bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
+ (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
+ (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
+ (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian32() and checks
+ * that the result matches the given value.
+ */
+ private void assertWriteLittleEndian32(byte[] data, int value)
+ throws Exception {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawLittleEndian32(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ rawOutput = new ByteArrayOutputStream();
+ output = CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawLittleEndian32(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+
+ /**
+ * Parses the given bytes using writeRawLittleEndian64() and checks
+ * that the result matches the given value.
+ */
+ private void assertWriteLittleEndian64(byte[] data, long value)
+ throws Exception {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
+ output.writeRawLittleEndian64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
+ rawOutput = new ByteArrayOutputStream();
+ output = CodedOutputStream.newInstance(rawOutput, blockSize);
+ output.writeRawLittleEndian64(value);
+ output.flush();
+ assertEqualBytes(data, rawOutput.toByteArray());
+ }
+ }
+
+ /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */
+ public void testWriteLittleEndian() throws Exception {
+ assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
+ assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
+
+ assertWriteLittleEndian64(
+ bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
+ 0x123456789abcdef0L);
+ assertWriteLittleEndian64(
+ bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
+ 0x9abcdef012345678L);
+ }
+
+ /** Test encodeZigZag32() and encodeZigZag64(). */
+ public void testEncodeZigZag() throws Exception {
+ assertEquals(0, CodedOutputStream.encodeZigZag32( 0));
+ assertEquals(1, CodedOutputStream.encodeZigZag32(-1));
+ assertEquals(2, CodedOutputStream.encodeZigZag32( 1));
+ assertEquals(3, CodedOutputStream.encodeZigZag32(-2));
+ assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF));
+ assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000));
+ assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF));
+ assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000));
+
+ assertEquals(0, CodedOutputStream.encodeZigZag64( 0));
+ assertEquals(1, CodedOutputStream.encodeZigZag64(-1));
+ assertEquals(2, CodedOutputStream.encodeZigZag64( 1));
+ assertEquals(3, CodedOutputStream.encodeZigZag64(-2));
+ assertEquals(0x000000007FFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL));
+ assertEquals(0x000000007FFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L));
+ assertEquals(0x00000000FFFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL));
+ assertEquals(0x00000000FFFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L));
+ assertEquals(0xFFFFFFFFFFFFFFFEL,
+ CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL));
+ assertEquals(0xFFFFFFFFFFFFFFFFL,
+ CodedOutputStream.encodeZigZag64(0x8000000000000000L));
+
+ // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1)
+ // were chosen semi-randomly via keyboard bashing.
+ assertEquals(0,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0)));
+ assertEquals(1,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1)));
+ assertEquals(-1,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1)));
+ assertEquals(14927,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927)));
+ assertEquals(-3612,
+ CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612)));
+
+ assertEquals(0,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0)));
+ assertEquals(1,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1)));
+ assertEquals(-1,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1)));
+ assertEquals(14927,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927)));
+ assertEquals(-3612,
+ CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612)));
+
+ assertEquals(856912304801416L,
+ CodedOutputStream.encodeZigZag64(
+ CodedInputStream.decodeZigZag64(
+ 856912304801416L)));
+ assertEquals(-75123905439571256L,
+ CodedOutputStream.encodeZigZag64(
+ CodedInputStream.decodeZigZag64(
+ -75123905439571256L)));
+ }
+
+ /** Tests writing a whole message with every field type. */
+ public void testWriteWholeMessage() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ byte[] rawBytes = message.toByteArray();
+ assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes);
+
+ // Try different block sizes.
+ for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
+ ByteArrayOutputStream rawOutput = new ByteArrayOutputStream();
+ CodedOutputStream output =
+ CodedOutputStream.newInstance(rawOutput, blockSize);
+ message.writeTo(output);
+ output.flush();
+ assertEqualBytes(rawBytes, rawOutput.toByteArray());
+ }
+ }
+
+ /** Tests writing a whole message with every packed field type. Ensures the
+ * wire format of packed fields is compatible with C++. */
+ public void testWriteWholePackedFieldsMessage() throws Exception {
+ TestPackedTypes message = TestUtil.getPackedSet();
+
+ byte[] rawBytes = message.toByteArray();
+ assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(),
+ rawBytes);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
new file mode 100644
index 0000000..c5c38b2
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/DescriptorsTest.java
@@ -0,0 +1,408 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FileDescriptor;
+import com.google.protobuf.Descriptors.Descriptor;
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import com.google.protobuf.Descriptors.EnumDescriptor;
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
+import com.google.protobuf.Descriptors.ServiceDescriptor;
+import com.google.protobuf.Descriptors.MethodDescriptor;
+
+import com.google.protobuf.test.UnittestImport;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestService;
+import protobuf_unittest.UnittestCustomOptions;
+
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * Unit test for {@link Descriptors}.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DescriptorsTest extends TestCase {
+ public void testFileDescriptor() throws Exception {
+ FileDescriptor file = UnittestProto.getDescriptor();
+
+ assertEquals("google/protobuf/unittest.proto", file.getName());
+ assertEquals("protobuf_unittest", file.getPackage());
+
+ assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
+ assertEquals("google/protobuf/unittest.proto",
+ file.toProto().getName());
+
+ assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
+ file.getDependencies());
+
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ assertEquals(messageType, file.getMessageTypes().get(0));
+ assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
+ assertNull(file.findMessageTypeByName("NoSuchType"));
+ assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
+ for (int i = 0; i < file.getMessageTypes().size(); i++) {
+ assertEquals(i, file.getMessageTypes().get(i).getIndex());
+ }
+
+ EnumDescriptor enumType = ForeignEnum.getDescriptor();
+ assertEquals(enumType, file.getEnumTypes().get(0));
+ assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
+ assertNull(file.findEnumTypeByName("NoSuchType"));
+ assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
+ assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
+ UnittestImport.getDescriptor().getEnumTypes());
+ for (int i = 0; i < file.getEnumTypes().size(); i++) {
+ assertEquals(i, file.getEnumTypes().get(i).getIndex());
+ }
+
+ ServiceDescriptor service = TestService.getDescriptor();
+ assertEquals(service, file.getServices().get(0));
+ assertEquals(service, file.findServiceByName("TestService"));
+ assertNull(file.findServiceByName("NoSuchType"));
+ assertNull(file.findServiceByName("protobuf_unittest.TestService"));
+ assertEquals(Collections.emptyList(),
+ UnittestImport.getDescriptor().getServices());
+ for (int i = 0; i < file.getServices().size(); i++) {
+ assertEquals(i, file.getServices().get(i).getIndex());
+ }
+
+ FieldDescriptor extension =
+ UnittestProto.optionalInt32Extension.getDescriptor();
+ assertEquals(extension, file.getExtensions().get(0));
+ assertEquals(extension,
+ file.findExtensionByName("optional_int32_extension"));
+ assertNull(file.findExtensionByName("no_such_ext"));
+ assertNull(file.findExtensionByName(
+ "protobuf_unittest.optional_int32_extension"));
+ assertEquals(Collections.emptyList(),
+ UnittestImport.getDescriptor().getExtensions());
+ for (int i = 0; i < file.getExtensions().size(); i++) {
+ assertEquals(i, file.getExtensions().get(i).getIndex());
+ }
+ }
+
+ public void testDescriptor() throws Exception {
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
+
+ assertEquals("TestAllTypes", messageType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
+ assertNull(messageType.getContainingType());
+ assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
+ messageType.getOptions());
+ assertEquals("TestAllTypes", messageType.toProto().getName());
+
+ assertEquals("NestedMessage", nestedType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
+ nestedType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+ assertEquals(messageType, nestedType.getContainingType());
+
+ FieldDescriptor field = messageType.getFields().get(0);
+ assertEquals("optional_int32", field.getName());
+ assertEquals(field, messageType.findFieldByName("optional_int32"));
+ assertNull(messageType.findFieldByName("no_such_field"));
+ assertEquals(field, messageType.findFieldByNumber(1));
+ assertNull(messageType.findFieldByNumber(571283));
+ for (int i = 0; i < messageType.getFields().size(); i++) {
+ assertEquals(i, messageType.getFields().get(i).getIndex());
+ }
+
+ assertEquals(nestedType, messageType.getNestedTypes().get(0));
+ assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
+ assertNull(messageType.findNestedTypeByName("NoSuchType"));
+ for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
+ assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
+ }
+
+ EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
+ assertEquals(enumType, messageType.getEnumTypes().get(0));
+ assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
+ assertNull(messageType.findEnumTypeByName("NoSuchType"));
+ for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
+ assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
+ }
+ }
+
+ public void testFieldDescriptor() throws Exception {
+ Descriptor messageType = TestAllTypes.getDescriptor();
+ FieldDescriptor primitiveField =
+ messageType.findFieldByName("optional_int32");
+ FieldDescriptor enumField =
+ messageType.findFieldByName("optional_nested_enum");
+ FieldDescriptor messageField =
+ messageType.findFieldByName("optional_foreign_message");
+ FieldDescriptor cordField =
+ messageType.findFieldByName("optional_cord");
+ FieldDescriptor extension =
+ UnittestProto.optionalInt32Extension.getDescriptor();
+ FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
+
+ assertEquals("optional_int32", primitiveField.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
+ primitiveField.getFullName());
+ assertEquals(1, primitiveField.getNumber());
+ assertEquals(messageType, primitiveField.getContainingType());
+ assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
+ assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
+ assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+ primitiveField.getOptions());
+ assertFalse(primitiveField.isExtension());
+ assertEquals("optional_int32", primitiveField.toProto().getName());
+
+ assertEquals("optional_nested_enum", enumField.getName());
+ assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
+ assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
+ assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
+ enumField.getEnumType());
+
+ assertEquals("optional_foreign_message", messageField.getName());
+ assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
+ assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
+ assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
+
+ assertEquals("optional_cord", cordField.getName());
+ assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
+ assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
+ cordField.getOptions().getCtype());
+
+ assertEquals("optional_int32_extension", extension.getName());
+ assertEquals("protobuf_unittest.optional_int32_extension",
+ extension.getFullName());
+ assertEquals(1, extension.getNumber());
+ assertEquals(TestAllExtensions.getDescriptor(),
+ extension.getContainingType());
+ assertEquals(UnittestProto.getDescriptor(), extension.getFile());
+ assertEquals(FieldDescriptor.Type.INT32, extension.getType());
+ assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
+ assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
+ extension.getOptions());
+ assertTrue(extension.isExtension());
+ assertEquals(null, extension.getExtensionScope());
+ assertEquals("optional_int32_extension", extension.toProto().getName());
+
+ assertEquals("single", nestedExtension.getName());
+ assertEquals("protobuf_unittest.TestRequired.single",
+ nestedExtension.getFullName());
+ assertEquals(TestRequired.getDescriptor(),
+ nestedExtension.getExtensionScope());
+ }
+
+ public void testFieldDescriptorLabel() throws Exception {
+ FieldDescriptor requiredField =
+ TestRequired.getDescriptor().findFieldByName("a");
+ FieldDescriptor optionalField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_int32");
+ FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
+
+ assertTrue(requiredField.isRequired());
+ assertFalse(requiredField.isRepeated());
+ assertFalse(optionalField.isRequired());
+ assertFalse(optionalField.isRepeated());
+ assertFalse(repeatedField.isRequired());
+ assertTrue(repeatedField.isRepeated());
+ }
+
+ public void testFieldDescriptorDefault() throws Exception {
+ Descriptor d = TestAllTypes.getDescriptor();
+ assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
+ assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
+ assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
+ assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
+
+ d = TestExtremeDefaultValues.getDescriptor();
+ assertEquals(
+ ByteString.copyFrom(
+ "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
+ d.findFieldByName("escaped_bytes").getDefaultValue());
+ assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
+ assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
+ }
+
+ public void testEnumDescriptor() throws Exception {
+ EnumDescriptor enumType = ForeignEnum.getDescriptor();
+ EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
+
+ assertEquals("ForeignEnum", enumType.getName());
+ assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
+ assertNull(enumType.getContainingType());
+ assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
+ enumType.getOptions());
+
+ assertEquals("NestedEnum", nestedType.getName());
+ assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
+ nestedType.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
+ assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
+
+ EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
+ assertEquals(value, enumType.getValues().get(0));
+ assertEquals("FOREIGN_FOO", value.getName());
+ assertEquals(4, value.getNumber());
+ assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
+ assertEquals(value, enumType.findValueByNumber(4));
+ assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
+ for (int i = 0; i < enumType.getValues().size(); i++) {
+ assertEquals(i, enumType.getValues().get(i).getIndex());
+ }
+ }
+
+ public void testServiceDescriptor() throws Exception {
+ ServiceDescriptor service = TestService.getDescriptor();
+
+ assertEquals("TestService", service.getName());
+ assertEquals("protobuf_unittest.TestService", service.getFullName());
+ assertEquals(UnittestProto.getDescriptor(), service.getFile());
+
+ assertEquals(2, service.getMethods().size());
+
+ MethodDescriptor fooMethod = service.getMethods().get(0);
+ assertEquals("Foo", fooMethod.getName());
+ assertEquals(UnittestProto.FooRequest.getDescriptor(),
+ fooMethod.getInputType());
+ assertEquals(UnittestProto.FooResponse.getDescriptor(),
+ fooMethod.getOutputType());
+ assertEquals(fooMethod, service.findMethodByName("Foo"));
+
+ MethodDescriptor barMethod = service.getMethods().get(1);
+ assertEquals("Bar", barMethod.getName());
+ assertEquals(UnittestProto.BarRequest.getDescriptor(),
+ barMethod.getInputType());
+ assertEquals(UnittestProto.BarResponse.getDescriptor(),
+ barMethod.getOutputType());
+ assertEquals(barMethod, service.findMethodByName("Bar"));
+
+ assertNull(service.findMethodByName("NoSuchMethod"));
+
+ for (int i = 0; i < service.getMethods().size(); i++) {
+ assertEquals(i, service.getMethods().get(i).getIndex());
+ }
+ }
+
+
+ public void testCustomOptions() throws Exception {
+ Descriptor descriptor =
+ UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
+
+ assertTrue(
+ descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
+ assertEquals(Integer.valueOf(-56),
+ descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
+
+ FieldDescriptor field = descriptor.findFieldByName("field1");
+ assertNotNull(field);
+
+ assertTrue(
+ field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
+ assertEquals(Long.valueOf(8765432109L),
+ field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
+
+ EnumDescriptor enumType =
+ UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
+
+ assertTrue(
+ enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
+ assertEquals(Integer.valueOf(-789),
+ enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
+
+ ServiceDescriptor service =
+ UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
+
+ assertTrue(
+ service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
+ assertEquals(Long.valueOf(-9876543210L),
+ service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
+
+ MethodDescriptor method = service.findMethodByName("Foo");
+ assertNotNull(method);
+
+ assertTrue(
+ method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
+ assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
+ method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
+ }
+
+ /**
+ * Test that the FieldDescriptor.Type enum is the same as the
+ * WireFormat.FieldType enum.
+ */
+ public void testFieldTypeTablesMatch() throws Exception {
+ FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
+ WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
+
+ assertEquals(values1.length, values2.length);
+
+ for (int i = 0; i < values1.length; i++) {
+ assertEquals(values1[i].toString(), values2[i].toString());
+ }
+ }
+
+ /**
+ * Test that the FieldDescriptor.JavaType enum is the same as the
+ * WireFormat.JavaType enum.
+ */
+ public void testJavaTypeTablesMatch() throws Exception {
+ FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
+ WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
+
+ assertEquals(values1.length, values2.length);
+
+ for (int i = 0; i < values1.length; i++) {
+ assertEquals(values1[i].toString(), values2[i].toString());
+ }
+ }
+
+ public void testEnormousDescriptor() throws Exception {
+ // The descriptor for this file is larger than 64k, yet it did not cause
+ // a compiler error due to an over-long string literal.
+ assertTrue(
+ UnittestEnormousDescriptor.getDescriptor()
+ .toProto().getSerializedSize() > 65536);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/DynamicMessageTest.java b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
new file mode 100644
index 0000000..aabccda
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/DynamicMessageTest.java
@@ -0,0 +1,226 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+
+import junit.framework.TestCase;
+import java.util.Arrays;
+
+/**
+ * Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which
+ * tests some {@link DynamicMessage} functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class DynamicMessageTest extends TestCase {
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+ TestUtil.ReflectionTester packedReflectionTester =
+ new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null);
+
+ public void testDynamicMessageAccessors() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+ reflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testDoubleBuildError() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ builder.build();
+ try {
+ builder.build();
+ fail("Should have thrown exception.");
+ } catch (IllegalStateException e) {
+ // Success.
+ }
+ }
+
+ public void testClearAfterBuildError() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ builder.build();
+ try {
+ builder.clear();
+ fail("Should have thrown exception.");
+ } catch (IllegalStateException e) {
+ // Success.
+ }
+ }
+
+ public void testDynamicMessageSettersRejectNull() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.assertReflectionSettersRejectNull(builder);
+ }
+
+ public void testDynamicMessageExtensionAccessors() throws Exception {
+ // We don't need to extensively test DynamicMessage's handling of
+ // extensions because, frankly, it doesn't do anything special with them.
+ // It treats them just like any other fields.
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testDynamicMessageExtensionSettersRejectNull() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllExtensions.getDescriptor());
+ extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+ }
+
+ public void testDynamicMessageRepeatedSetters() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ Message message = builder.build();
+ reflectionTester.assertRepeatedFieldsModifiedViaReflection(message);
+ }
+
+ public void testDynamicMessageRepeatedSettersRejectNull() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+ }
+
+ public void testDynamicMessageDefaults() throws Exception {
+ reflectionTester.assertClearViaReflection(
+ DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor()));
+ reflectionTester.assertClearViaReflection(
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build());
+ }
+
+ public void testDynamicMessageSerializedSize() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ Message.Builder dynamicBuilder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(dynamicBuilder);
+ Message dynamicMessage = dynamicBuilder.build();
+
+ assertEquals(message.getSerializedSize(),
+ dynamicMessage.getSerializedSize());
+ }
+
+ public void testDynamicMessageSerialization() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ Message message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+
+ // In fact, the serialized forms should be exactly the same, byte-for-byte.
+ assertEquals(TestUtil.getAllSet().toByteString(), rawBytes);
+ }
+
+ public void testDynamicMessageParsing() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+
+ Message message2 =
+ DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes);
+ reflectionTester.assertAllFieldsSetViaReflection(message2);
+ }
+
+ public void testDynamicMessagePackedSerialization() throws Exception {
+ Message.Builder builder =
+ DynamicMessage.newBuilder(TestPackedTypes.getDescriptor());
+ packedReflectionTester.setPackedFieldsViaReflection(builder);
+ Message message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+ TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+ TestUtil.assertPackedFieldsSet(message2);
+
+ // In fact, the serialized forms should be exactly the same, byte-for-byte.
+ assertEquals(TestUtil.getPackedSet().toByteString(), rawBytes);
+ }
+
+ public void testDynamicMessagePackedParsing() throws Exception {
+ TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+ TestUtil.setPackedFields(builder);
+ TestPackedTypes message = builder.build();
+
+ ByteString rawBytes = message.toByteString();
+
+ Message message2 =
+ DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes);
+ packedReflectionTester.assertPackedFieldsSetViaReflection(message2);
+ }
+
+ public void testDynamicMessageCopy() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+
+ DynamicMessage copy = DynamicMessage.newBuilder(message).build();
+ reflectionTester.assertAllFieldsSetViaReflection(copy);
+ }
+
+ public void testToBuilder() throws Exception {
+ DynamicMessage.Builder builder =
+ DynamicMessage.newBuilder(TestAllTypes.getDescriptor());
+ reflectionTester.setAllFieldsViaReflection(builder);
+ int unknownFieldNum = 9;
+ long unknownFieldVal = 90;
+ builder.setUnknownFields(UnknownFieldSet.newBuilder()
+ .addField(unknownFieldNum,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(unknownFieldVal).build())
+ .build());
+ DynamicMessage message = builder.build();
+
+ DynamicMessage derived = message.toBuilder().build();
+ reflectionTester.assertAllFieldsSetViaReflection(derived);
+ assertEquals(Arrays.asList(unknownFieldVal),
+ derived.getUnknownFields().getField(unknownFieldNum).getVarintList());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
new file mode 100644
index 0000000..cdf60c5
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/GeneratedMessageTest.java
@@ -0,0 +1,618 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestOptionalOptimizedForSize;
+import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize;
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
+import protobuf_unittest.MultipleFilesTestProto;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.EnumWithNoOuter;
+import protobuf_unittest.ServiceWithNoOuter;
+import com.google.protobuf.UnittestLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+
+import junit.framework.TestCase;
+import java.util.Arrays;
+
+/**
+ * Unit test for generated messages and generated code. See also
+ * {@link MessageTest}, which tests some generated message functionality.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class GeneratedMessageTest extends TestCase {
+ TestUtil.ReflectionTester reflectionTester =
+ new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null);
+
+ public void testDefaultInstance() throws Exception {
+ assertSame(TestAllTypes.getDefaultInstance(),
+ TestAllTypes.getDefaultInstance().getDefaultInstanceForType());
+ assertSame(TestAllTypes.getDefaultInstance(),
+ TestAllTypes.newBuilder().getDefaultInstanceForType());
+ }
+
+ public void testAccessors() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertAllFieldsSet(message);
+ }
+
+ public void testDoubleBuildError() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ builder.build();
+ try {
+ builder.build();
+ fail("Should have thrown exception.");
+ } catch (IllegalStateException e) {
+ // Success.
+ }
+ }
+
+ public void testClearAfterBuildError() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ builder.build();
+ try {
+ builder.clear();
+ fail("Should have thrown exception.");
+ } catch (IllegalStateException e) {
+ // Success.
+ }
+ }
+
+ public void testSettersRejectNull() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ builder.setOptionalString(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setOptionalBytes(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setOptionalNestedMessage((TestAllTypes.NestedMessage) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setOptionalNestedMessage(
+ (TestAllTypes.NestedMessage.Builder) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setOptionalNestedEnum(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedString(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedBytes(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedNestedMessage((TestAllTypes.NestedMessage) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedNestedMessage(
+ (TestAllTypes.NestedMessage.Builder) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedNestedEnum(null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
+
+ public void testRepeatedSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestUtil.modifyRepeatedFields(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertRepeatedFieldsModified(message);
+ }
+
+ public void testRepeatedSettersRejectNull() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+ builder.addRepeatedString("one");
+ builder.addRepeatedString("two");
+ try {
+ builder.setRepeatedString(1, null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedBytes(TestUtil.toBytes("one"));
+ builder.addRepeatedBytes(TestUtil.toBytes("two"));
+ try {
+ builder.setRepeatedBytes(1, null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ builder.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(456).build());
+ try {
+ builder.setRepeatedNestedMessage(1, (TestAllTypes.NestedMessage) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setRepeatedNestedMessage(
+ 1, (TestAllTypes.NestedMessage.Builder) null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.FOO);
+ builder.addRepeatedNestedEnum(TestAllTypes.NestedEnum.BAR);
+ try {
+ builder.setRepeatedNestedEnum(1, null);
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
+
+ public void testRepeatedAppend() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+ builder.addAllRepeatedInt32(Arrays.asList(1, 2, 3, 4));
+ builder.addAllRepeatedForeignEnum(Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+
+ ForeignMessage foreignMessage =
+ ForeignMessage.newBuilder().setC(12).build();
+ builder.addAllRepeatedForeignMessage(Arrays.asList(foreignMessage));
+
+ TestAllTypes message = builder.build();
+ assertEquals(message.getRepeatedInt32List(), Arrays.asList(1, 2, 3, 4));
+ assertEquals(message.getRepeatedForeignEnumList(),
+ Arrays.asList(ForeignEnum.FOREIGN_BAZ));
+ assertEquals(1, message.getRepeatedForeignMessageCount());
+ assertEquals(12, message.getRepeatedForeignMessage(0).getC());
+ }
+
+ public void testRepeatedAppendRejectsNull() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+
+ ForeignMessage foreignMessage =
+ ForeignMessage.newBuilder().setC(12).build();
+ try {
+ builder.addAllRepeatedForeignMessage(
+ Arrays.asList(foreignMessage, (ForeignMessage) null));
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ try {
+ builder.addAllRepeatedForeignEnum(
+ Arrays.asList(ForeignEnum.FOREIGN_BAZ, null));
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ try {
+ builder.addAllRepeatedString(Arrays.asList("one", null));
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ try {
+ builder.addAllRepeatedBytes(Arrays.asList(TestUtil.toBytes("one"), null));
+ fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
+
+ public void testSettingForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = TestAllTypes.newBuilder()
+ // Pass builder for foreign message instance.
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(123))
+ .build();
+ TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+ // Create expected version passing foreign message instance explicitly.
+ .setOptionalForeignMessage(
+ ForeignMessage.newBuilder().setC(123).build())
+ .build();
+ // TODO(ngd): Upgrade to using real #equals method once implemented
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testSettingRepeatedForeignMessageUsingBuilder() throws Exception {
+ TestAllTypes message = TestAllTypes.newBuilder()
+ // Pass builder for foreign message instance.
+ .addRepeatedForeignMessage(ForeignMessage.newBuilder().setC(456))
+ .build();
+ TestAllTypes expectedMessage = TestAllTypes.newBuilder()
+ // Create expected version passing foreign message instance explicitly.
+ .addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(456).build())
+ .build();
+ assertEquals(expectedMessage.toString(), message.toString());
+ }
+
+ public void testDefaults() throws Exception {
+ TestUtil.assertClear(TestAllTypes.getDefaultInstance());
+ TestUtil.assertClear(TestAllTypes.newBuilder().build());
+
+ assertEquals("\u1234",
+ TestExtremeDefaultValues.getDefaultInstance().getUtf8String());
+ }
+
+ public void testReflectionGetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+ reflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testReflectionSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertAllFieldsSet(message);
+ }
+
+ public void testReflectionSettersRejectNull() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.assertReflectionSettersRejectNull(builder);
+ }
+
+ public void testReflectionRepeatedSetters() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.setAllFieldsViaReflection(builder);
+ reflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertRepeatedFieldsModified(message);
+ }
+
+ public void testReflectionRepeatedSettersRejectNull() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ reflectionTester.assertReflectionRepeatedSettersRejectNull(builder);
+ }
+
+ public void testReflectionDefaults() throws Exception {
+ reflectionTester.assertClearViaReflection(
+ TestAllTypes.getDefaultInstance());
+ reflectionTester.assertClearViaReflection(
+ TestAllTypes.newBuilder().build());
+ }
+
+ public void testEnumInterface() throws Exception {
+ assertTrue(TestAllTypes.getDefaultInstance().getDefaultNestedEnum()
+ instanceof ProtocolMessageEnum);
+ }
+
+ public void testEnumMap() throws Exception {
+ Internal.EnumLiteMap<ForeignEnum> map = ForeignEnum.internalGetValueMap();
+
+ for (ForeignEnum value : ForeignEnum.values()) {
+ assertEquals(value, map.findValueByNumber(value.getNumber()));
+ }
+
+ assertTrue(map.findValueByNumber(12345) == null);
+ }
+
+ // =================================================================
+ // Extensions.
+
+ TestUtil.ReflectionTester extensionsReflectionTester =
+ new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(),
+ TestUtil.getExtensionRegistry());
+
+ public void testExtensionAccessors() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertAllExtensionsSet(message);
+ }
+
+ public void testExtensionRepeatedSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestUtil.modifyRepeatedExtensions(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertRepeatedExtensionsModified(message);
+ }
+
+ public void testExtensionDefaults() throws Exception {
+ TestUtil.assertExtensionsClear(TestAllExtensions.getDefaultInstance());
+ TestUtil.assertExtensionsClear(TestAllExtensions.newBuilder().build());
+ }
+
+ public void testExtensionReflectionGetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestAllExtensions message = builder.build();
+ extensionsReflectionTester.assertAllFieldsSetViaReflection(message);
+ }
+
+ public void testExtensionReflectionSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertAllExtensionsSet(message);
+ }
+
+ public void testExtensionReflectionSettersRejectNull() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.assertReflectionSettersRejectNull(builder);
+ }
+
+ public void testExtensionReflectionRepeatedSetters() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.setAllFieldsViaReflection(builder);
+ extensionsReflectionTester.modifyRepeatedFieldsViaReflection(builder);
+ TestAllExtensions message = builder.build();
+ TestUtil.assertRepeatedExtensionsModified(message);
+ }
+
+ public void testExtensionReflectionRepeatedSettersRejectNull()
+ throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ extensionsReflectionTester.assertReflectionRepeatedSettersRejectNull(
+ builder);
+ }
+
+ public void testExtensionReflectionDefaults() throws Exception {
+ extensionsReflectionTester.assertClearViaReflection(
+ TestAllExtensions.getDefaultInstance());
+ extensionsReflectionTester.assertClearViaReflection(
+ TestAllExtensions.newBuilder().build());
+ }
+
+ public void testClearExtension() throws Exception {
+ // clearExtension() is not actually used in TestUtil, so try it manually.
+ assertFalse(
+ TestAllExtensions.newBuilder()
+ .setExtension(UnittestProto.optionalInt32Extension, 1)
+ .clearExtension(UnittestProto.optionalInt32Extension)
+ .hasExtension(UnittestProto.optionalInt32Extension));
+ assertEquals(0,
+ TestAllExtensions.newBuilder()
+ .addExtension(UnittestProto.repeatedInt32Extension, 1)
+ .clearExtension(UnittestProto.repeatedInt32Extension)
+ .getExtensionCount(UnittestProto.repeatedInt32Extension));
+ }
+
+ public void testExtensionCopy() throws Exception {
+ TestAllExtensions original = TestUtil.getAllExtensionsSet();
+ TestAllExtensions copy = TestAllExtensions.newBuilder(original).build();
+ TestUtil.assertAllExtensionsSet(copy);
+ }
+
+ public void testExtensionMergeFrom() throws Exception {
+ TestAllExtensions original =
+ TestAllExtensions.newBuilder()
+ .setExtension(UnittestProto.optionalInt32Extension, 1).build();
+ TestAllExtensions merged =
+ TestAllExtensions.newBuilder().mergeFrom(original).build();
+ assertTrue(merged.hasExtension(UnittestProto.optionalInt32Extension));
+ assertEquals(
+ 1, (int) merged.getExtension(UnittestProto.optionalInt32Extension));
+ }
+
+ // =================================================================
+ // Lite Extensions.
+
+ // We test lite extensions directly because they have a separate
+ // implementation from full extensions. In contrast, we do not test
+ // lite fields directly since they are implemented exactly the same as
+ // regular fields.
+
+ public void testLiteExtensionAccessors() throws Exception {
+ TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestAllExtensionsLite message = builder.build();
+ TestUtil.assertAllExtensionsSet(message);
+ }
+
+ public void testLiteExtensionRepeatedSetters() throws Exception {
+ TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+ TestUtil.setAllExtensions(builder);
+ TestUtil.modifyRepeatedExtensions(builder);
+ TestAllExtensionsLite message = builder.build();
+ TestUtil.assertRepeatedExtensionsModified(message);
+ }
+
+ public void testLiteExtensionDefaults() throws Exception {
+ TestUtil.assertExtensionsClear(TestAllExtensionsLite.getDefaultInstance());
+ TestUtil.assertExtensionsClear(TestAllExtensionsLite.newBuilder().build());
+ }
+
+ public void testClearLiteExtension() throws Exception {
+ // clearExtension() is not actually used in TestUtil, so try it manually.
+ assertFalse(
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 1)
+ .clearExtension(UnittestLite.optionalInt32ExtensionLite)
+ .hasExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(0,
+ TestAllExtensionsLite.newBuilder()
+ .addExtension(UnittestLite.repeatedInt32ExtensionLite, 1)
+ .clearExtension(UnittestLite.repeatedInt32ExtensionLite)
+ .getExtensionCount(UnittestLite.repeatedInt32ExtensionLite));
+ }
+
+ public void testLiteExtensionCopy() throws Exception {
+ TestAllExtensionsLite original = TestUtil.getAllLiteExtensionsSet();
+ TestAllExtensionsLite copy =
+ TestAllExtensionsLite.newBuilder(original).build();
+ TestUtil.assertAllExtensionsSet(copy);
+ }
+
+ public void testLiteExtensionMergeFrom() throws Exception {
+ TestAllExtensionsLite original =
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 1).build();
+ TestAllExtensionsLite merged =
+ TestAllExtensionsLite.newBuilder().mergeFrom(original).build();
+ assertTrue(merged.hasExtension(UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(
+ 1, (int) merged.getExtension(UnittestLite.optionalInt32ExtensionLite));
+ }
+
+ // =================================================================
+ // multiple_files_test
+
+ public void testMultipleFilesOption() throws Exception {
+ // We mostly just want to check that things compile.
+ MessageWithNoOuter message =
+ MessageWithNoOuter.newBuilder()
+ .setNested(MessageWithNoOuter.NestedMessage.newBuilder().setI(1))
+ .addForeign(TestAllTypes.newBuilder().setOptionalInt32(1))
+ .setNestedEnum(MessageWithNoOuter.NestedEnum.BAZ)
+ .setForeignEnum(EnumWithNoOuter.BAR)
+ .build();
+ assertEquals(message, MessageWithNoOuter.parseFrom(message.toByteString()));
+
+ assertEquals(MultipleFilesTestProto.getDescriptor(),
+ MessageWithNoOuter.getDescriptor().getFile());
+
+ Descriptors.FieldDescriptor field =
+ MessageWithNoOuter.getDescriptor().findFieldByName("foreign_enum");
+ assertEquals(EnumWithNoOuter.BAR.getValueDescriptor(),
+ message.getField(field));
+
+ assertEquals(MultipleFilesTestProto.getDescriptor(),
+ ServiceWithNoOuter.getDescriptor().getFile());
+
+ assertFalse(
+ TestAllExtensions.getDefaultInstance().hasExtension(
+ MultipleFilesTestProto.extensionWithOuter));
+ }
+
+ public void testOptionalFieldWithRequiredSubfieldsOptimizedForSize()
+ throws Exception {
+ TestOptionalOptimizedForSize message =
+ TestOptionalOptimizedForSize.getDefaultInstance();
+ assertTrue(message.isInitialized());
+
+ message = TestOptionalOptimizedForSize.newBuilder().setO(
+ TestRequiredOptimizedForSize.newBuilder().buildPartial()
+ ).buildPartial();
+ assertFalse(message.isInitialized());
+
+ message = TestOptionalOptimizedForSize.newBuilder().setO(
+ TestRequiredOptimizedForSize.newBuilder().setX(5).buildPartial()
+ ).buildPartial();
+ assertTrue(message.isInitialized());
+ }
+
+ public void testUninitializedExtensionInOptimizedForSize()
+ throws Exception {
+ TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder();
+ builder.setExtension(TestOptimizedForSize.testExtension2,
+ TestRequiredOptimizedForSize.newBuilder().buildPartial());
+ assertFalse(builder.isInitialized());
+ assertFalse(builder.buildPartial().isInitialized());
+
+ builder = TestOptimizedForSize.newBuilder();
+ builder.setExtension(TestOptimizedForSize.testExtension2,
+ TestRequiredOptimizedForSize.newBuilder().setX(10).buildPartial());
+ assertTrue(builder.isInitialized());
+ assertTrue(builder.buildPartial().isInitialized());
+ }
+
+ public void testToBuilder() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TestUtil.setAllFields(builder);
+ TestAllTypes message = builder.build();
+ TestUtil.assertAllFieldsSet(message.toBuilder().build());
+ }
+
+ public void testFieldConstantValues() throws Exception {
+ assertEquals(TestAllTypes.NestedMessage.BB_FIELD_NUMBER, 1);
+ assertEquals(TestAllTypes.OPTIONAL_INT32_FIELD_NUMBER, 1);
+ assertEquals(TestAllTypes.OPTIONALGROUP_FIELD_NUMBER, 16);
+ assertEquals(TestAllTypes.OPTIONAL_NESTED_MESSAGE_FIELD_NUMBER, 18);
+ assertEquals(TestAllTypes.OPTIONAL_NESTED_ENUM_FIELD_NUMBER, 21);
+ assertEquals(TestAllTypes.REPEATED_INT32_FIELD_NUMBER, 31);
+ assertEquals(TestAllTypes.REPEATEDGROUP_FIELD_NUMBER, 46);
+ assertEquals(TestAllTypes.REPEATED_NESTED_MESSAGE_FIELD_NUMBER, 48);
+ assertEquals(TestAllTypes.REPEATED_NESTED_ENUM_FIELD_NUMBER, 51);
+ }
+
+ public void testExtensionConstantValues() throws Exception {
+ assertEquals(UnittestProto.TestRequired.SINGLE_FIELD_NUMBER, 1000);
+ assertEquals(UnittestProto.TestRequired.MULTI_FIELD_NUMBER, 1001);
+ assertEquals(UnittestProto.OPTIONAL_INT32_EXTENSION_FIELD_NUMBER, 1);
+ assertEquals(UnittestProto.OPTIONALGROUP_EXTENSION_FIELD_NUMBER, 16);
+ assertEquals(
+ UnittestProto.OPTIONAL_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 18);
+ assertEquals(UnittestProto.OPTIONAL_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 21);
+ assertEquals(UnittestProto.REPEATED_INT32_EXTENSION_FIELD_NUMBER, 31);
+ assertEquals(UnittestProto.REPEATEDGROUP_EXTENSION_FIELD_NUMBER, 46);
+ assertEquals(
+ UnittestProto.REPEATED_NESTED_MESSAGE_EXTENSION_FIELD_NUMBER, 48);
+ assertEquals(UnittestProto.REPEATED_NESTED_ENUM_EXTENSION_FIELD_NUMBER, 51);
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/LiteTest.java b/java/src/test/java/com/google/protobuf/LiteTest.java
new file mode 100644
index 0000000..9dd730c
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/LiteTest.java
@@ -0,0 +1,114 @@
+// 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.UnittestLite;
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestNestedExtensionLite;
+
+import junit.framework.TestCase;
+
+/**
+ * Test lite runtime.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class LiteTest extends TestCase {
+ public void setUp() throws Exception {
+ // Test that nested extensions are initialized correctly even if the outer
+ // class has not been accessed directly. This was once a bug with lite
+ // messages.
+ //
+ // We put this in setUp() rather than in its own test method because we
+ // need to make sure it runs before any actual tests.
+ assertTrue(TestNestedExtensionLite.nestedExtension != null);
+ }
+
+ public void testLite() throws Exception {
+ // Since lite messages are a subset of regular messages, we can mostly
+ // assume that the functionality of lite messages is already thoroughly
+ // tested by the regular tests. All this test really verifies is that
+ // a proto with optimize_for = LITE_RUNTIME compiles correctly when
+ // linked only against the lite library. That is all tested at compile
+ // time, leaving not much to do in this method. Let's just do some random
+ // stuff to make sure the lite message is actually here and usable.
+
+ TestAllTypesLite message =
+ TestAllTypesLite.newBuilder()
+ .setOptionalInt32(123)
+ .addRepeatedString("hello")
+ .setOptionalNestedMessage(
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7))
+ .build();
+
+ ByteString data = message.toByteString();
+
+ TestAllTypesLite message2 = TestAllTypesLite.parseFrom(data);
+
+ assertEquals(123, message2.getOptionalInt32());
+ assertEquals(1, message2.getRepeatedStringCount());
+ assertEquals("hello", message2.getRepeatedString(0));
+ assertEquals(7, message2.getOptionalNestedMessage().getBb());
+ }
+
+ public void testLiteExtensions() throws Exception {
+ // TODO(kenton): Unlike other features of the lite library, extensions are
+ // implemented completely differently from the regular library. We
+ // need to test them more thoroughly, once they are fully-implemented.
+
+ TestAllExtensionsLite message =
+ TestAllExtensionsLite.newBuilder()
+ .setExtension(UnittestLite.optionalInt32ExtensionLite, 123)
+ .addExtension(UnittestLite.repeatedStringExtensionLite, "hello")
+ .setExtension(UnittestLite.optionalNestedEnumExtensionLite,
+ TestAllTypesLite.NestedEnum.BAZ)
+ .setExtension(UnittestLite.optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(7).build())
+ .build();
+
+ // Test copying a message, since coping extensions actually does use a
+ // different code path between lite and regular libraries, and as of this
+ // writing, parsing hasn't been implemented yet.
+ TestAllExtensionsLite message2 = message.toBuilder().build();
+
+ assertEquals(123, (int) message2.getExtension(
+ UnittestLite.optionalInt32ExtensionLite));
+ assertEquals(1, message2.getExtensionCount(
+ UnittestLite.repeatedStringExtensionLite));
+ assertEquals("hello", message2.getExtension(
+ UnittestLite.repeatedStringExtensionLite, 0));
+ assertEquals(TestAllTypesLite.NestedEnum.BAZ, message2.getExtension(
+ UnittestLite.optionalNestedEnumExtensionLite));
+ assertEquals(7, message2.getExtension(
+ UnittestLite.optionalNestedMessageExtensionLite).getBb());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/MessageTest.java b/java/src/test/java/com/google/protobuf/MessageTest.java
new file mode 100644
index 0000000..c2f47eb
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/MessageTest.java
@@ -0,0 +1,313 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestRequired;
+import protobuf_unittest.UnittestProto.TestRequiredForeign;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+
+import junit.framework.TestCase;
+
+/**
+ * Misc. unit tests for message operations that apply to both generated
+ * and dynamic messages.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class MessageTest extends TestCase {
+ // =================================================================
+ // Message-merging tests.
+
+ static final TestAllTypes MERGE_SOURCE =
+ TestAllTypes.newBuilder()
+ .setOptionalInt32(1)
+ .setOptionalString("foo")
+ .setOptionalForeignMessage(ForeignMessage.getDefaultInstance())
+ .addRepeatedString("bar")
+ .build();
+
+ static final TestAllTypes MERGE_DEST =
+ TestAllTypes.newBuilder()
+ .setOptionalInt64(2)
+ .setOptionalString("baz")
+ .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build())
+ .addRepeatedString("qux")
+ .build();
+
+ static final String MERGE_RESULT_TEXT =
+ "optional_int32: 1\n" +
+ "optional_int64: 2\n" +
+ "optional_string: \"foo\"\n" +
+ "optional_foreign_message {\n" +
+ " c: 3\n" +
+ "}\n" +
+ "repeated_string: \"qux\"\n" +
+ "repeated_string: \"bar\"\n";
+
+ public void testMergeFrom() throws Exception {
+ TestAllTypes result =
+ TestAllTypes.newBuilder(MERGE_DEST)
+ .mergeFrom(MERGE_SOURCE).build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ /**
+ * Test merging a DynamicMessage into a GeneratedMessage. As long as they
+ * have the same descriptor, this should work, but it is an entirely different
+ * code path.
+ */
+ public void testMergeFromDynamic() throws Exception {
+ TestAllTypes result =
+ TestAllTypes.newBuilder(MERGE_DEST)
+ .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+ .build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ /** Test merging two DynamicMessages. */
+ public void testDynamicMergeFrom() throws Exception {
+ DynamicMessage result =
+ DynamicMessage.newBuilder(MERGE_DEST)
+ .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build())
+ .build();
+
+ assertEquals(MERGE_RESULT_TEXT, result.toString());
+ }
+
+ // =================================================================
+ // Required-field-related tests.
+
+ private static final TestRequired TEST_REQUIRED_UNINITIALIZED =
+ TestRequired.getDefaultInstance();
+ private static final TestRequired TEST_REQUIRED_INITIALIZED =
+ TestRequired.newBuilder().setA(1).setB(2).setC(3).build();
+
+ public void testRequired() throws Exception {
+ TestRequired.Builder builder = TestRequired.newBuilder();
+
+ assertFalse(builder.isInitialized());
+ builder.setA(1);
+ assertFalse(builder.isInitialized());
+ builder.setB(1);
+ assertFalse(builder.isInitialized());
+ builder.setC(1);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredForeign() throws Exception {
+ TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder();
+
+ assertTrue(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredExtension() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+
+ assertTrue(builder.isInitialized());
+
+ builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredDynamic() throws Exception {
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("a"), 1);
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("b"), 1);
+ assertFalse(builder.isInitialized());
+ builder.setField(descriptor.findFieldByName("c"), 1);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testRequiredDynamicForeign() throws Exception {
+ Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor();
+ DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor);
+
+ assertTrue(builder.isInitialized());
+
+ builder.setField(descriptor.findFieldByName("optional_message"),
+ TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setField(descriptor.findFieldByName("optional_message"),
+ TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+
+ builder.addRepeatedField(descriptor.findFieldByName("repeated_message"),
+ TEST_REQUIRED_UNINITIALIZED);
+ assertFalse(builder.isInitialized());
+
+ builder.setRepeatedField(descriptor.findFieldByName("repeated_message"), 0,
+ TEST_REQUIRED_INITIALIZED);
+ assertTrue(builder.isInitialized());
+ }
+
+ public void testUninitializedException() throws Exception {
+ try {
+ TestRequired.newBuilder().build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testBuildPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ TestRequired message = TestRequired.newBuilder().buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testNestedUninitializedException() throws Exception {
+ try {
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals(
+ "Message missing required fields: " +
+ "optional_message.a, " +
+ "optional_message.b, " +
+ "optional_message.c, " +
+ "repeated_message[0].a, " +
+ "repeated_message[0].b, " +
+ "repeated_message[0].c, " +
+ "repeated_message[1].a, " +
+ "repeated_message[1].b, " +
+ "repeated_message[1].c",
+ e.getMessage());
+ }
+ }
+
+ public void testBuildNestedPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ TestRequiredForeign message =
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testParseUnititialized() throws Exception {
+ try {
+ TestRequired.parseFrom(ByteString.EMPTY);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testParseNestedUnititialized() throws Exception {
+ ByteString data =
+ TestRequiredForeign.newBuilder()
+ .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED)
+ .buildPartial().toByteString();
+
+ try {
+ TestRequiredForeign.parseFrom(data);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals(
+ "Message missing required fields: " +
+ "optional_message.a, " +
+ "optional_message.b, " +
+ "optional_message.c, " +
+ "repeated_message[0].a, " +
+ "repeated_message[0].b, " +
+ "repeated_message[0].c, " +
+ "repeated_message[1].a, " +
+ "repeated_message[1].b, " +
+ "repeated_message[1].c",
+ e.getMessage());
+ }
+ }
+
+ public void testDynamicUninitializedException() throws Exception {
+ try {
+ DynamicMessage.newBuilder(TestRequired.getDescriptor()).build();
+ fail("Should have thrown an exception.");
+ } catch (UninitializedMessageException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+
+ public void testDynamicBuildPartial() throws Exception {
+ // We're mostly testing that no exception is thrown.
+ DynamicMessage message =
+ DynamicMessage.newBuilder(TestRequired.getDescriptor())
+ .buildPartial();
+ assertFalse(message.isInitialized());
+ }
+
+ public void testDynamicParseUnititialized() throws Exception {
+ try {
+ Descriptors.Descriptor descriptor = TestRequired.getDescriptor();
+ DynamicMessage.parseFrom(descriptor, ByteString.EMPTY);
+ fail("Should have thrown an exception.");
+ } catch (InvalidProtocolBufferException e) {
+ assertEquals("Message missing required fields: a, b, c", e.getMessage());
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/ServiceTest.java b/java/src/test/java/com/google/protobuf/ServiceTest.java
new file mode 100644
index 0000000..d8523ea
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/ServiceTest.java
@@ -0,0 +1,271 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.MethodDescriptor;
+import protobuf_unittest.MessageWithNoOuter;
+import protobuf_unittest.ServiceWithNoOuter;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestService;
+import protobuf_unittest.UnittestProto.FooRequest;
+import protobuf_unittest.UnittestProto.FooResponse;
+import protobuf_unittest.UnittestProto.BarRequest;
+import protobuf_unittest.UnittestProto.BarResponse;
+
+import org.easymock.classextension.EasyMock;
+import org.easymock.classextension.IMocksControl;
+import org.easymock.IArgumentMatcher;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests services and stubs.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+public class ServiceTest extends TestCase {
+ private IMocksControl control;
+ private RpcController mockController;
+
+ private final Descriptors.MethodDescriptor fooDescriptor =
+ TestService.getDescriptor().getMethods().get(0);
+ private final Descriptors.MethodDescriptor barDescriptor =
+ TestService.getDescriptor().getMethods().get(1);
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ control = EasyMock.createStrictControl();
+ mockController = control.createMock(RpcController.class);
+ }
+
+ // =================================================================
+
+ /** Tests Service.callMethod(). */
+ public void testCallMethod() throws Exception {
+ FooRequest fooRequest = FooRequest.newBuilder().build();
+ BarRequest barRequest = BarRequest.newBuilder().build();
+ MockCallback<Message> fooCallback = new MockCallback<Message>();
+ MockCallback<Message> barCallback = new MockCallback<Message>();
+ TestService mockService = control.createMock(TestService.class);
+
+ mockService.foo(EasyMock.same(mockController), EasyMock.same(fooRequest),
+ this.<FooResponse>wrapsCallback(fooCallback));
+ mockService.bar(EasyMock.same(mockController), EasyMock.same(barRequest),
+ this.<BarResponse>wrapsCallback(barCallback));
+ control.replay();
+
+ mockService.callMethod(fooDescriptor, mockController,
+ fooRequest, fooCallback);
+ mockService.callMethod(barDescriptor, mockController,
+ barRequest, barCallback);
+ control.verify();
+ }
+
+ /** Tests Service.get{Request,Response}Prototype(). */
+ public void testGetPrototype() throws Exception {
+ TestService mockService = control.createMock(TestService.class);
+
+ assertSame(mockService.getRequestPrototype(fooDescriptor),
+ FooRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(fooDescriptor),
+ FooResponse.getDefaultInstance());
+ assertSame(mockService.getRequestPrototype(barDescriptor),
+ BarRequest.getDefaultInstance());
+ assertSame(mockService.getResponsePrototype(barDescriptor),
+ BarResponse.getDefaultInstance());
+ }
+
+ /** Tests generated stubs. */
+ public void testStub() throws Exception {
+ FooRequest fooRequest = FooRequest.newBuilder().build();
+ BarRequest barRequest = BarRequest.newBuilder().build();
+ MockCallback<FooResponse> fooCallback = new MockCallback<FooResponse>();
+ MockCallback<BarResponse> barCallback = new MockCallback<BarResponse>();
+ RpcChannel mockChannel = control.createMock(RpcChannel.class);
+ TestService stub = TestService.newStub(mockChannel);
+
+ mockChannel.callMethod(
+ EasyMock.same(fooDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ EasyMock.same(FooResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(fooCallback));
+ mockChannel.callMethod(
+ EasyMock.same(barDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ EasyMock.same(BarResponse.getDefaultInstance()),
+ this.<Message>wrapsCallback(barCallback));
+ control.replay();
+
+ stub.foo(mockController, fooRequest, fooCallback);
+ stub.bar(mockController, barRequest, barCallback);
+ control.verify();
+ }
+
+ /** Tests generated blocking stubs. */
+ public void testBlockingStub() throws Exception {
+ FooRequest fooRequest = FooRequest.newBuilder().build();
+ BarRequest barRequest = BarRequest.newBuilder().build();
+ BlockingRpcChannel mockChannel =
+ control.createMock(BlockingRpcChannel.class);
+ TestService.BlockingInterface stub =
+ TestService.newBlockingStub(mockChannel);
+
+ FooResponse fooResponse = FooResponse.newBuilder().build();
+ BarResponse barResponse = BarResponse.newBuilder().build();
+
+ EasyMock.expect(mockChannel.callBlockingMethod(
+ EasyMock.same(fooDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(fooRequest),
+ EasyMock.same(FooResponse.getDefaultInstance()))).andReturn(fooResponse);
+ EasyMock.expect(mockChannel.callBlockingMethod(
+ EasyMock.same(barDescriptor),
+ EasyMock.same(mockController),
+ EasyMock.same(barRequest),
+ EasyMock.same(BarResponse.getDefaultInstance()))).andReturn(barResponse);
+ control.replay();
+
+ assertSame(fooResponse, stub.foo(mockController, fooRequest));
+ assertSame(barResponse, stub.bar(mockController, barRequest));
+ control.verify();
+ }
+
+ public void testNewReflectiveService() {
+ ServiceWithNoOuter.Interface impl =
+ control.createMock(ServiceWithNoOuter.Interface.class);
+ RpcController controller = control.createMock(RpcController.class);
+ Service service = ServiceWithNoOuter.newReflectiveService(impl);
+
+ MethodDescriptor fooMethod =
+ ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+ MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+ RpcCallback<Message> callback = new RpcCallback<Message>() {
+ public void run(Message parameter) {
+ // No reason this should be run.
+ fail();
+ }
+ };
+ RpcCallback<TestAllTypes> specializedCallback =
+ RpcUtil.specializeCallback(callback);
+
+ impl.foo(EasyMock.same(controller), EasyMock.same(request),
+ EasyMock.same(specializedCallback));
+ EasyMock.expectLastCall();
+
+ control.replay();
+
+ service.callMethod(fooMethod, controller, request, callback);
+
+ control.verify();
+ }
+
+ public void testNewReflectiveBlockingService() throws ServiceException {
+ ServiceWithNoOuter.BlockingInterface impl =
+ control.createMock(ServiceWithNoOuter.BlockingInterface.class);
+ RpcController controller = control.createMock(RpcController.class);
+ BlockingService service =
+ ServiceWithNoOuter.newReflectiveBlockingService(impl);
+
+ MethodDescriptor fooMethod =
+ ServiceWithNoOuter.getDescriptor().findMethodByName("Foo");
+ MessageWithNoOuter request = MessageWithNoOuter.getDefaultInstance();
+ RpcCallback<Message> callback = new RpcCallback<Message>() {
+ public void run(Message parameter) {
+ // No reason this should be run.
+ fail();
+ }
+ };
+
+ TestAllTypes expectedResponse = TestAllTypes.getDefaultInstance();
+ EasyMock.expect(impl.foo(EasyMock.same(controller), EasyMock.same(request)))
+ .andReturn(expectedResponse);
+
+ control.replay();
+
+ Message response =
+ service.callBlockingMethod(fooMethod, controller, request);
+ assertEquals(expectedResponse, response);
+
+ control.verify();
+ }
+
+ // =================================================================
+
+ /**
+ * wrapsCallback() is an EasyMock argument predicate. wrapsCallback(c)
+ * matches a callback if calling that callback causes c to be called.
+ * In other words, c wraps the given callback.
+ */
+ private <Type extends Message> RpcCallback<Type> wrapsCallback(
+ MockCallback<?> callback) {
+ EasyMock.reportMatcher(new WrapsCallback(callback));
+ return null;
+ }
+
+ /** The parameter to wrapsCallback() must be a MockCallback. */
+ private static class MockCallback<Type extends Message>
+ implements RpcCallback<Type> {
+ private boolean called = false;
+
+ public boolean isCalled() { return called; }
+
+ public void reset() { called = false; }
+ public void run(Type message) { called = true; }
+ }
+
+ /** Implementation of the wrapsCallback() argument matcher. */
+ private static class WrapsCallback implements IArgumentMatcher {
+ private MockCallback<?> callback;
+
+ public WrapsCallback(MockCallback<?> callback) {
+ this.callback = callback;
+ }
+
+ @SuppressWarnings("unchecked")
+ public boolean matches(Object actual) {
+ if (!(actual instanceof RpcCallback)) {
+ return false;
+ }
+ RpcCallback actualCallback = (RpcCallback)actual;
+
+ callback.reset();
+ actualCallback.run(null);
+ return callback.isCalled();
+ }
+
+ public void appendTo(StringBuffer buffer) {
+ buffer.append("wrapsCallback(mockCallback)");
+ }
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/TestUtil.java b/java/src/test/java/com/google/protobuf/TestUtil.java
new file mode 100644
index 0000000..805c42a
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/TestUtil.java
@@ -0,0 +1,3660 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import com.google.protobuf.UnittestLite;
+
+// The static imports are to avoid 100+ char lines. The following is roughly equivalent to
+// import static protobuf_unittest.UnittestProto.*;
+import static protobuf_unittest.UnittestProto.defaultInt32Extension;
+import static protobuf_unittest.UnittestProto.defaultInt64Extension;
+import static protobuf_unittest.UnittestProto.defaultUint32Extension;
+import static protobuf_unittest.UnittestProto.defaultUint64Extension;
+import static protobuf_unittest.UnittestProto.defaultSint32Extension;
+import static protobuf_unittest.UnittestProto.defaultSint64Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultFixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultSfixed32Extension;
+import static protobuf_unittest.UnittestProto.defaultSfixed64Extension;
+import static protobuf_unittest.UnittestProto.defaultFloatExtension;
+import static protobuf_unittest.UnittestProto.defaultDoubleExtension;
+import static protobuf_unittest.UnittestProto.defaultBoolExtension;
+import static protobuf_unittest.UnittestProto.defaultStringExtension;
+import static protobuf_unittest.UnittestProto.defaultBytesExtension;
+import static protobuf_unittest.UnittestProto.defaultNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultImportEnumExtension;
+import static protobuf_unittest.UnittestProto.defaultStringPieceExtension;
+import static protobuf_unittest.UnittestProto.defaultCordExtension;
+
+import static protobuf_unittest.UnittestProto.optionalInt32Extension;
+import static protobuf_unittest.UnittestProto.optionalInt64Extension;
+import static protobuf_unittest.UnittestProto.optionalUint32Extension;
+import static protobuf_unittest.UnittestProto.optionalUint64Extension;
+import static protobuf_unittest.UnittestProto.optionalSint32Extension;
+import static protobuf_unittest.UnittestProto.optionalSint64Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalFixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed32Extension;
+import static protobuf_unittest.UnittestProto.optionalSfixed64Extension;
+import static protobuf_unittest.UnittestProto.optionalFloatExtension;
+import static protobuf_unittest.UnittestProto.optionalDoubleExtension;
+import static protobuf_unittest.UnittestProto.optionalBoolExtension;
+import static protobuf_unittest.UnittestProto.optionalStringExtension;
+import static protobuf_unittest.UnittestProto.optionalBytesExtension;
+import static protobuf_unittest.UnittestProto.optionalGroupExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalImportMessageExtension;
+import static protobuf_unittest.UnittestProto.optionalNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalImportEnumExtension;
+import static protobuf_unittest.UnittestProto.optionalStringPieceExtension;
+import static protobuf_unittest.UnittestProto.optionalCordExtension;
+
+import static protobuf_unittest.UnittestProto.repeatedInt32Extension;
+import static protobuf_unittest.UnittestProto.repeatedInt64Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedUint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSint64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedFixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.repeatedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.repeatedFloatExtension;
+import static protobuf_unittest.UnittestProto.repeatedDoubleExtension;
+import static protobuf_unittest.UnittestProto.repeatedBoolExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringExtension;
+import static protobuf_unittest.UnittestProto.repeatedBytesExtension;
+import static protobuf_unittest.UnittestProto.repeatedGroupExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportMessageExtension;
+import static protobuf_unittest.UnittestProto.repeatedNestedEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedForeignEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedImportEnumExtension;
+import static protobuf_unittest.UnittestProto.repeatedStringPieceExtension;
+import static protobuf_unittest.UnittestProto.repeatedCordExtension;
+
+import static protobuf_unittest.UnittestProto.OptionalGroup_extension;
+import static protobuf_unittest.UnittestProto.RepeatedGroup_extension;
+
+import static protobuf_unittest.UnittestProto.packedInt32Extension;
+import static protobuf_unittest.UnittestProto.packedInt64Extension;
+import static protobuf_unittest.UnittestProto.packedUint32Extension;
+import static protobuf_unittest.UnittestProto.packedUint64Extension;
+import static protobuf_unittest.UnittestProto.packedSint32Extension;
+import static protobuf_unittest.UnittestProto.packedSint64Extension;
+import static protobuf_unittest.UnittestProto.packedFixed32Extension;
+import static protobuf_unittest.UnittestProto.packedFixed64Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed32Extension;
+import static protobuf_unittest.UnittestProto.packedSfixed64Extension;
+import static protobuf_unittest.UnittestProto.packedFloatExtension;
+import static protobuf_unittest.UnittestProto.packedDoubleExtension;
+import static protobuf_unittest.UnittestProto.packedBoolExtension;
+import static protobuf_unittest.UnittestProto.packedEnumExtension;
+
+import static com.google.protobuf.UnittestLite.defaultInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.defaultCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.optionalInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.optionalCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.repeatedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedBytesExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedGroupExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportMessageExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedNestedEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedForeignEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedImportEnumExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedStringPieceExtensionLite;
+import static com.google.protobuf.UnittestLite.repeatedCordExtensionLite;
+
+import static com.google.protobuf.UnittestLite.OptionalGroup_extension_lite;
+import static com.google.protobuf.UnittestLite.RepeatedGroup_extension_lite;
+
+import static com.google.protobuf.UnittestLite.packedInt32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedInt64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedUint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSint64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed32ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedSfixed64ExtensionLite;
+import static com.google.protobuf.UnittestLite.packedFloatExtensionLite;
+import static com.google.protobuf.UnittestLite.packedDoubleExtensionLite;
+import static com.google.protobuf.UnittestLite.packedBoolExtensionLite;
+import static com.google.protobuf.UnittestLite.packedEnumExtensionLite;
+
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestProto.ForeignMessage;
+import protobuf_unittest.UnittestProto.ForeignEnum;
+import com.google.protobuf.test.UnittestImport.ImportMessage;
+import com.google.protobuf.test.UnittestImport.ImportEnum;
+
+import com.google.protobuf.UnittestLite.TestAllTypesLite;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+import com.google.protobuf.UnittestLite.ForeignMessageLite;
+import com.google.protobuf.UnittestLite.ForeignEnumLite;
+import com.google.protobuf.UnittestImportLite.ImportMessageLite;
+import com.google.protobuf.UnittestImportLite.ImportEnumLite;
+
+import junit.framework.Assert;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Contains methods for setting all fields of {@code TestAllTypes} to
+ * some vaules as well as checking that all the fields are set to those values.
+ * These are useful for testing various protocol message features, e.g.
+ * set all fields of a message, serialize it, parse it, and check that all
+ * fields are set.
+ *
+ * @author kenton@google.com Kenton Varda
+ */
+class TestUtil {
+ private TestUtil() {}
+
+ /** Helper to convert a String to ByteString. */
+ static ByteString toBytes(String str) {
+ try {
+ return ByteString.copyFrom(str.getBytes("UTF-8"));
+ } catch(java.io.UnsupportedEncodingException e) {
+ throw new RuntimeException("UTF-8 not supported.", e);
+ }
+ }
+
+ /**
+ * Get a {@code TestAllTypes} with all fields set as they would be by
+ * {@link #setAllFields(TestAllTypes.Builder)}.
+ */
+ public static TestAllTypes getAllSet() {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ setAllFields(builder);
+ return builder.build();
+ }
+
+ /**
+ * Get a {@code TestAllExtensions} with all fields set as they would be by
+ * {@link #setAllExtensions(TestAllExtensions.Builder)}.
+ */
+ public static TestAllExtensions getAllExtensionsSet() {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ setAllExtensions(builder);
+ return builder.build();
+ }
+
+ public static TestAllExtensionsLite getAllLiteExtensionsSet() {
+ TestAllExtensionsLite.Builder builder = TestAllExtensionsLite.newBuilder();
+ setAllExtensions(builder);
+ return builder.build();
+ }
+
+ public static TestPackedTypes getPackedSet() {
+ TestPackedTypes.Builder builder = TestPackedTypes.newBuilder();
+ setPackedFields(builder);
+ return builder.build();
+ }
+
+ public static TestPackedExtensions getPackedExtensionsSet() {
+ TestPackedExtensions.Builder builder = TestPackedExtensions.newBuilder();
+ setPackedExtensions(builder);
+ return builder.build();
+ }
+
+ public static TestPackedExtensionsLite getLitePackedExtensionsSet() {
+ TestPackedExtensionsLite.Builder builder =
+ TestPackedExtensionsLite.newBuilder();
+ setPackedExtensions(builder);
+ return builder.build();
+ }
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllFieldsSet()}.
+ */
+ public static void setAllFields(TestAllTypes.Builder message) {
+ message.setOptionalInt32 (101);
+ message.setOptionalInt64 (102);
+ message.setOptionalUint32 (103);
+ message.setOptionalUint64 (104);
+ message.setOptionalSint32 (105);
+ message.setOptionalSint64 (106);
+ message.setOptionalFixed32 (107);
+ message.setOptionalFixed64 (108);
+ message.setOptionalSfixed32(109);
+ message.setOptionalSfixed64(110);
+ message.setOptionalFloat (111);
+ message.setOptionalDouble (112);
+ message.setOptionalBool (true);
+ message.setOptionalString ("115");
+ message.setOptionalBytes (toBytes("116"));
+
+ message.setOptionalGroup(
+ TestAllTypes.OptionalGroup.newBuilder().setA(117).build());
+ message.setOptionalNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+ message.setOptionalForeignMessage(
+ ForeignMessage.newBuilder().setC(119).build());
+ message.setOptionalImportMessage(
+ ImportMessage.newBuilder().setD(120).build());
+
+ message.setOptionalNestedEnum (TestAllTypes.NestedEnum.BAZ);
+ message.setOptionalForeignEnum(ForeignEnum.FOREIGN_BAZ);
+ message.setOptionalImportEnum (ImportEnum.IMPORT_BAZ);
+
+ message.setOptionalStringPiece("124");
+ message.setOptionalCord("125");
+
+ // -----------------------------------------------------------------
+
+ message.addRepeatedInt32 (201);
+ message.addRepeatedInt64 (202);
+ message.addRepeatedUint32 (203);
+ message.addRepeatedUint64 (204);
+ message.addRepeatedSint32 (205);
+ message.addRepeatedSint64 (206);
+ message.addRepeatedFixed32 (207);
+ message.addRepeatedFixed64 (208);
+ message.addRepeatedSfixed32(209);
+ message.addRepeatedSfixed64(210);
+ message.addRepeatedFloat (211);
+ message.addRepeatedDouble (212);
+ message.addRepeatedBool (true);
+ message.addRepeatedString ("215");
+ message.addRepeatedBytes (toBytes("216"));
+
+ message.addRepeatedGroup(
+ TestAllTypes.RepeatedGroup.newBuilder().setA(217).build());
+ message.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ message.addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(219).build());
+ message.addRepeatedImportMessage(
+ ImportMessage.newBuilder().setD(220).build());
+
+ message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAR);
+ message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAR);
+ message.addRepeatedImportEnum (ImportEnum.IMPORT_BAR);
+
+ message.addRepeatedStringPiece("224");
+ message.addRepeatedCord("225");
+
+ // Add a second one of each field.
+ message.addRepeatedInt32 (301);
+ message.addRepeatedInt64 (302);
+ message.addRepeatedUint32 (303);
+ message.addRepeatedUint64 (304);
+ message.addRepeatedSint32 (305);
+ message.addRepeatedSint64 (306);
+ message.addRepeatedFixed32 (307);
+ message.addRepeatedFixed64 (308);
+ message.addRepeatedSfixed32(309);
+ message.addRepeatedSfixed64(310);
+ message.addRepeatedFloat (311);
+ message.addRepeatedDouble (312);
+ message.addRepeatedBool (false);
+ message.addRepeatedString ("315");
+ message.addRepeatedBytes (toBytes("316"));
+
+ message.addRepeatedGroup(
+ TestAllTypes.RepeatedGroup.newBuilder().setA(317).build());
+ message.addRepeatedNestedMessage(
+ TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+ message.addRepeatedForeignMessage(
+ ForeignMessage.newBuilder().setC(319).build());
+ message.addRepeatedImportMessage(
+ ImportMessage.newBuilder().setD(320).build());
+
+ message.addRepeatedNestedEnum (TestAllTypes.NestedEnum.BAZ);
+ message.addRepeatedForeignEnum(ForeignEnum.FOREIGN_BAZ);
+ message.addRepeatedImportEnum (ImportEnum.IMPORT_BAZ);
+
+ message.addRepeatedStringPiece("324");
+ message.addRepeatedCord("325");
+
+ // -----------------------------------------------------------------
+
+ message.setDefaultInt32 (401);
+ message.setDefaultInt64 (402);
+ message.setDefaultUint32 (403);
+ message.setDefaultUint64 (404);
+ message.setDefaultSint32 (405);
+ message.setDefaultSint64 (406);
+ message.setDefaultFixed32 (407);
+ message.setDefaultFixed64 (408);
+ message.setDefaultSfixed32(409);
+ message.setDefaultSfixed64(410);
+ message.setDefaultFloat (411);
+ message.setDefaultDouble (412);
+ message.setDefaultBool (false);
+ message.setDefaultString ("415");
+ message.setDefaultBytes (toBytes("416"));
+
+ message.setDefaultNestedEnum (TestAllTypes.NestedEnum.FOO);
+ message.setDefaultForeignEnum(ForeignEnum.FOREIGN_FOO);
+ message.setDefaultImportEnum (ImportEnum.IMPORT_FOO);
+
+ message.setDefaultStringPiece("424");
+ message.setDefaultCord("425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated fields of {@code message} to contain the values
+ * expected by {@code assertRepeatedFieldsModified()}.
+ */
+ public static void modifyRepeatedFields(TestAllTypes.Builder message) {
+ message.setRepeatedInt32 (1, 501);
+ message.setRepeatedInt64 (1, 502);
+ message.setRepeatedUint32 (1, 503);
+ message.setRepeatedUint64 (1, 504);
+ message.setRepeatedSint32 (1, 505);
+ message.setRepeatedSint64 (1, 506);
+ message.setRepeatedFixed32 (1, 507);
+ message.setRepeatedFixed64 (1, 508);
+ message.setRepeatedSfixed32(1, 509);
+ message.setRepeatedSfixed64(1, 510);
+ message.setRepeatedFloat (1, 511);
+ message.setRepeatedDouble (1, 512);
+ message.setRepeatedBool (1, true);
+ message.setRepeatedString (1, "515");
+ message.setRepeatedBytes (1, toBytes("516"));
+
+ message.setRepeatedGroup(1,
+ TestAllTypes.RepeatedGroup.newBuilder().setA(517).build());
+ message.setRepeatedNestedMessage(1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+ message.setRepeatedForeignMessage(1,
+ ForeignMessage.newBuilder().setC(519).build());
+ message.setRepeatedImportMessage(1,
+ ImportMessage.newBuilder().setD(520).build());
+
+ message.setRepeatedNestedEnum (1, TestAllTypes.NestedEnum.FOO);
+ message.setRepeatedForeignEnum(1, ForeignEnum.FOREIGN_FOO);
+ message.setRepeatedImportEnum (1, ImportEnum.IMPORT_FOO);
+
+ message.setRepeatedStringPiece(1, "524");
+ message.setRepeatedCord(1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}.
+ */
+ public static void assertAllFieldsSet(TestAllTypes message) {
+ Assert.assertTrue(message.hasOptionalInt32 ());
+ Assert.assertTrue(message.hasOptionalInt64 ());
+ Assert.assertTrue(message.hasOptionalUint32 ());
+ Assert.assertTrue(message.hasOptionalUint64 ());
+ Assert.assertTrue(message.hasOptionalSint32 ());
+ Assert.assertTrue(message.hasOptionalSint64 ());
+ Assert.assertTrue(message.hasOptionalFixed32 ());
+ Assert.assertTrue(message.hasOptionalFixed64 ());
+ Assert.assertTrue(message.hasOptionalSfixed32());
+ Assert.assertTrue(message.hasOptionalSfixed64());
+ Assert.assertTrue(message.hasOptionalFloat ());
+ Assert.assertTrue(message.hasOptionalDouble ());
+ Assert.assertTrue(message.hasOptionalBool ());
+ Assert.assertTrue(message.hasOptionalString ());
+ Assert.assertTrue(message.hasOptionalBytes ());
+
+ Assert.assertTrue(message.hasOptionalGroup ());
+ Assert.assertTrue(message.hasOptionalNestedMessage ());
+ Assert.assertTrue(message.hasOptionalForeignMessage());
+ Assert.assertTrue(message.hasOptionalImportMessage ());
+
+ Assert.assertTrue(message.getOptionalGroup ().hasA());
+ Assert.assertTrue(message.getOptionalNestedMessage ().hasBb());
+ Assert.assertTrue(message.getOptionalForeignMessage().hasC());
+ Assert.assertTrue(message.getOptionalImportMessage ().hasD());
+
+ Assert.assertTrue(message.hasOptionalNestedEnum ());
+ Assert.assertTrue(message.hasOptionalForeignEnum());
+ Assert.assertTrue(message.hasOptionalImportEnum ());
+
+ Assert.assertTrue(message.hasOptionalStringPiece());
+ Assert.assertTrue(message.hasOptionalCord());
+
+ Assert.assertEquals(101 , message.getOptionalInt32 ());
+ Assert.assertEquals(102 , message.getOptionalInt64 ());
+ Assert.assertEquals(103 , message.getOptionalUint32 ());
+ Assert.assertEquals(104 , message.getOptionalUint64 ());
+ Assert.assertEquals(105 , message.getOptionalSint32 ());
+ Assert.assertEquals(106 , message.getOptionalSint64 ());
+ Assert.assertEquals(107 , message.getOptionalFixed32 ());
+ Assert.assertEquals(108 , message.getOptionalFixed64 ());
+ Assert.assertEquals(109 , message.getOptionalSfixed32());
+ Assert.assertEquals(110 , message.getOptionalSfixed64());
+ Assert.assertEquals(111 , message.getOptionalFloat (), 0.0);
+ Assert.assertEquals(112 , message.getOptionalDouble (), 0.0);
+ Assert.assertEquals(true , message.getOptionalBool ());
+ Assert.assertEquals("115", message.getOptionalString ());
+ Assert.assertEquals(toBytes("116"), message.getOptionalBytes());
+
+ Assert.assertEquals(117, message.getOptionalGroup ().getA());
+ Assert.assertEquals(118, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(119, message.getOptionalForeignMessage().getC());
+ Assert.assertEquals(120, message.getOptionalImportMessage ().getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getOptionalNestedEnum());
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getOptionalForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getOptionalImportEnum());
+
+ Assert.assertEquals("124", message.getOptionalStringPiece());
+ Assert.assertEquals("125", message.getOptionalCord());
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getRepeatedInt32Count ());
+ Assert.assertEquals(2, message.getRepeatedInt64Count ());
+ Assert.assertEquals(2, message.getRepeatedUint32Count ());
+ Assert.assertEquals(2, message.getRepeatedUint64Count ());
+ Assert.assertEquals(2, message.getRepeatedSint32Count ());
+ Assert.assertEquals(2, message.getRepeatedSint64Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(2, message.getRepeatedFloatCount ());
+ Assert.assertEquals(2, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(2, message.getRepeatedBoolCount ());
+ Assert.assertEquals(2, message.getRepeatedStringCount ());
+ Assert.assertEquals(2, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(2, message.getRepeatedGroupCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(2, message.getRepeatedCordCount());
+
+ Assert.assertEquals(201 , message.getRepeatedInt32 (0));
+ Assert.assertEquals(202 , message.getRepeatedInt64 (0));
+ Assert.assertEquals(203 , message.getRepeatedUint32 (0));
+ Assert.assertEquals(204 , message.getRepeatedUint64 (0));
+ Assert.assertEquals(205 , message.getRepeatedSint32 (0));
+ Assert.assertEquals(206 , message.getRepeatedSint64 (0));
+ Assert.assertEquals(207 , message.getRepeatedFixed32 (0));
+ Assert.assertEquals(208 , message.getRepeatedFixed64 (0));
+ Assert.assertEquals(209 , message.getRepeatedSfixed32(0));
+ Assert.assertEquals(210 , message.getRepeatedSfixed64(0));
+ Assert.assertEquals(211 , message.getRepeatedFloat (0), 0.0);
+ Assert.assertEquals(212 , message.getRepeatedDouble (0), 0.0);
+ Assert.assertEquals(true , message.getRepeatedBool (0));
+ Assert.assertEquals("215", message.getRepeatedString (0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+ Assert.assertEquals(217, message.getRepeatedGroup (0).getA());
+ Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+ Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+ Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+ Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+ Assert.assertEquals("225", message.getRepeatedCord(0));
+
+ Assert.assertEquals(301 , message.getRepeatedInt32 (1));
+ Assert.assertEquals(302 , message.getRepeatedInt64 (1));
+ Assert.assertEquals(303 , message.getRepeatedUint32 (1));
+ Assert.assertEquals(304 , message.getRepeatedUint64 (1));
+ Assert.assertEquals(305 , message.getRepeatedSint32 (1));
+ Assert.assertEquals(306 , message.getRepeatedSint64 (1));
+ Assert.assertEquals(307 , message.getRepeatedFixed32 (1));
+ Assert.assertEquals(308 , message.getRepeatedFixed64 (1));
+ Assert.assertEquals(309 , message.getRepeatedSfixed32(1));
+ Assert.assertEquals(310 , message.getRepeatedSfixed64(1));
+ Assert.assertEquals(311 , message.getRepeatedFloat (1), 0.0);
+ Assert.assertEquals(312 , message.getRepeatedDouble (1), 0.0);
+ Assert.assertEquals(false, message.getRepeatedBool (1));
+ Assert.assertEquals("315", message.getRepeatedString (1));
+ Assert.assertEquals(toBytes("316"), message.getRepeatedBytes(1));
+
+ Assert.assertEquals(317, message.getRepeatedGroup (1).getA());
+ Assert.assertEquals(318, message.getRepeatedNestedMessage (1).getBb());
+ Assert.assertEquals(319, message.getRepeatedForeignMessage(1).getC());
+ Assert.assertEquals(320, message.getRepeatedImportMessage (1).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAZ, message.getRepeatedNestedEnum (1));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getRepeatedForeignEnum(1));
+ Assert.assertEquals(ImportEnum.IMPORT_BAZ, message.getRepeatedImportEnum(1));
+
+ Assert.assertEquals("324", message.getRepeatedStringPiece(1));
+ Assert.assertEquals("325", message.getRepeatedCord(1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasDefaultInt32 ());
+ Assert.assertTrue(message.hasDefaultInt64 ());
+ Assert.assertTrue(message.hasDefaultUint32 ());
+ Assert.assertTrue(message.hasDefaultUint64 ());
+ Assert.assertTrue(message.hasDefaultSint32 ());
+ Assert.assertTrue(message.hasDefaultSint64 ());
+ Assert.assertTrue(message.hasDefaultFixed32 ());
+ Assert.assertTrue(message.hasDefaultFixed64 ());
+ Assert.assertTrue(message.hasDefaultSfixed32());
+ Assert.assertTrue(message.hasDefaultSfixed64());
+ Assert.assertTrue(message.hasDefaultFloat ());
+ Assert.assertTrue(message.hasDefaultDouble ());
+ Assert.assertTrue(message.hasDefaultBool ());
+ Assert.assertTrue(message.hasDefaultString ());
+ Assert.assertTrue(message.hasDefaultBytes ());
+
+ Assert.assertTrue(message.hasDefaultNestedEnum ());
+ Assert.assertTrue(message.hasDefaultForeignEnum());
+ Assert.assertTrue(message.hasDefaultImportEnum ());
+
+ Assert.assertTrue(message.hasDefaultStringPiece());
+ Assert.assertTrue(message.hasDefaultCord());
+
+ Assert.assertEquals(401 , message.getDefaultInt32 ());
+ Assert.assertEquals(402 , message.getDefaultInt64 ());
+ Assert.assertEquals(403 , message.getDefaultUint32 ());
+ Assert.assertEquals(404 , message.getDefaultUint64 ());
+ Assert.assertEquals(405 , message.getDefaultSint32 ());
+ Assert.assertEquals(406 , message.getDefaultSint64 ());
+ Assert.assertEquals(407 , message.getDefaultFixed32 ());
+ Assert.assertEquals(408 , message.getDefaultFixed64 ());
+ Assert.assertEquals(409 , message.getDefaultSfixed32());
+ Assert.assertEquals(410 , message.getDefaultSfixed64());
+ Assert.assertEquals(411 , message.getDefaultFloat (), 0.0);
+ Assert.assertEquals(412 , message.getDefaultDouble (), 0.0);
+ Assert.assertEquals(false, message.getDefaultBool ());
+ Assert.assertEquals("415", message.getDefaultString ());
+ Assert.assertEquals(toBytes("416"), message.getDefaultBytes());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getDefaultNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getDefaultForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getDefaultImportEnum());
+
+ Assert.assertEquals("424", message.getDefaultStringPiece());
+ Assert.assertEquals("425", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are cleared, and that getting the fields returns their
+ * default values.
+ */
+ public static void assertClear(TestAllTypes message) {
+ // hasBlah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasOptionalInt32 ());
+ Assert.assertFalse(message.hasOptionalInt64 ());
+ Assert.assertFalse(message.hasOptionalUint32 ());
+ Assert.assertFalse(message.hasOptionalUint64 ());
+ Assert.assertFalse(message.hasOptionalSint32 ());
+ Assert.assertFalse(message.hasOptionalSint64 ());
+ Assert.assertFalse(message.hasOptionalFixed32 ());
+ Assert.assertFalse(message.hasOptionalFixed64 ());
+ Assert.assertFalse(message.hasOptionalSfixed32());
+ Assert.assertFalse(message.hasOptionalSfixed64());
+ Assert.assertFalse(message.hasOptionalFloat ());
+ Assert.assertFalse(message.hasOptionalDouble ());
+ Assert.assertFalse(message.hasOptionalBool ());
+ Assert.assertFalse(message.hasOptionalString ());
+ Assert.assertFalse(message.hasOptionalBytes ());
+
+ Assert.assertFalse(message.hasOptionalGroup ());
+ Assert.assertFalse(message.hasOptionalNestedMessage ());
+ Assert.assertFalse(message.hasOptionalForeignMessage());
+ Assert.assertFalse(message.hasOptionalImportMessage ());
+
+ Assert.assertFalse(message.hasOptionalNestedEnum ());
+ Assert.assertFalse(message.hasOptionalForeignEnum());
+ Assert.assertFalse(message.hasOptionalImportEnum ());
+
+ Assert.assertFalse(message.hasOptionalStringPiece());
+ Assert.assertFalse(message.hasOptionalCord());
+
+ // Optional fields without defaults are set to zero or something like it.
+ Assert.assertEquals(0 , message.getOptionalInt32 ());
+ Assert.assertEquals(0 , message.getOptionalInt64 ());
+ Assert.assertEquals(0 , message.getOptionalUint32 ());
+ Assert.assertEquals(0 , message.getOptionalUint64 ());
+ Assert.assertEquals(0 , message.getOptionalSint32 ());
+ Assert.assertEquals(0 , message.getOptionalSint64 ());
+ Assert.assertEquals(0 , message.getOptionalFixed32 ());
+ Assert.assertEquals(0 , message.getOptionalFixed64 ());
+ Assert.assertEquals(0 , message.getOptionalSfixed32());
+ Assert.assertEquals(0 , message.getOptionalSfixed64());
+ Assert.assertEquals(0 , message.getOptionalFloat (), 0.0);
+ Assert.assertEquals(0 , message.getOptionalDouble (), 0.0);
+ Assert.assertEquals(false, message.getOptionalBool ());
+ Assert.assertEquals("" , message.getOptionalString ());
+ Assert.assertEquals(ByteString.EMPTY, message.getOptionalBytes());
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(message.getOptionalGroup ().hasA());
+ Assert.assertFalse(message.getOptionalNestedMessage ().hasBb());
+ Assert.assertFalse(message.getOptionalForeignMessage().hasC());
+ Assert.assertFalse(message.getOptionalImportMessage ().hasD());
+
+ Assert.assertEquals(0, message.getOptionalGroup ().getA());
+ Assert.assertEquals(0, message.getOptionalNestedMessage ().getBb());
+ Assert.assertEquals(0, message.getOptionalForeignMessage().getC());
+ Assert.assertEquals(0, message.getOptionalImportMessage ().getD());
+
+ // Enums without defaults are set to the first value in the enum.
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getOptionalForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getOptionalImportEnum());
+
+ Assert.assertEquals("", message.getOptionalStringPiece());
+ Assert.assertEquals("", message.getOptionalCord());
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getRepeatedInt32Count ());
+ Assert.assertEquals(0, message.getRepeatedInt64Count ());
+ Assert.assertEquals(0, message.getRepeatedUint32Count ());
+ Assert.assertEquals(0, message.getRepeatedUint64Count ());
+ Assert.assertEquals(0, message.getRepeatedSint32Count ());
+ Assert.assertEquals(0, message.getRepeatedSint64Count ());
+ Assert.assertEquals(0, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(0, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(0, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(0, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(0, message.getRepeatedFloatCount ());
+ Assert.assertEquals(0, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(0, message.getRepeatedBoolCount ());
+ Assert.assertEquals(0, message.getRepeatedStringCount ());
+ Assert.assertEquals(0, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(0, message.getRepeatedGroupCount ());
+ Assert.assertEquals(0, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(0, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(0, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(0, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(0, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(0, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(0, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(0, message.getRepeatedCordCount());
+
+ // hasBlah() should also be false for all default fields.
+ Assert.assertFalse(message.hasDefaultInt32 ());
+ Assert.assertFalse(message.hasDefaultInt64 ());
+ Assert.assertFalse(message.hasDefaultUint32 ());
+ Assert.assertFalse(message.hasDefaultUint64 ());
+ Assert.assertFalse(message.hasDefaultSint32 ());
+ Assert.assertFalse(message.hasDefaultSint64 ());
+ Assert.assertFalse(message.hasDefaultFixed32 ());
+ Assert.assertFalse(message.hasDefaultFixed64 ());
+ Assert.assertFalse(message.hasDefaultSfixed32());
+ Assert.assertFalse(message.hasDefaultSfixed64());
+ Assert.assertFalse(message.hasDefaultFloat ());
+ Assert.assertFalse(message.hasDefaultDouble ());
+ Assert.assertFalse(message.hasDefaultBool ());
+ Assert.assertFalse(message.hasDefaultString ());
+ Assert.assertFalse(message.hasDefaultBytes ());
+
+ Assert.assertFalse(message.hasDefaultNestedEnum ());
+ Assert.assertFalse(message.hasDefaultForeignEnum());
+ Assert.assertFalse(message.hasDefaultImportEnum ());
+
+ Assert.assertFalse(message.hasDefaultStringPiece());
+ Assert.assertFalse(message.hasDefaultCord());
+
+ // Fields with defaults have their default values (duh).
+ Assert.assertEquals( 41 , message.getDefaultInt32 ());
+ Assert.assertEquals( 42 , message.getDefaultInt64 ());
+ Assert.assertEquals( 43 , message.getDefaultUint32 ());
+ Assert.assertEquals( 44 , message.getDefaultUint64 ());
+ Assert.assertEquals(-45 , message.getDefaultSint32 ());
+ Assert.assertEquals( 46 , message.getDefaultSint64 ());
+ Assert.assertEquals( 47 , message.getDefaultFixed32 ());
+ Assert.assertEquals( 48 , message.getDefaultFixed64 ());
+ Assert.assertEquals( 49 , message.getDefaultSfixed32());
+ Assert.assertEquals(-50 , message.getDefaultSfixed64());
+ Assert.assertEquals( 51.5 , message.getDefaultFloat (), 0.0);
+ Assert.assertEquals( 52e3 , message.getDefaultDouble (), 0.0);
+ Assert.assertEquals(true , message.getDefaultBool ());
+ Assert.assertEquals("hello", message.getDefaultString ());
+ Assert.assertEquals(toBytes("world"), message.getDefaultBytes());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getDefaultNestedEnum ());
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getDefaultForeignEnum());
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getDefaultImportEnum());
+
+ Assert.assertEquals("abc", message.getDefaultStringPiece());
+ Assert.assertEquals("123", message.getDefaultCord());
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields}
+ * followed by {@code modifyRepeatedFields}.
+ */
+ public static void assertRepeatedFieldsModified(TestAllTypes message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ Assert.assertEquals(2, message.getRepeatedInt32Count ());
+ Assert.assertEquals(2, message.getRepeatedInt64Count ());
+ Assert.assertEquals(2, message.getRepeatedUint32Count ());
+ Assert.assertEquals(2, message.getRepeatedUint64Count ());
+ Assert.assertEquals(2, message.getRepeatedSint32Count ());
+ Assert.assertEquals(2, message.getRepeatedSint64Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed32Count ());
+ Assert.assertEquals(2, message.getRepeatedFixed64Count ());
+ Assert.assertEquals(2, message.getRepeatedSfixed32Count());
+ Assert.assertEquals(2, message.getRepeatedSfixed64Count());
+ Assert.assertEquals(2, message.getRepeatedFloatCount ());
+ Assert.assertEquals(2, message.getRepeatedDoubleCount ());
+ Assert.assertEquals(2, message.getRepeatedBoolCount ());
+ Assert.assertEquals(2, message.getRepeatedStringCount ());
+ Assert.assertEquals(2, message.getRepeatedBytesCount ());
+
+ Assert.assertEquals(2, message.getRepeatedGroupCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignMessageCount());
+ Assert.assertEquals(2, message.getRepeatedImportMessageCount ());
+ Assert.assertEquals(2, message.getRepeatedNestedEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedForeignEnumCount ());
+ Assert.assertEquals(2, message.getRepeatedImportEnumCount ());
+
+ Assert.assertEquals(2, message.getRepeatedStringPieceCount());
+ Assert.assertEquals(2, message.getRepeatedCordCount());
+
+ Assert.assertEquals(201 , message.getRepeatedInt32 (0));
+ Assert.assertEquals(202L , message.getRepeatedInt64 (0));
+ Assert.assertEquals(203 , message.getRepeatedUint32 (0));
+ Assert.assertEquals(204L , message.getRepeatedUint64 (0));
+ Assert.assertEquals(205 , message.getRepeatedSint32 (0));
+ Assert.assertEquals(206L , message.getRepeatedSint64 (0));
+ Assert.assertEquals(207 , message.getRepeatedFixed32 (0));
+ Assert.assertEquals(208L , message.getRepeatedFixed64 (0));
+ Assert.assertEquals(209 , message.getRepeatedSfixed32(0));
+ Assert.assertEquals(210L , message.getRepeatedSfixed64(0));
+ Assert.assertEquals(211F , message.getRepeatedFloat (0));
+ Assert.assertEquals(212D , message.getRepeatedDouble (0));
+ Assert.assertEquals(true , message.getRepeatedBool (0));
+ Assert.assertEquals("215", message.getRepeatedString (0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedBytes(0));
+
+ Assert.assertEquals(217, message.getRepeatedGroup (0).getA());
+ Assert.assertEquals(218, message.getRepeatedNestedMessage (0).getBb());
+ Assert.assertEquals(219, message.getRepeatedForeignMessage(0).getC());
+ Assert.assertEquals(220, message.getRepeatedImportMessage (0).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.BAR, message.getRepeatedNestedEnum (0));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getRepeatedForeignEnum(0));
+ Assert.assertEquals(ImportEnum.IMPORT_BAR, message.getRepeatedImportEnum(0));
+
+ Assert.assertEquals("224", message.getRepeatedStringPiece(0));
+ Assert.assertEquals("225", message.getRepeatedCord(0));
+
+ // Actually verify the second (modified) elements now.
+ Assert.assertEquals(501 , message.getRepeatedInt32 (1));
+ Assert.assertEquals(502L , message.getRepeatedInt64 (1));
+ Assert.assertEquals(503 , message.getRepeatedUint32 (1));
+ Assert.assertEquals(504L , message.getRepeatedUint64 (1));
+ Assert.assertEquals(505 , message.getRepeatedSint32 (1));
+ Assert.assertEquals(506L , message.getRepeatedSint64 (1));
+ Assert.assertEquals(507 , message.getRepeatedFixed32 (1));
+ Assert.assertEquals(508L , message.getRepeatedFixed64 (1));
+ Assert.assertEquals(509 , message.getRepeatedSfixed32(1));
+ Assert.assertEquals(510L , message.getRepeatedSfixed64(1));
+ Assert.assertEquals(511F , message.getRepeatedFloat (1));
+ Assert.assertEquals(512D , message.getRepeatedDouble (1));
+ Assert.assertEquals(true , message.getRepeatedBool (1));
+ Assert.assertEquals("515", message.getRepeatedString (1));
+ Assert.assertEquals(toBytes("516"), message.getRepeatedBytes(1));
+
+ Assert.assertEquals(517, message.getRepeatedGroup (1).getA());
+ Assert.assertEquals(518, message.getRepeatedNestedMessage (1).getBb());
+ Assert.assertEquals(519, message.getRepeatedForeignMessage(1).getC());
+ Assert.assertEquals(520, message.getRepeatedImportMessage (1).getD());
+
+ Assert.assertEquals(TestAllTypes.NestedEnum.FOO, message.getRepeatedNestedEnum (1));
+ Assert.assertEquals(ForeignEnum.FOREIGN_FOO, message.getRepeatedForeignEnum(1));
+ Assert.assertEquals(ImportEnum.IMPORT_FOO, message.getRepeatedImportEnum(1));
+
+ Assert.assertEquals("524", message.getRepeatedStringPiece(1));
+ Assert.assertEquals("525", message.getRepeatedCord(1));
+ }
+
+ /**
+ * Set every field of {@code message} to a unique value.
+ */
+ public static void setPackedFields(TestPackedTypes.Builder message) {
+ message.addPackedInt32 (601);
+ message.addPackedInt64 (602);
+ message.addPackedUint32 (603);
+ message.addPackedUint64 (604);
+ message.addPackedSint32 (605);
+ message.addPackedSint64 (606);
+ message.addPackedFixed32 (607);
+ message.addPackedFixed64 (608);
+ message.addPackedSfixed32(609);
+ message.addPackedSfixed64(610);
+ message.addPackedFloat (611);
+ message.addPackedDouble (612);
+ message.addPackedBool (true);
+ message.addPackedEnum (ForeignEnum.FOREIGN_BAR);
+ // Add a second one of each field.
+ message.addPackedInt32 (701);
+ message.addPackedInt64 (702);
+ message.addPackedUint32 (703);
+ message.addPackedUint64 (704);
+ message.addPackedSint32 (705);
+ message.addPackedSint64 (706);
+ message.addPackedFixed32 (707);
+ message.addPackedFixed64 (708);
+ message.addPackedSfixed32(709);
+ message.addPackedSfixed64(710);
+ message.addPackedFloat (711);
+ message.addPackedDouble (712);
+ message.addPackedBool (false);
+ message.addPackedEnum (ForeignEnum.FOREIGN_BAZ);
+ }
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setPackedFields}.
+ */
+ public static void assertPackedFieldsSet(TestPackedTypes message) {
+ Assert.assertEquals(2, message.getPackedInt32Count ());
+ Assert.assertEquals(2, message.getPackedInt64Count ());
+ Assert.assertEquals(2, message.getPackedUint32Count ());
+ Assert.assertEquals(2, message.getPackedUint64Count ());
+ Assert.assertEquals(2, message.getPackedSint32Count ());
+ Assert.assertEquals(2, message.getPackedSint64Count ());
+ Assert.assertEquals(2, message.getPackedFixed32Count ());
+ Assert.assertEquals(2, message.getPackedFixed64Count ());
+ Assert.assertEquals(2, message.getPackedSfixed32Count());
+ Assert.assertEquals(2, message.getPackedSfixed64Count());
+ Assert.assertEquals(2, message.getPackedFloatCount ());
+ Assert.assertEquals(2, message.getPackedDoubleCount ());
+ Assert.assertEquals(2, message.getPackedBoolCount ());
+ Assert.assertEquals(2, message.getPackedEnumCount ());
+ Assert.assertEquals(601 , message.getPackedInt32 (0));
+ Assert.assertEquals(602 , message.getPackedInt64 (0));
+ Assert.assertEquals(603 , message.getPackedUint32 (0));
+ Assert.assertEquals(604 , message.getPackedUint64 (0));
+ Assert.assertEquals(605 , message.getPackedSint32 (0));
+ Assert.assertEquals(606 , message.getPackedSint64 (0));
+ Assert.assertEquals(607 , message.getPackedFixed32 (0));
+ Assert.assertEquals(608 , message.getPackedFixed64 (0));
+ Assert.assertEquals(609 , message.getPackedSfixed32(0));
+ Assert.assertEquals(610 , message.getPackedSfixed64(0));
+ Assert.assertEquals(611 , message.getPackedFloat (0), 0.0);
+ Assert.assertEquals(612 , message.getPackedDouble (0), 0.0);
+ Assert.assertEquals(true , message.getPackedBool (0));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAR, message.getPackedEnum(0));
+ Assert.assertEquals(701 , message.getPackedInt32 (1));
+ Assert.assertEquals(702 , message.getPackedInt64 (1));
+ Assert.assertEquals(703 , message.getPackedUint32 (1));
+ Assert.assertEquals(704 , message.getPackedUint64 (1));
+ Assert.assertEquals(705 , message.getPackedSint32 (1));
+ Assert.assertEquals(706 , message.getPackedSint64 (1));
+ Assert.assertEquals(707 , message.getPackedFixed32 (1));
+ Assert.assertEquals(708 , message.getPackedFixed64 (1));
+ Assert.assertEquals(709 , message.getPackedSfixed32(1));
+ Assert.assertEquals(710 , message.getPackedSfixed64(1));
+ Assert.assertEquals(711 , message.getPackedFloat (1), 0.0);
+ Assert.assertEquals(712 , message.getPackedDouble (1), 0.0);
+ Assert.assertEquals(false, message.getPackedBool (1));
+ Assert.assertEquals(ForeignEnum.FOREIGN_BAZ, message.getPackedEnum(1));
+ }
+
+ // ===================================================================
+ // Like above, but for extensions
+
+ // Java gets confused with things like assertEquals(int, Integer): it can't
+ // decide whether to call assertEquals(int, int) or assertEquals(Object,
+ // Object). So we define these methods to help it.
+ private static void assertEqualsExactType(int a, int b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(long a, long b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(float a, float b) {
+ Assert.assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(double a, double b) {
+ Assert.assertEquals(a, b, 0.0);
+ }
+ private static void assertEqualsExactType(boolean a, boolean b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(String a, String b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ByteString a, ByteString b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(TestAllTypes.NestedEnum a,
+ TestAllTypes.NestedEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ForeignEnum a, ForeignEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ImportEnum a, ImportEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(TestAllTypesLite.NestedEnum a,
+ TestAllTypesLite.NestedEnum b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ForeignEnumLite a,
+ ForeignEnumLite b) {
+ Assert.assertEquals(a, b);
+ }
+ private static void assertEqualsExactType(ImportEnumLite a,
+ ImportEnumLite b) {
+ Assert.assertEquals(a, b);
+ }
+
+ /**
+ * Get an unmodifiable {@link ExtensionRegistry} containing all the
+ * extensions of {@code TestAllExtensions}.
+ */
+ public static ExtensionRegistry getExtensionRegistry() {
+ ExtensionRegistry registry = ExtensionRegistry.newInstance();
+ registerAllExtensions(registry);
+ return registry.getUnmodifiable();
+ }
+
+ public static ExtensionRegistryLite getExtensionRegistryLite() {
+ ExtensionRegistryLite registry = ExtensionRegistryLite.newInstance();
+ registerAllExtensionsLite(registry);
+ return registry.getUnmodifiable();
+ }
+
+ /**
+ * Register all of {@code TestAllExtensions}'s extensions with the
+ * given {@link ExtensionRegistry}.
+ */
+ public static void registerAllExtensions(ExtensionRegistry registry) {
+ UnittestProto.registerAllExtensions(registry);
+ registerAllExtensionsLite(registry);
+ }
+
+ public static void registerAllExtensionsLite(ExtensionRegistryLite registry) {
+ UnittestLite.registerAllExtensions(registry);
+ }
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllExtensionsSet()}.
+ */
+ public static void setAllExtensions(TestAllExtensions.Builder message) {
+ message.setExtension(optionalInt32Extension , 101);
+ message.setExtension(optionalInt64Extension , 102L);
+ message.setExtension(optionalUint32Extension , 103);
+ message.setExtension(optionalUint64Extension , 104L);
+ message.setExtension(optionalSint32Extension , 105);
+ message.setExtension(optionalSint64Extension , 106L);
+ message.setExtension(optionalFixed32Extension , 107);
+ message.setExtension(optionalFixed64Extension , 108L);
+ message.setExtension(optionalSfixed32Extension, 109);
+ message.setExtension(optionalSfixed64Extension, 110L);
+ message.setExtension(optionalFloatExtension , 111F);
+ message.setExtension(optionalDoubleExtension , 112D);
+ message.setExtension(optionalBoolExtension , true);
+ message.setExtension(optionalStringExtension , "115");
+ message.setExtension(optionalBytesExtension , toBytes("116"));
+
+ message.setExtension(optionalGroupExtension,
+ OptionalGroup_extension.newBuilder().setA(117).build());
+ message.setExtension(optionalNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(118).build());
+ message.setExtension(optionalForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(119).build());
+ message.setExtension(optionalImportMessageExtension,
+ ImportMessage.newBuilder().setD(120).build());
+
+ message.setExtension(optionalNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+ message.setExtension(optionalForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+ message.setExtension(optionalImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+ message.setExtension(optionalStringPieceExtension, "124");
+ message.setExtension(optionalCordExtension, "125");
+
+ // -----------------------------------------------------------------
+
+ message.addExtension(repeatedInt32Extension , 201);
+ message.addExtension(repeatedInt64Extension , 202L);
+ message.addExtension(repeatedUint32Extension , 203);
+ message.addExtension(repeatedUint64Extension , 204L);
+ message.addExtension(repeatedSint32Extension , 205);
+ message.addExtension(repeatedSint64Extension , 206L);
+ message.addExtension(repeatedFixed32Extension , 207);
+ message.addExtension(repeatedFixed64Extension , 208L);
+ message.addExtension(repeatedSfixed32Extension, 209);
+ message.addExtension(repeatedSfixed64Extension, 210L);
+ message.addExtension(repeatedFloatExtension , 211F);
+ message.addExtension(repeatedDoubleExtension , 212D);
+ message.addExtension(repeatedBoolExtension , true);
+ message.addExtension(repeatedStringExtension , "215");
+ message.addExtension(repeatedBytesExtension , toBytes("216"));
+
+ message.addExtension(repeatedGroupExtension,
+ RepeatedGroup_extension.newBuilder().setA(217).build());
+ message.addExtension(repeatedNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ message.addExtension(repeatedForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(219).build());
+ message.addExtension(repeatedImportMessageExtension,
+ ImportMessage.newBuilder().setD(220).build());
+
+ message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAR);
+ message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAR);
+ message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAR);
+
+ message.addExtension(repeatedStringPieceExtension, "224");
+ message.addExtension(repeatedCordExtension, "225");
+
+ // Add a second one of each field.
+ message.addExtension(repeatedInt32Extension , 301);
+ message.addExtension(repeatedInt64Extension , 302L);
+ message.addExtension(repeatedUint32Extension , 303);
+ message.addExtension(repeatedUint64Extension , 304L);
+ message.addExtension(repeatedSint32Extension , 305);
+ message.addExtension(repeatedSint64Extension , 306L);
+ message.addExtension(repeatedFixed32Extension , 307);
+ message.addExtension(repeatedFixed64Extension , 308L);
+ message.addExtension(repeatedSfixed32Extension, 309);
+ message.addExtension(repeatedSfixed64Extension, 310L);
+ message.addExtension(repeatedFloatExtension , 311F);
+ message.addExtension(repeatedDoubleExtension , 312D);
+ message.addExtension(repeatedBoolExtension , false);
+ message.addExtension(repeatedStringExtension , "315");
+ message.addExtension(repeatedBytesExtension , toBytes("316"));
+
+ message.addExtension(repeatedGroupExtension,
+ RepeatedGroup_extension.newBuilder().setA(317).build());
+ message.addExtension(repeatedNestedMessageExtension,
+ TestAllTypes.NestedMessage.newBuilder().setBb(318).build());
+ message.addExtension(repeatedForeignMessageExtension,
+ ForeignMessage.newBuilder().setC(319).build());
+ message.addExtension(repeatedImportMessageExtension,
+ ImportMessage.newBuilder().setD(320).build());
+
+ message.addExtension(repeatedNestedEnumExtension, TestAllTypes.NestedEnum.BAZ);
+ message.addExtension(repeatedForeignEnumExtension, ForeignEnum.FOREIGN_BAZ);
+ message.addExtension(repeatedImportEnumExtension, ImportEnum.IMPORT_BAZ);
+
+ message.addExtension(repeatedStringPieceExtension, "324");
+ message.addExtension(repeatedCordExtension, "325");
+
+ // -----------------------------------------------------------------
+
+ message.setExtension(defaultInt32Extension , 401);
+ message.setExtension(defaultInt64Extension , 402L);
+ message.setExtension(defaultUint32Extension , 403);
+ message.setExtension(defaultUint64Extension , 404L);
+ message.setExtension(defaultSint32Extension , 405);
+ message.setExtension(defaultSint64Extension , 406L);
+ message.setExtension(defaultFixed32Extension , 407);
+ message.setExtension(defaultFixed64Extension , 408L);
+ message.setExtension(defaultSfixed32Extension, 409);
+ message.setExtension(defaultSfixed64Extension, 410L);
+ message.setExtension(defaultFloatExtension , 411F);
+ message.setExtension(defaultDoubleExtension , 412D);
+ message.setExtension(defaultBoolExtension , false);
+ message.setExtension(defaultStringExtension , "415");
+ message.setExtension(defaultBytesExtension , toBytes("416"));
+
+ message.setExtension(defaultNestedEnumExtension, TestAllTypes.NestedEnum.FOO);
+ message.setExtension(defaultForeignEnumExtension, ForeignEnum.FOREIGN_FOO);
+ message.setExtension(defaultImportEnumExtension, ImportEnum.IMPORT_FOO);
+
+ message.setExtension(defaultStringPieceExtension, "424");
+ message.setExtension(defaultCordExtension, "425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated extensions of {@code message} to contain the values
+ * expected by {@code assertRepeatedExtensionsModified()}.
+ */
+ public static void modifyRepeatedExtensions(
+ TestAllExtensions.Builder message) {
+ message.setExtension(repeatedInt32Extension , 1, 501);
+ message.setExtension(repeatedInt64Extension , 1, 502L);
+ message.setExtension(repeatedUint32Extension , 1, 503);
+ message.setExtension(repeatedUint64Extension , 1, 504L);
+ message.setExtension(repeatedSint32Extension , 1, 505);
+ message.setExtension(repeatedSint64Extension , 1, 506L);
+ message.setExtension(repeatedFixed32Extension , 1, 507);
+ message.setExtension(repeatedFixed64Extension , 1, 508L);
+ message.setExtension(repeatedSfixed32Extension, 1, 509);
+ message.setExtension(repeatedSfixed64Extension, 1, 510L);
+ message.setExtension(repeatedFloatExtension , 1, 511F);
+ message.setExtension(repeatedDoubleExtension , 1, 512D);
+ message.setExtension(repeatedBoolExtension , 1, true);
+ message.setExtension(repeatedStringExtension , 1, "515");
+ message.setExtension(repeatedBytesExtension , 1, toBytes("516"));
+
+ message.setExtension(repeatedGroupExtension, 1,
+ RepeatedGroup_extension.newBuilder().setA(517).build());
+ message.setExtension(repeatedNestedMessageExtension, 1,
+ TestAllTypes.NestedMessage.newBuilder().setBb(518).build());
+ message.setExtension(repeatedForeignMessageExtension, 1,
+ ForeignMessage.newBuilder().setC(519).build());
+ message.setExtension(repeatedImportMessageExtension, 1,
+ ImportMessage.newBuilder().setD(520).build());
+
+ message.setExtension(repeatedNestedEnumExtension , 1, TestAllTypes.NestedEnum.FOO);
+ message.setExtension(repeatedForeignEnumExtension, 1, ForeignEnum.FOREIGN_FOO);
+ message.setExtension(repeatedImportEnumExtension , 1, ImportEnum.IMPORT_FOO);
+
+ message.setExtension(repeatedStringPieceExtension, 1, "524");
+ message.setExtension(repeatedCordExtension, 1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}.
+ */
+ public static void assertAllExtensionsSet(TestAllExtensions message) {
+ Assert.assertTrue(message.hasExtension(optionalInt32Extension ));
+ Assert.assertTrue(message.hasExtension(optionalInt64Extension ));
+ Assert.assertTrue(message.hasExtension(optionalUint32Extension ));
+ Assert.assertTrue(message.hasExtension(optionalUint64Extension ));
+ Assert.assertTrue(message.hasExtension(optionalSint32Extension ));
+ Assert.assertTrue(message.hasExtension(optionalSint64Extension ));
+ Assert.assertTrue(message.hasExtension(optionalFixed32Extension ));
+ Assert.assertTrue(message.hasExtension(optionalFixed64Extension ));
+ Assert.assertTrue(message.hasExtension(optionalSfixed32Extension));
+ Assert.assertTrue(message.hasExtension(optionalSfixed64Extension));
+ Assert.assertTrue(message.hasExtension(optionalFloatExtension ));
+ Assert.assertTrue(message.hasExtension(optionalDoubleExtension ));
+ Assert.assertTrue(message.hasExtension(optionalBoolExtension ));
+ Assert.assertTrue(message.hasExtension(optionalStringExtension ));
+ Assert.assertTrue(message.hasExtension(optionalBytesExtension ));
+
+ Assert.assertTrue(message.hasExtension(optionalGroupExtension ));
+ Assert.assertTrue(message.hasExtension(optionalNestedMessageExtension ));
+ Assert.assertTrue(message.hasExtension(optionalForeignMessageExtension));
+ Assert.assertTrue(message.hasExtension(optionalImportMessageExtension ));
+
+ Assert.assertTrue(message.getExtension(optionalGroupExtension ).hasA());
+ Assert.assertTrue(message.getExtension(optionalNestedMessageExtension ).hasBb());
+ Assert.assertTrue(message.getExtension(optionalForeignMessageExtension).hasC());
+ Assert.assertTrue(message.getExtension(optionalImportMessageExtension ).hasD());
+
+ Assert.assertTrue(message.hasExtension(optionalNestedEnumExtension ));
+ Assert.assertTrue(message.hasExtension(optionalForeignEnumExtension));
+ Assert.assertTrue(message.hasExtension(optionalImportEnumExtension ));
+
+ Assert.assertTrue(message.hasExtension(optionalStringPieceExtension));
+ Assert.assertTrue(message.hasExtension(optionalCordExtension));
+
+ assertEqualsExactType(101 , message.getExtension(optionalInt32Extension ));
+ assertEqualsExactType(102L , message.getExtension(optionalInt64Extension ));
+ assertEqualsExactType(103 , message.getExtension(optionalUint32Extension ));
+ assertEqualsExactType(104L , message.getExtension(optionalUint64Extension ));
+ assertEqualsExactType(105 , message.getExtension(optionalSint32Extension ));
+ assertEqualsExactType(106L , message.getExtension(optionalSint64Extension ));
+ assertEqualsExactType(107 , message.getExtension(optionalFixed32Extension ));
+ assertEqualsExactType(108L , message.getExtension(optionalFixed64Extension ));
+ assertEqualsExactType(109 , message.getExtension(optionalSfixed32Extension));
+ assertEqualsExactType(110L , message.getExtension(optionalSfixed64Extension));
+ assertEqualsExactType(111F , message.getExtension(optionalFloatExtension ));
+ assertEqualsExactType(112D , message.getExtension(optionalDoubleExtension ));
+ assertEqualsExactType(true , message.getExtension(optionalBoolExtension ));
+ assertEqualsExactType("115", message.getExtension(optionalStringExtension ));
+ assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtension));
+
+ assertEqualsExactType(117, message.getExtension(optionalGroupExtension ).getA());
+ assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtension ).getBb());
+ assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtension).getC());
+ assertEqualsExactType(120, message.getExtension(optionalImportMessageExtension ).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+ message.getExtension(optionalNestedEnumExtension));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+ message.getExtension(optionalForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+ message.getExtension(optionalImportEnumExtension));
+
+ assertEqualsExactType("124", message.getExtension(optionalStringPieceExtension));
+ assertEqualsExactType("125", message.getExtension(optionalCordExtension));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+ assertEqualsExactType(201 , message.getExtension(repeatedInt32Extension , 0));
+ assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension , 0));
+ assertEqualsExactType(203 , message.getExtension(repeatedUint32Extension , 0));
+ assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension , 0));
+ assertEqualsExactType(205 , message.getExtension(repeatedSint32Extension , 0));
+ assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension , 0));
+ assertEqualsExactType(207 , message.getExtension(repeatedFixed32Extension , 0));
+ assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+ assertEqualsExactType(209 , message.getExtension(repeatedSfixed32Extension, 0));
+ assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+ assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension , 0));
+ assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension , 0));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 0));
+ assertEqualsExactType("215", message.getExtension(repeatedStringExtension , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+ assertEqualsExactType(217, message.getExtension(repeatedGroupExtension , 0).getA());
+ assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+ assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+ assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(repeatedNestedEnumExtension, 0));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(repeatedForeignEnumExtension, 0));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(repeatedImportEnumExtension, 0));
+
+ assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+ assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+ assertEqualsExactType(301 , message.getExtension(repeatedInt32Extension , 1));
+ assertEqualsExactType(302L , message.getExtension(repeatedInt64Extension , 1));
+ assertEqualsExactType(303 , message.getExtension(repeatedUint32Extension , 1));
+ assertEqualsExactType(304L , message.getExtension(repeatedUint64Extension , 1));
+ assertEqualsExactType(305 , message.getExtension(repeatedSint32Extension , 1));
+ assertEqualsExactType(306L , message.getExtension(repeatedSint64Extension , 1));
+ assertEqualsExactType(307 , message.getExtension(repeatedFixed32Extension , 1));
+ assertEqualsExactType(308L , message.getExtension(repeatedFixed64Extension , 1));
+ assertEqualsExactType(309 , message.getExtension(repeatedSfixed32Extension, 1));
+ assertEqualsExactType(310L , message.getExtension(repeatedSfixed64Extension, 1));
+ assertEqualsExactType(311F , message.getExtension(repeatedFloatExtension , 1));
+ assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtension , 1));
+ assertEqualsExactType(false, message.getExtension(repeatedBoolExtension , 1));
+ assertEqualsExactType("315", message.getExtension(repeatedStringExtension , 1));
+ assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtension, 1));
+
+ assertEqualsExactType(317, message.getExtension(repeatedGroupExtension , 1).getA());
+ assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+ assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+ assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtension , 1).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAZ,
+ message.getExtension(repeatedNestedEnumExtension, 1));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+ message.getExtension(repeatedForeignEnumExtension, 1));
+ assertEqualsExactType(ImportEnum.IMPORT_BAZ,
+ message.getExtension(repeatedImportEnumExtension, 1));
+
+ assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtension, 1));
+ assertEqualsExactType("325", message.getExtension(repeatedCordExtension, 1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasExtension(defaultInt32Extension ));
+ Assert.assertTrue(message.hasExtension(defaultInt64Extension ));
+ Assert.assertTrue(message.hasExtension(defaultUint32Extension ));
+ Assert.assertTrue(message.hasExtension(defaultUint64Extension ));
+ Assert.assertTrue(message.hasExtension(defaultSint32Extension ));
+ Assert.assertTrue(message.hasExtension(defaultSint64Extension ));
+ Assert.assertTrue(message.hasExtension(defaultFixed32Extension ));
+ Assert.assertTrue(message.hasExtension(defaultFixed64Extension ));
+ Assert.assertTrue(message.hasExtension(defaultSfixed32Extension));
+ Assert.assertTrue(message.hasExtension(defaultSfixed64Extension));
+ Assert.assertTrue(message.hasExtension(defaultFloatExtension ));
+ Assert.assertTrue(message.hasExtension(defaultDoubleExtension ));
+ Assert.assertTrue(message.hasExtension(defaultBoolExtension ));
+ Assert.assertTrue(message.hasExtension(defaultStringExtension ));
+ Assert.assertTrue(message.hasExtension(defaultBytesExtension ));
+
+ Assert.assertTrue(message.hasExtension(defaultNestedEnumExtension ));
+ Assert.assertTrue(message.hasExtension(defaultForeignEnumExtension));
+ Assert.assertTrue(message.hasExtension(defaultImportEnumExtension ));
+
+ Assert.assertTrue(message.hasExtension(defaultStringPieceExtension));
+ Assert.assertTrue(message.hasExtension(defaultCordExtension));
+
+ assertEqualsExactType(401 , message.getExtension(defaultInt32Extension ));
+ assertEqualsExactType(402L , message.getExtension(defaultInt64Extension ));
+ assertEqualsExactType(403 , message.getExtension(defaultUint32Extension ));
+ assertEqualsExactType(404L , message.getExtension(defaultUint64Extension ));
+ assertEqualsExactType(405 , message.getExtension(defaultSint32Extension ));
+ assertEqualsExactType(406L , message.getExtension(defaultSint64Extension ));
+ assertEqualsExactType(407 , message.getExtension(defaultFixed32Extension ));
+ assertEqualsExactType(408L , message.getExtension(defaultFixed64Extension ));
+ assertEqualsExactType(409 , message.getExtension(defaultSfixed32Extension));
+ assertEqualsExactType(410L , message.getExtension(defaultSfixed64Extension));
+ assertEqualsExactType(411F , message.getExtension(defaultFloatExtension ));
+ assertEqualsExactType(412D , message.getExtension(defaultDoubleExtension ));
+ assertEqualsExactType(false, message.getExtension(defaultBoolExtension ));
+ assertEqualsExactType("415", message.getExtension(defaultStringExtension ));
+ assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtension));
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(defaultNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(defaultForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(defaultImportEnumExtension));
+
+ assertEqualsExactType("424", message.getExtension(defaultStringPieceExtension));
+ assertEqualsExactType("425", message.getExtension(defaultCordExtension));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are cleared, and that getting the extensions returns their
+ * default values.
+ */
+ public static void assertExtensionsClear(TestAllExtensions message) {
+ // hasBlah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasExtension(optionalInt32Extension ));
+ Assert.assertFalse(message.hasExtension(optionalInt64Extension ));
+ Assert.assertFalse(message.hasExtension(optionalUint32Extension ));
+ Assert.assertFalse(message.hasExtension(optionalUint64Extension ));
+ Assert.assertFalse(message.hasExtension(optionalSint32Extension ));
+ Assert.assertFalse(message.hasExtension(optionalSint64Extension ));
+ Assert.assertFalse(message.hasExtension(optionalFixed32Extension ));
+ Assert.assertFalse(message.hasExtension(optionalFixed64Extension ));
+ Assert.assertFalse(message.hasExtension(optionalSfixed32Extension));
+ Assert.assertFalse(message.hasExtension(optionalSfixed64Extension));
+ Assert.assertFalse(message.hasExtension(optionalFloatExtension ));
+ Assert.assertFalse(message.hasExtension(optionalDoubleExtension ));
+ Assert.assertFalse(message.hasExtension(optionalBoolExtension ));
+ Assert.assertFalse(message.hasExtension(optionalStringExtension ));
+ Assert.assertFalse(message.hasExtension(optionalBytesExtension ));
+
+ Assert.assertFalse(message.hasExtension(optionalGroupExtension ));
+ Assert.assertFalse(message.hasExtension(optionalNestedMessageExtension ));
+ Assert.assertFalse(message.hasExtension(optionalForeignMessageExtension));
+ Assert.assertFalse(message.hasExtension(optionalImportMessageExtension ));
+
+ Assert.assertFalse(message.hasExtension(optionalNestedEnumExtension ));
+ Assert.assertFalse(message.hasExtension(optionalForeignEnumExtension));
+ Assert.assertFalse(message.hasExtension(optionalImportEnumExtension ));
+
+ Assert.assertFalse(message.hasExtension(optionalStringPieceExtension));
+ Assert.assertFalse(message.hasExtension(optionalCordExtension));
+
+ // Optional fields without defaults are set to zero or something like it.
+ assertEqualsExactType(0 , message.getExtension(optionalInt32Extension ));
+ assertEqualsExactType(0L , message.getExtension(optionalInt64Extension ));
+ assertEqualsExactType(0 , message.getExtension(optionalUint32Extension ));
+ assertEqualsExactType(0L , message.getExtension(optionalUint64Extension ));
+ assertEqualsExactType(0 , message.getExtension(optionalSint32Extension ));
+ assertEqualsExactType(0L , message.getExtension(optionalSint64Extension ));
+ assertEqualsExactType(0 , message.getExtension(optionalFixed32Extension ));
+ assertEqualsExactType(0L , message.getExtension(optionalFixed64Extension ));
+ assertEqualsExactType(0 , message.getExtension(optionalSfixed32Extension));
+ assertEqualsExactType(0L , message.getExtension(optionalSfixed64Extension));
+ assertEqualsExactType(0F , message.getExtension(optionalFloatExtension ));
+ assertEqualsExactType(0D , message.getExtension(optionalDoubleExtension ));
+ assertEqualsExactType(false, message.getExtension(optionalBoolExtension ));
+ assertEqualsExactType("" , message.getExtension(optionalStringExtension ));
+ assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtension));
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(message.getExtension(optionalGroupExtension ).hasA());
+ Assert.assertFalse(message.getExtension(optionalNestedMessageExtension ).hasBb());
+ Assert.assertFalse(message.getExtension(optionalForeignMessageExtension).hasC());
+ Assert.assertFalse(message.getExtension(optionalImportMessageExtension ).hasD());
+
+ assertEqualsExactType(0, message.getExtension(optionalGroupExtension ).getA());
+ assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtension ).getBb());
+ assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtension).getC());
+ assertEqualsExactType(0, message.getExtension(optionalImportMessageExtension ).getD());
+
+ // Enums without defaults are set to the first value in the enum.
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(optionalNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(optionalForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(optionalImportEnumExtension));
+
+ assertEqualsExactType("", message.getExtension(optionalStringPieceExtension));
+ assertEqualsExactType("", message.getExtension(optionalCordExtension));
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getExtensionCount(repeatedInt32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedInt64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedUint32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedUint64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSint32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSint64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64Extension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32Extension));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64Extension));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtension ));
+
+ Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtension));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtension ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtension ));
+
+ Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtension));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtension));
+
+ // hasBlah() should also be false for all default fields.
+ Assert.assertFalse(message.hasExtension(defaultInt32Extension ));
+ Assert.assertFalse(message.hasExtension(defaultInt64Extension ));
+ Assert.assertFalse(message.hasExtension(defaultUint32Extension ));
+ Assert.assertFalse(message.hasExtension(defaultUint64Extension ));
+ Assert.assertFalse(message.hasExtension(defaultSint32Extension ));
+ Assert.assertFalse(message.hasExtension(defaultSint64Extension ));
+ Assert.assertFalse(message.hasExtension(defaultFixed32Extension ));
+ Assert.assertFalse(message.hasExtension(defaultFixed64Extension ));
+ Assert.assertFalse(message.hasExtension(defaultSfixed32Extension));
+ Assert.assertFalse(message.hasExtension(defaultSfixed64Extension));
+ Assert.assertFalse(message.hasExtension(defaultFloatExtension ));
+ Assert.assertFalse(message.hasExtension(defaultDoubleExtension ));
+ Assert.assertFalse(message.hasExtension(defaultBoolExtension ));
+ Assert.assertFalse(message.hasExtension(defaultStringExtension ));
+ Assert.assertFalse(message.hasExtension(defaultBytesExtension ));
+
+ Assert.assertFalse(message.hasExtension(defaultNestedEnumExtension ));
+ Assert.assertFalse(message.hasExtension(defaultForeignEnumExtension));
+ Assert.assertFalse(message.hasExtension(defaultImportEnumExtension ));
+
+ Assert.assertFalse(message.hasExtension(defaultStringPieceExtension));
+ Assert.assertFalse(message.hasExtension(defaultCordExtension));
+
+ // Fields with defaults have their default values (duh).
+ assertEqualsExactType( 41 , message.getExtension(defaultInt32Extension ));
+ assertEqualsExactType( 42L , message.getExtension(defaultInt64Extension ));
+ assertEqualsExactType( 43 , message.getExtension(defaultUint32Extension ));
+ assertEqualsExactType( 44L , message.getExtension(defaultUint64Extension ));
+ assertEqualsExactType(-45 , message.getExtension(defaultSint32Extension ));
+ assertEqualsExactType( 46L , message.getExtension(defaultSint64Extension ));
+ assertEqualsExactType( 47 , message.getExtension(defaultFixed32Extension ));
+ assertEqualsExactType( 48L , message.getExtension(defaultFixed64Extension ));
+ assertEqualsExactType( 49 , message.getExtension(defaultSfixed32Extension));
+ assertEqualsExactType(-50L , message.getExtension(defaultSfixed64Extension));
+ assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtension ));
+ assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtension ));
+ assertEqualsExactType(true , message.getExtension(defaultBoolExtension ));
+ assertEqualsExactType("hello", message.getExtension(defaultStringExtension ));
+ assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtension));
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(defaultNestedEnumExtension ));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(defaultForeignEnumExtension));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(defaultImportEnumExtension));
+
+ assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtension));
+ assertEqualsExactType("123", message.getExtension(defaultCordExtension));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}
+ * followed by {@code modifyRepeatedExtensions}.
+ */
+ public static void assertRepeatedExtensionsModified(
+ TestAllExtensions message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32Extension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64Extension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtension ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtension));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtension));
+
+ assertEqualsExactType(201 , message.getExtension(repeatedInt32Extension , 0));
+ assertEqualsExactType(202L , message.getExtension(repeatedInt64Extension , 0));
+ assertEqualsExactType(203 , message.getExtension(repeatedUint32Extension , 0));
+ assertEqualsExactType(204L , message.getExtension(repeatedUint64Extension , 0));
+ assertEqualsExactType(205 , message.getExtension(repeatedSint32Extension , 0));
+ assertEqualsExactType(206L , message.getExtension(repeatedSint64Extension , 0));
+ assertEqualsExactType(207 , message.getExtension(repeatedFixed32Extension , 0));
+ assertEqualsExactType(208L , message.getExtension(repeatedFixed64Extension , 0));
+ assertEqualsExactType(209 , message.getExtension(repeatedSfixed32Extension, 0));
+ assertEqualsExactType(210L , message.getExtension(repeatedSfixed64Extension, 0));
+ assertEqualsExactType(211F , message.getExtension(repeatedFloatExtension , 0));
+ assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtension , 0));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 0));
+ assertEqualsExactType("215", message.getExtension(repeatedStringExtension , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtension, 0));
+
+ assertEqualsExactType(217, message.getExtension(repeatedGroupExtension , 0).getA());
+ assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtension , 0).getBb());
+ assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtension, 0).getC());
+ assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtension , 0).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(repeatedNestedEnumExtension, 0));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(repeatedForeignEnumExtension, 0));
+ assertEqualsExactType(ImportEnum.IMPORT_BAR,
+ message.getExtension(repeatedImportEnumExtension, 0));
+
+ assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtension, 0));
+ assertEqualsExactType("225", message.getExtension(repeatedCordExtension, 0));
+
+ // Actually verify the second (modified) elements now.
+ assertEqualsExactType(501 , message.getExtension(repeatedInt32Extension , 1));
+ assertEqualsExactType(502L , message.getExtension(repeatedInt64Extension , 1));
+ assertEqualsExactType(503 , message.getExtension(repeatedUint32Extension , 1));
+ assertEqualsExactType(504L , message.getExtension(repeatedUint64Extension , 1));
+ assertEqualsExactType(505 , message.getExtension(repeatedSint32Extension , 1));
+ assertEqualsExactType(506L , message.getExtension(repeatedSint64Extension , 1));
+ assertEqualsExactType(507 , message.getExtension(repeatedFixed32Extension , 1));
+ assertEqualsExactType(508L , message.getExtension(repeatedFixed64Extension , 1));
+ assertEqualsExactType(509 , message.getExtension(repeatedSfixed32Extension, 1));
+ assertEqualsExactType(510L , message.getExtension(repeatedSfixed64Extension, 1));
+ assertEqualsExactType(511F , message.getExtension(repeatedFloatExtension , 1));
+ assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtension , 1));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtension , 1));
+ assertEqualsExactType("515", message.getExtension(repeatedStringExtension , 1));
+ assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtension, 1));
+
+ assertEqualsExactType(517, message.getExtension(repeatedGroupExtension , 1).getA());
+ assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtension , 1).getBb());
+ assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtension, 1).getC());
+ assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtension , 1).getD());
+
+ assertEqualsExactType(TestAllTypes.NestedEnum.FOO,
+ message.getExtension(repeatedNestedEnumExtension, 1));
+ assertEqualsExactType(ForeignEnum.FOREIGN_FOO,
+ message.getExtension(repeatedForeignEnumExtension, 1));
+ assertEqualsExactType(ImportEnum.IMPORT_FOO,
+ message.getExtension(repeatedImportEnumExtension, 1));
+
+ assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtension, 1));
+ assertEqualsExactType("525", message.getExtension(repeatedCordExtension, 1));
+ }
+
+ public static void setPackedExtensions(TestPackedExtensions.Builder message) {
+ message.addExtension(packedInt32Extension , 601);
+ message.addExtension(packedInt64Extension , 602L);
+ message.addExtension(packedUint32Extension , 603);
+ message.addExtension(packedUint64Extension , 604L);
+ message.addExtension(packedSint32Extension , 605);
+ message.addExtension(packedSint64Extension , 606L);
+ message.addExtension(packedFixed32Extension , 607);
+ message.addExtension(packedFixed64Extension , 608L);
+ message.addExtension(packedSfixed32Extension, 609);
+ message.addExtension(packedSfixed64Extension, 610L);
+ message.addExtension(packedFloatExtension , 611F);
+ message.addExtension(packedDoubleExtension , 612D);
+ message.addExtension(packedBoolExtension , true);
+ message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAR);
+ // Add a second one of each field.
+ message.addExtension(packedInt32Extension , 701);
+ message.addExtension(packedInt64Extension , 702L);
+ message.addExtension(packedUint32Extension , 703);
+ message.addExtension(packedUint64Extension , 704L);
+ message.addExtension(packedSint32Extension , 705);
+ message.addExtension(packedSint64Extension , 706L);
+ message.addExtension(packedFixed32Extension , 707);
+ message.addExtension(packedFixed64Extension , 708L);
+ message.addExtension(packedSfixed32Extension, 709);
+ message.addExtension(packedSfixed64Extension, 710L);
+ message.addExtension(packedFloatExtension , 711F);
+ message.addExtension(packedDoubleExtension , 712D);
+ message.addExtension(packedBoolExtension , false);
+ message.addExtension(packedEnumExtension, ForeignEnum.FOREIGN_BAZ);
+ }
+
+ public static void assertPackedExtensionsSet(TestPackedExtensions message) {
+ Assert.assertEquals(2, message.getExtensionCount(packedInt32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedInt64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedUint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedUint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSint32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSint64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedFixed32Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedFixed64Extension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSfixed32Extension));
+ Assert.assertEquals(2, message.getExtensionCount(packedSfixed64Extension));
+ Assert.assertEquals(2, message.getExtensionCount(packedFloatExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedBoolExtension ));
+ Assert.assertEquals(2, message.getExtensionCount(packedEnumExtension));
+ assertEqualsExactType(601 , message.getExtension(packedInt32Extension , 0));
+ assertEqualsExactType(602L , message.getExtension(packedInt64Extension , 0));
+ assertEqualsExactType(603 , message.getExtension(packedUint32Extension , 0));
+ assertEqualsExactType(604L , message.getExtension(packedUint64Extension , 0));
+ assertEqualsExactType(605 , message.getExtension(packedSint32Extension , 0));
+ assertEqualsExactType(606L , message.getExtension(packedSint64Extension , 0));
+ assertEqualsExactType(607 , message.getExtension(packedFixed32Extension , 0));
+ assertEqualsExactType(608L , message.getExtension(packedFixed64Extension , 0));
+ assertEqualsExactType(609 , message.getExtension(packedSfixed32Extension, 0));
+ assertEqualsExactType(610L , message.getExtension(packedSfixed64Extension, 0));
+ assertEqualsExactType(611F , message.getExtension(packedFloatExtension , 0));
+ assertEqualsExactType(612D , message.getExtension(packedDoubleExtension , 0));
+ assertEqualsExactType(true , message.getExtension(packedBoolExtension , 0));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAR,
+ message.getExtension(packedEnumExtension, 0));
+ assertEqualsExactType(701 , message.getExtension(packedInt32Extension , 1));
+ assertEqualsExactType(702L , message.getExtension(packedInt64Extension , 1));
+ assertEqualsExactType(703 , message.getExtension(packedUint32Extension , 1));
+ assertEqualsExactType(704L , message.getExtension(packedUint64Extension , 1));
+ assertEqualsExactType(705 , message.getExtension(packedSint32Extension , 1));
+ assertEqualsExactType(706L , message.getExtension(packedSint64Extension , 1));
+ assertEqualsExactType(707 , message.getExtension(packedFixed32Extension , 1));
+ assertEqualsExactType(708L , message.getExtension(packedFixed64Extension , 1));
+ assertEqualsExactType(709 , message.getExtension(packedSfixed32Extension, 1));
+ assertEqualsExactType(710L , message.getExtension(packedSfixed64Extension, 1));
+ assertEqualsExactType(711F , message.getExtension(packedFloatExtension , 1));
+ assertEqualsExactType(712D , message.getExtension(packedDoubleExtension , 1));
+ assertEqualsExactType(false, message.getExtension(packedBoolExtension , 1));
+ assertEqualsExactType(ForeignEnum.FOREIGN_BAZ,
+ message.getExtension(packedEnumExtension, 1));
+ }
+
+ // ===================================================================
+ // Lite extensions
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllExtensionsSet()}.
+ */
+ public static void setAllExtensions(TestAllExtensionsLite.Builder message) {
+ message.setExtension(optionalInt32ExtensionLite , 101);
+ message.setExtension(optionalInt64ExtensionLite , 102L);
+ message.setExtension(optionalUint32ExtensionLite , 103);
+ message.setExtension(optionalUint64ExtensionLite , 104L);
+ message.setExtension(optionalSint32ExtensionLite , 105);
+ message.setExtension(optionalSint64ExtensionLite , 106L);
+ message.setExtension(optionalFixed32ExtensionLite , 107);
+ message.setExtension(optionalFixed64ExtensionLite , 108L);
+ message.setExtension(optionalSfixed32ExtensionLite, 109);
+ message.setExtension(optionalSfixed64ExtensionLite, 110L);
+ message.setExtension(optionalFloatExtensionLite , 111F);
+ message.setExtension(optionalDoubleExtensionLite , 112D);
+ message.setExtension(optionalBoolExtensionLite , true);
+ message.setExtension(optionalStringExtensionLite , "115");
+ message.setExtension(optionalBytesExtensionLite , toBytes("116"));
+
+ message.setExtension(optionalGroupExtensionLite,
+ OptionalGroup_extension_lite.newBuilder().setA(117).build());
+ message.setExtension(optionalNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(118).build());
+ message.setExtension(optionalForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(119).build());
+ message.setExtension(optionalImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(120).build());
+
+ message.setExtension(optionalNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+ message.setExtension(optionalForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ message.setExtension(optionalImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+ message.setExtension(optionalStringPieceExtensionLite, "124");
+ message.setExtension(optionalCordExtensionLite, "125");
+
+ // -----------------------------------------------------------------
+
+ message.addExtension(repeatedInt32ExtensionLite , 201);
+ message.addExtension(repeatedInt64ExtensionLite , 202L);
+ message.addExtension(repeatedUint32ExtensionLite , 203);
+ message.addExtension(repeatedUint64ExtensionLite , 204L);
+ message.addExtension(repeatedSint32ExtensionLite , 205);
+ message.addExtension(repeatedSint64ExtensionLite , 206L);
+ message.addExtension(repeatedFixed32ExtensionLite , 207);
+ message.addExtension(repeatedFixed64ExtensionLite , 208L);
+ message.addExtension(repeatedSfixed32ExtensionLite, 209);
+ message.addExtension(repeatedSfixed64ExtensionLite, 210L);
+ message.addExtension(repeatedFloatExtensionLite , 211F);
+ message.addExtension(repeatedDoubleExtensionLite , 212D);
+ message.addExtension(repeatedBoolExtensionLite , true);
+ message.addExtension(repeatedStringExtensionLite , "215");
+ message.addExtension(repeatedBytesExtensionLite , toBytes("216"));
+
+ message.addExtension(repeatedGroupExtensionLite,
+ RepeatedGroup_extension_lite.newBuilder().setA(217).build());
+ message.addExtension(repeatedNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(218).build());
+ message.addExtension(repeatedForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(219).build());
+ message.addExtension(repeatedImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(220).build());
+
+ message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAR);
+ message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+ message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAR);
+
+ message.addExtension(repeatedStringPieceExtensionLite, "224");
+ message.addExtension(repeatedCordExtensionLite, "225");
+
+ // Add a second one of each field.
+ message.addExtension(repeatedInt32ExtensionLite , 301);
+ message.addExtension(repeatedInt64ExtensionLite , 302L);
+ message.addExtension(repeatedUint32ExtensionLite , 303);
+ message.addExtension(repeatedUint64ExtensionLite , 304L);
+ message.addExtension(repeatedSint32ExtensionLite , 305);
+ message.addExtension(repeatedSint64ExtensionLite , 306L);
+ message.addExtension(repeatedFixed32ExtensionLite , 307);
+ message.addExtension(repeatedFixed64ExtensionLite , 308L);
+ message.addExtension(repeatedSfixed32ExtensionLite, 309);
+ message.addExtension(repeatedSfixed64ExtensionLite, 310L);
+ message.addExtension(repeatedFloatExtensionLite , 311F);
+ message.addExtension(repeatedDoubleExtensionLite , 312D);
+ message.addExtension(repeatedBoolExtensionLite , false);
+ message.addExtension(repeatedStringExtensionLite , "315");
+ message.addExtension(repeatedBytesExtensionLite , toBytes("316"));
+
+ message.addExtension(repeatedGroupExtensionLite,
+ RepeatedGroup_extension_lite.newBuilder().setA(317).build());
+ message.addExtension(repeatedNestedMessageExtensionLite,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(318).build());
+ message.addExtension(repeatedForeignMessageExtensionLite,
+ ForeignMessageLite.newBuilder().setC(319).build());
+ message.addExtension(repeatedImportMessageExtensionLite,
+ ImportMessageLite.newBuilder().setD(320).build());
+
+ message.addExtension(repeatedNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.BAZ);
+ message.addExtension(repeatedForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ message.addExtension(repeatedImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_BAZ);
+
+ message.addExtension(repeatedStringPieceExtensionLite, "324");
+ message.addExtension(repeatedCordExtensionLite, "325");
+
+ // -----------------------------------------------------------------
+
+ message.setExtension(defaultInt32ExtensionLite , 401);
+ message.setExtension(defaultInt64ExtensionLite , 402L);
+ message.setExtension(defaultUint32ExtensionLite , 403);
+ message.setExtension(defaultUint64ExtensionLite , 404L);
+ message.setExtension(defaultSint32ExtensionLite , 405);
+ message.setExtension(defaultSint64ExtensionLite , 406L);
+ message.setExtension(defaultFixed32ExtensionLite , 407);
+ message.setExtension(defaultFixed64ExtensionLite , 408L);
+ message.setExtension(defaultSfixed32ExtensionLite, 409);
+ message.setExtension(defaultSfixed64ExtensionLite, 410L);
+ message.setExtension(defaultFloatExtensionLite , 411F);
+ message.setExtension(defaultDoubleExtensionLite , 412D);
+ message.setExtension(defaultBoolExtensionLite , false);
+ message.setExtension(defaultStringExtensionLite , "415");
+ message.setExtension(defaultBytesExtensionLite , toBytes("416"));
+
+ message.setExtension(defaultNestedEnumExtensionLite, TestAllTypesLite.NestedEnum.FOO);
+ message.setExtension(defaultForeignEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_FOO);
+ message.setExtension(defaultImportEnumExtensionLite, ImportEnumLite.IMPORT_LITE_FOO);
+
+ message.setExtension(defaultStringPieceExtensionLite, "424");
+ message.setExtension(defaultCordExtensionLite, "425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated extensions of {@code message} to contain the values
+ * expected by {@code assertRepeatedExtensionsModified()}.
+ */
+ public static void modifyRepeatedExtensions(
+ TestAllExtensionsLite.Builder message) {
+ message.setExtension(repeatedInt32ExtensionLite , 1, 501);
+ message.setExtension(repeatedInt64ExtensionLite , 1, 502L);
+ message.setExtension(repeatedUint32ExtensionLite , 1, 503);
+ message.setExtension(repeatedUint64ExtensionLite , 1, 504L);
+ message.setExtension(repeatedSint32ExtensionLite , 1, 505);
+ message.setExtension(repeatedSint64ExtensionLite , 1, 506L);
+ message.setExtension(repeatedFixed32ExtensionLite , 1, 507);
+ message.setExtension(repeatedFixed64ExtensionLite , 1, 508L);
+ message.setExtension(repeatedSfixed32ExtensionLite, 1, 509);
+ message.setExtension(repeatedSfixed64ExtensionLite, 1, 510L);
+ message.setExtension(repeatedFloatExtensionLite , 1, 511F);
+ message.setExtension(repeatedDoubleExtensionLite , 1, 512D);
+ message.setExtension(repeatedBoolExtensionLite , 1, true);
+ message.setExtension(repeatedStringExtensionLite , 1, "515");
+ message.setExtension(repeatedBytesExtensionLite , 1, toBytes("516"));
+
+ message.setExtension(repeatedGroupExtensionLite, 1,
+ RepeatedGroup_extension_lite.newBuilder().setA(517).build());
+ message.setExtension(repeatedNestedMessageExtensionLite, 1,
+ TestAllTypesLite.NestedMessage.newBuilder().setBb(518).build());
+ message.setExtension(repeatedForeignMessageExtensionLite, 1,
+ ForeignMessageLite.newBuilder().setC(519).build());
+ message.setExtension(repeatedImportMessageExtensionLite, 1,
+ ImportMessageLite.newBuilder().setD(520).build());
+
+ message.setExtension(repeatedNestedEnumExtensionLite , 1, TestAllTypesLite.NestedEnum.FOO);
+ message.setExtension(repeatedForeignEnumExtensionLite, 1, ForeignEnumLite.FOREIGN_LITE_FOO);
+ message.setExtension(repeatedImportEnumExtensionLite , 1, ImportEnumLite.IMPORT_LITE_FOO);
+
+ message.setExtension(repeatedStringPieceExtensionLite, 1, "524");
+ message.setExtension(repeatedCordExtensionLite, 1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}.
+ */
+ public static void assertAllExtensionsSet(TestAllExtensionsLite message) {
+ Assert.assertTrue(message.hasExtension(optionalInt32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalInt64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalUint32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalUint64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalSint32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalSint64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalFixed32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalFixed64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalSfixed32ExtensionLite));
+ Assert.assertTrue(message.hasExtension(optionalSfixed64ExtensionLite));
+ Assert.assertTrue(message.hasExtension(optionalFloatExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalDoubleExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalBoolExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalStringExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalBytesExtensionLite ));
+
+ Assert.assertTrue(message.hasExtension(optionalGroupExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalNestedMessageExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalForeignMessageExtensionLite));
+ Assert.assertTrue(message.hasExtension(optionalImportMessageExtensionLite ));
+
+ Assert.assertTrue(message.getExtension(optionalGroupExtensionLite ).hasA());
+ Assert.assertTrue(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+ Assert.assertTrue(message.getExtension(optionalForeignMessageExtensionLite).hasC());
+ Assert.assertTrue(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+
+ Assert.assertTrue(message.hasExtension(optionalNestedEnumExtensionLite ));
+ Assert.assertTrue(message.hasExtension(optionalForeignEnumExtensionLite));
+ Assert.assertTrue(message.hasExtension(optionalImportEnumExtensionLite ));
+
+ Assert.assertTrue(message.hasExtension(optionalStringPieceExtensionLite));
+ Assert.assertTrue(message.hasExtension(optionalCordExtensionLite));
+
+ assertEqualsExactType(101 , message.getExtension(optionalInt32ExtensionLite ));
+ assertEqualsExactType(102L , message.getExtension(optionalInt64ExtensionLite ));
+ assertEqualsExactType(103 , message.getExtension(optionalUint32ExtensionLite ));
+ assertEqualsExactType(104L , message.getExtension(optionalUint64ExtensionLite ));
+ assertEqualsExactType(105 , message.getExtension(optionalSint32ExtensionLite ));
+ assertEqualsExactType(106L , message.getExtension(optionalSint64ExtensionLite ));
+ assertEqualsExactType(107 , message.getExtension(optionalFixed32ExtensionLite ));
+ assertEqualsExactType(108L , message.getExtension(optionalFixed64ExtensionLite ));
+ assertEqualsExactType(109 , message.getExtension(optionalSfixed32ExtensionLite));
+ assertEqualsExactType(110L , message.getExtension(optionalSfixed64ExtensionLite));
+ assertEqualsExactType(111F , message.getExtension(optionalFloatExtensionLite ));
+ assertEqualsExactType(112D , message.getExtension(optionalDoubleExtensionLite ));
+ assertEqualsExactType(true , message.getExtension(optionalBoolExtensionLite ));
+ assertEqualsExactType("115", message.getExtension(optionalStringExtensionLite ));
+ assertEqualsExactType(toBytes("116"), message.getExtension(optionalBytesExtensionLite));
+
+ assertEqualsExactType(117, message.getExtension(optionalGroupExtensionLite ).getA());
+ assertEqualsExactType(118, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+ assertEqualsExactType(119, message.getExtension(optionalForeignMessageExtensionLite).getC());
+ assertEqualsExactType(120, message.getExtension(optionalImportMessageExtensionLite ).getD());
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+ message.getExtension(optionalNestedEnumExtensionLite));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+ message.getExtension(optionalForeignEnumExtensionLite));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+ message.getExtension(optionalImportEnumExtensionLite));
+
+ assertEqualsExactType("124", message.getExtension(optionalStringPieceExtensionLite));
+ assertEqualsExactType("125", message.getExtension(optionalCordExtensionLite));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+ assertEqualsExactType(201 , message.getExtension(repeatedInt32ExtensionLite , 0));
+ assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite , 0));
+ assertEqualsExactType(203 , message.getExtension(repeatedUint32ExtensionLite , 0));
+ assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite , 0));
+ assertEqualsExactType(205 , message.getExtension(repeatedSint32ExtensionLite , 0));
+ assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite , 0));
+ assertEqualsExactType(207 , message.getExtension(repeatedFixed32ExtensionLite , 0));
+ assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+ assertEqualsExactType(209 , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+ assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+ assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite , 0));
+ assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite , 0));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite , 0));
+ assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+ assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite ,0).getA());
+ assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+ assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+ assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+ message.getExtension(repeatedNestedEnumExtensionLite, 0));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+ message.getExtension(repeatedForeignEnumExtensionLite, 0));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+ message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+ assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+ assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+ assertEqualsExactType(301 , message.getExtension(repeatedInt32ExtensionLite , 1));
+ assertEqualsExactType(302L , message.getExtension(repeatedInt64ExtensionLite , 1));
+ assertEqualsExactType(303 , message.getExtension(repeatedUint32ExtensionLite , 1));
+ assertEqualsExactType(304L , message.getExtension(repeatedUint64ExtensionLite , 1));
+ assertEqualsExactType(305 , message.getExtension(repeatedSint32ExtensionLite , 1));
+ assertEqualsExactType(306L , message.getExtension(repeatedSint64ExtensionLite , 1));
+ assertEqualsExactType(307 , message.getExtension(repeatedFixed32ExtensionLite , 1));
+ assertEqualsExactType(308L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+ assertEqualsExactType(309 , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+ assertEqualsExactType(310L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+ assertEqualsExactType(311F , message.getExtension(repeatedFloatExtensionLite , 1));
+ assertEqualsExactType(312D , message.getExtension(repeatedDoubleExtensionLite , 1));
+ assertEqualsExactType(false, message.getExtension(repeatedBoolExtensionLite , 1));
+ assertEqualsExactType("315", message.getExtension(repeatedStringExtensionLite , 1));
+ assertEqualsExactType(toBytes("316"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+ assertEqualsExactType(317, message.getExtension(repeatedGroupExtensionLite ,1).getA());
+ assertEqualsExactType(318, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+ assertEqualsExactType(319, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+ assertEqualsExactType(320, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.BAZ,
+ message.getExtension(repeatedNestedEnumExtensionLite, 1));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+ message.getExtension(repeatedForeignEnumExtensionLite, 1));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAZ,
+ message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+ assertEqualsExactType("324", message.getExtension(repeatedStringPieceExtensionLite, 1));
+ assertEqualsExactType("325", message.getExtension(repeatedCordExtensionLite, 1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasExtension(defaultInt32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultInt64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultUint32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultUint64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultSint32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultSint64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultFixed32ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultFixed64ExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultSfixed32ExtensionLite));
+ Assert.assertTrue(message.hasExtension(defaultSfixed64ExtensionLite));
+ Assert.assertTrue(message.hasExtension(defaultFloatExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultDoubleExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultBoolExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultStringExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultBytesExtensionLite ));
+
+ Assert.assertTrue(message.hasExtension(defaultNestedEnumExtensionLite ));
+ Assert.assertTrue(message.hasExtension(defaultForeignEnumExtensionLite));
+ Assert.assertTrue(message.hasExtension(defaultImportEnumExtensionLite ));
+
+ Assert.assertTrue(message.hasExtension(defaultStringPieceExtensionLite));
+ Assert.assertTrue(message.hasExtension(defaultCordExtensionLite));
+
+ assertEqualsExactType(401 , message.getExtension(defaultInt32ExtensionLite ));
+ assertEqualsExactType(402L , message.getExtension(defaultInt64ExtensionLite ));
+ assertEqualsExactType(403 , message.getExtension(defaultUint32ExtensionLite ));
+ assertEqualsExactType(404L , message.getExtension(defaultUint64ExtensionLite ));
+ assertEqualsExactType(405 , message.getExtension(defaultSint32ExtensionLite ));
+ assertEqualsExactType(406L , message.getExtension(defaultSint64ExtensionLite ));
+ assertEqualsExactType(407 , message.getExtension(defaultFixed32ExtensionLite ));
+ assertEqualsExactType(408L , message.getExtension(defaultFixed64ExtensionLite ));
+ assertEqualsExactType(409 , message.getExtension(defaultSfixed32ExtensionLite));
+ assertEqualsExactType(410L , message.getExtension(defaultSfixed64ExtensionLite));
+ assertEqualsExactType(411F , message.getExtension(defaultFloatExtensionLite ));
+ assertEqualsExactType(412D , message.getExtension(defaultDoubleExtensionLite ));
+ assertEqualsExactType(false, message.getExtension(defaultBoolExtensionLite ));
+ assertEqualsExactType("415", message.getExtension(defaultStringExtensionLite ));
+ assertEqualsExactType(toBytes("416"), message.getExtension(defaultBytesExtensionLite));
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+ message.getExtension(defaultNestedEnumExtensionLite ));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+ message.getExtension(defaultForeignEnumExtensionLite));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+ message.getExtension(defaultImportEnumExtensionLite));
+
+ assertEqualsExactType("424", message.getExtension(defaultStringPieceExtensionLite));
+ assertEqualsExactType("425", message.getExtension(defaultCordExtensionLite));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are cleared, and that getting the extensions returns their
+ * default values.
+ */
+ public static void assertExtensionsClear(TestAllExtensionsLite message) {
+ // hasBlah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasExtension(optionalInt32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalInt64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalUint32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalUint64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalSint32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalSint64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalFixed32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalFixed64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalSfixed32ExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalSfixed64ExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalFloatExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalDoubleExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalBoolExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalStringExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalBytesExtensionLite ));
+
+ Assert.assertFalse(message.hasExtension(optionalGroupExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalNestedMessageExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalForeignMessageExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalImportMessageExtensionLite ));
+
+ Assert.assertFalse(message.hasExtension(optionalNestedEnumExtensionLite ));
+ Assert.assertFalse(message.hasExtension(optionalForeignEnumExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalImportEnumExtensionLite ));
+
+ Assert.assertFalse(message.hasExtension(optionalStringPieceExtensionLite));
+ Assert.assertFalse(message.hasExtension(optionalCordExtensionLite));
+
+ // Optional fields without defaults are set to zero or something like it.
+ assertEqualsExactType(0 , message.getExtension(optionalInt32ExtensionLite ));
+ assertEqualsExactType(0L , message.getExtension(optionalInt64ExtensionLite ));
+ assertEqualsExactType(0 , message.getExtension(optionalUint32ExtensionLite ));
+ assertEqualsExactType(0L , message.getExtension(optionalUint64ExtensionLite ));
+ assertEqualsExactType(0 , message.getExtension(optionalSint32ExtensionLite ));
+ assertEqualsExactType(0L , message.getExtension(optionalSint64ExtensionLite ));
+ assertEqualsExactType(0 , message.getExtension(optionalFixed32ExtensionLite ));
+ assertEqualsExactType(0L , message.getExtension(optionalFixed64ExtensionLite ));
+ assertEqualsExactType(0 , message.getExtension(optionalSfixed32ExtensionLite));
+ assertEqualsExactType(0L , message.getExtension(optionalSfixed64ExtensionLite));
+ assertEqualsExactType(0F , message.getExtension(optionalFloatExtensionLite ));
+ assertEqualsExactType(0D , message.getExtension(optionalDoubleExtensionLite ));
+ assertEqualsExactType(false, message.getExtension(optionalBoolExtensionLite ));
+ assertEqualsExactType("" , message.getExtension(optionalStringExtensionLite ));
+ assertEqualsExactType(ByteString.EMPTY, message.getExtension(optionalBytesExtensionLite));
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(message.getExtension(optionalGroupExtensionLite ).hasA());
+ Assert.assertFalse(message.getExtension(optionalNestedMessageExtensionLite ).hasBb());
+ Assert.assertFalse(message.getExtension(optionalForeignMessageExtensionLite).hasC());
+ Assert.assertFalse(message.getExtension(optionalImportMessageExtensionLite ).hasD());
+
+ assertEqualsExactType(0, message.getExtension(optionalGroupExtensionLite ).getA());
+ assertEqualsExactType(0, message.getExtension(optionalNestedMessageExtensionLite ).getBb());
+ assertEqualsExactType(0, message.getExtension(optionalForeignMessageExtensionLite).getC());
+ assertEqualsExactType(0, message.getExtension(optionalImportMessageExtensionLite ).getD());
+
+ // Enums without defaults are set to the first value in the enum.
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+ message.getExtension(optionalNestedEnumExtensionLite ));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+ message.getExtension(optionalForeignEnumExtensionLite));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+ message.getExtension(optionalImportEnumExtensionLite));
+
+ assertEqualsExactType("", message.getExtension(optionalStringPieceExtensionLite));
+ assertEqualsExactType("", message.getExtension(optionalCordExtensionLite));
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getExtensionCount(repeatedInt32ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedInt64ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedUint32ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedUint64ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSint32ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSint64ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedFloatExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedDoubleExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedBoolExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedStringExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedBytesExtensionLite ));
+
+ Assert.assertEquals(0, message.getExtensionCount(repeatedGroupExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedImportEnumExtensionLite ));
+
+ Assert.assertEquals(0, message.getExtensionCount(repeatedStringPieceExtensionLite));
+ Assert.assertEquals(0, message.getExtensionCount(repeatedCordExtensionLite));
+
+ // hasBlah() should also be false for all default fields.
+ Assert.assertFalse(message.hasExtension(defaultInt32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultInt64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultUint32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultUint64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultSint32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultSint64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultFixed32ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultFixed64ExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultSfixed32ExtensionLite));
+ Assert.assertFalse(message.hasExtension(defaultSfixed64ExtensionLite));
+ Assert.assertFalse(message.hasExtension(defaultFloatExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultDoubleExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultBoolExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultStringExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultBytesExtensionLite ));
+
+ Assert.assertFalse(message.hasExtension(defaultNestedEnumExtensionLite ));
+ Assert.assertFalse(message.hasExtension(defaultForeignEnumExtensionLite));
+ Assert.assertFalse(message.hasExtension(defaultImportEnumExtensionLite ));
+
+ Assert.assertFalse(message.hasExtension(defaultStringPieceExtensionLite));
+ Assert.assertFalse(message.hasExtension(defaultCordExtensionLite));
+
+ // Fields with defaults have their default values (duh).
+ assertEqualsExactType( 41 , message.getExtension(defaultInt32ExtensionLite ));
+ assertEqualsExactType( 42L , message.getExtension(defaultInt64ExtensionLite ));
+ assertEqualsExactType( 43 , message.getExtension(defaultUint32ExtensionLite ));
+ assertEqualsExactType( 44L , message.getExtension(defaultUint64ExtensionLite ));
+ assertEqualsExactType(-45 , message.getExtension(defaultSint32ExtensionLite ));
+ assertEqualsExactType( 46L , message.getExtension(defaultSint64ExtensionLite ));
+ assertEqualsExactType( 47 , message.getExtension(defaultFixed32ExtensionLite ));
+ assertEqualsExactType( 48L , message.getExtension(defaultFixed64ExtensionLite ));
+ assertEqualsExactType( 49 , message.getExtension(defaultSfixed32ExtensionLite));
+ assertEqualsExactType(-50L , message.getExtension(defaultSfixed64ExtensionLite));
+ assertEqualsExactType( 51.5F , message.getExtension(defaultFloatExtensionLite ));
+ assertEqualsExactType( 52e3D , message.getExtension(defaultDoubleExtensionLite ));
+ assertEqualsExactType(true , message.getExtension(defaultBoolExtensionLite ));
+ assertEqualsExactType("hello", message.getExtension(defaultStringExtensionLite ));
+ assertEqualsExactType(toBytes("world"), message.getExtension(defaultBytesExtensionLite));
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+ message.getExtension(defaultNestedEnumExtensionLite ));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+ message.getExtension(defaultForeignEnumExtensionLite));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+ message.getExtension(defaultImportEnumExtensionLite));
+
+ assertEqualsExactType("abc", message.getExtension(defaultStringPieceExtensionLite));
+ assertEqualsExactType("123", message.getExtension(defaultCordExtensionLite));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all extensions of
+ * {@code message} are set to the values assigned by {@code setAllExtensions}
+ * followed by {@code modifyRepeatedExtensions}.
+ */
+ public static void assertRepeatedExtensionsModified(
+ TestAllExtensionsLite message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedInt64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedUint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFixed64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed32ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedSfixed64ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedFloatExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedDoubleExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBoolExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedBytesExtensionLite ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedGroupExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignMessageExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportMessageExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedNestedEnumExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedForeignEnumExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedImportEnumExtensionLite ));
+
+ Assert.assertEquals(2, message.getExtensionCount(repeatedStringPieceExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(repeatedCordExtensionLite));
+
+ assertEqualsExactType(201 , message.getExtension(repeatedInt32ExtensionLite , 0));
+ assertEqualsExactType(202L , message.getExtension(repeatedInt64ExtensionLite , 0));
+ assertEqualsExactType(203 , message.getExtension(repeatedUint32ExtensionLite , 0));
+ assertEqualsExactType(204L , message.getExtension(repeatedUint64ExtensionLite , 0));
+ assertEqualsExactType(205 , message.getExtension(repeatedSint32ExtensionLite , 0));
+ assertEqualsExactType(206L , message.getExtension(repeatedSint64ExtensionLite , 0));
+ assertEqualsExactType(207 , message.getExtension(repeatedFixed32ExtensionLite , 0));
+ assertEqualsExactType(208L , message.getExtension(repeatedFixed64ExtensionLite , 0));
+ assertEqualsExactType(209 , message.getExtension(repeatedSfixed32ExtensionLite, 0));
+ assertEqualsExactType(210L , message.getExtension(repeatedSfixed64ExtensionLite, 0));
+ assertEqualsExactType(211F , message.getExtension(repeatedFloatExtensionLite , 0));
+ assertEqualsExactType(212D , message.getExtension(repeatedDoubleExtensionLite , 0));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite , 0));
+ assertEqualsExactType("215", message.getExtension(repeatedStringExtensionLite , 0));
+ assertEqualsExactType(toBytes("216"), message.getExtension(repeatedBytesExtensionLite, 0));
+
+ assertEqualsExactType(217, message.getExtension(repeatedGroupExtensionLite ,0).getA());
+ assertEqualsExactType(218, message.getExtension(repeatedNestedMessageExtensionLite ,0).getBb());
+ assertEqualsExactType(219, message.getExtension(repeatedForeignMessageExtensionLite,0).getC());
+ assertEqualsExactType(220, message.getExtension(repeatedImportMessageExtensionLite ,0).getD());
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.BAR,
+ message.getExtension(repeatedNestedEnumExtensionLite, 0));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+ message.getExtension(repeatedForeignEnumExtensionLite, 0));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_BAR,
+ message.getExtension(repeatedImportEnumExtensionLite, 0));
+
+ assertEqualsExactType("224", message.getExtension(repeatedStringPieceExtensionLite, 0));
+ assertEqualsExactType("225", message.getExtension(repeatedCordExtensionLite, 0));
+
+ // Actually verify the second (modified) elements now.
+ assertEqualsExactType(501 , message.getExtension(repeatedInt32ExtensionLite , 1));
+ assertEqualsExactType(502L , message.getExtension(repeatedInt64ExtensionLite , 1));
+ assertEqualsExactType(503 , message.getExtension(repeatedUint32ExtensionLite , 1));
+ assertEqualsExactType(504L , message.getExtension(repeatedUint64ExtensionLite , 1));
+ assertEqualsExactType(505 , message.getExtension(repeatedSint32ExtensionLite , 1));
+ assertEqualsExactType(506L , message.getExtension(repeatedSint64ExtensionLite , 1));
+ assertEqualsExactType(507 , message.getExtension(repeatedFixed32ExtensionLite , 1));
+ assertEqualsExactType(508L , message.getExtension(repeatedFixed64ExtensionLite , 1));
+ assertEqualsExactType(509 , message.getExtension(repeatedSfixed32ExtensionLite, 1));
+ assertEqualsExactType(510L , message.getExtension(repeatedSfixed64ExtensionLite, 1));
+ assertEqualsExactType(511F , message.getExtension(repeatedFloatExtensionLite , 1));
+ assertEqualsExactType(512D , message.getExtension(repeatedDoubleExtensionLite , 1));
+ assertEqualsExactType(true , message.getExtension(repeatedBoolExtensionLite , 1));
+ assertEqualsExactType("515", message.getExtension(repeatedStringExtensionLite , 1));
+ assertEqualsExactType(toBytes("516"), message.getExtension(repeatedBytesExtensionLite, 1));
+
+ assertEqualsExactType(517, message.getExtension(repeatedGroupExtensionLite ,1).getA());
+ assertEqualsExactType(518, message.getExtension(repeatedNestedMessageExtensionLite ,1).getBb());
+ assertEqualsExactType(519, message.getExtension(repeatedForeignMessageExtensionLite,1).getC());
+ assertEqualsExactType(520, message.getExtension(repeatedImportMessageExtensionLite ,1).getD());
+
+ assertEqualsExactType(TestAllTypesLite.NestedEnum.FOO,
+ message.getExtension(repeatedNestedEnumExtensionLite, 1));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_FOO,
+ message.getExtension(repeatedForeignEnumExtensionLite, 1));
+ assertEqualsExactType(ImportEnumLite.IMPORT_LITE_FOO,
+ message.getExtension(repeatedImportEnumExtensionLite, 1));
+
+ assertEqualsExactType("524", message.getExtension(repeatedStringPieceExtensionLite, 1));
+ assertEqualsExactType("525", message.getExtension(repeatedCordExtensionLite, 1));
+ }
+
+ public static void setPackedExtensions(TestPackedExtensionsLite.Builder message) {
+ message.addExtension(packedInt32ExtensionLite , 601);
+ message.addExtension(packedInt64ExtensionLite , 602L);
+ message.addExtension(packedUint32ExtensionLite , 603);
+ message.addExtension(packedUint64ExtensionLite , 604L);
+ message.addExtension(packedSint32ExtensionLite , 605);
+ message.addExtension(packedSint64ExtensionLite , 606L);
+ message.addExtension(packedFixed32ExtensionLite , 607);
+ message.addExtension(packedFixed64ExtensionLite , 608L);
+ message.addExtension(packedSfixed32ExtensionLite, 609);
+ message.addExtension(packedSfixed64ExtensionLite, 610L);
+ message.addExtension(packedFloatExtensionLite , 611F);
+ message.addExtension(packedDoubleExtensionLite , 612D);
+ message.addExtension(packedBoolExtensionLite , true);
+ message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAR);
+ // Add a second one of each field.
+ message.addExtension(packedInt32ExtensionLite , 701);
+ message.addExtension(packedInt64ExtensionLite , 702L);
+ message.addExtension(packedUint32ExtensionLite , 703);
+ message.addExtension(packedUint64ExtensionLite , 704L);
+ message.addExtension(packedSint32ExtensionLite , 705);
+ message.addExtension(packedSint64ExtensionLite , 706L);
+ message.addExtension(packedFixed32ExtensionLite , 707);
+ message.addExtension(packedFixed64ExtensionLite , 708L);
+ message.addExtension(packedSfixed32ExtensionLite, 709);
+ message.addExtension(packedSfixed64ExtensionLite, 710L);
+ message.addExtension(packedFloatExtensionLite , 711F);
+ message.addExtension(packedDoubleExtensionLite , 712D);
+ message.addExtension(packedBoolExtensionLite , false);
+ message.addExtension(packedEnumExtensionLite, ForeignEnumLite.FOREIGN_LITE_BAZ);
+ }
+
+ public static void assertPackedExtensionsSet(TestPackedExtensionsLite message) {
+ Assert.assertEquals(2, message.getExtensionCount(packedInt32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedInt64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedUint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedUint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSint32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSint64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedFixed32ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedFixed64ExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedSfixed32ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(packedSfixed64ExtensionLite));
+ Assert.assertEquals(2, message.getExtensionCount(packedFloatExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedDoubleExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedBoolExtensionLite ));
+ Assert.assertEquals(2, message.getExtensionCount(packedEnumExtensionLite));
+ assertEqualsExactType(601 , message.getExtension(packedInt32ExtensionLite , 0));
+ assertEqualsExactType(602L , message.getExtension(packedInt64ExtensionLite , 0));
+ assertEqualsExactType(603 , message.getExtension(packedUint32ExtensionLite , 0));
+ assertEqualsExactType(604L , message.getExtension(packedUint64ExtensionLite , 0));
+ assertEqualsExactType(605 , message.getExtension(packedSint32ExtensionLite , 0));
+ assertEqualsExactType(606L , message.getExtension(packedSint64ExtensionLite , 0));
+ assertEqualsExactType(607 , message.getExtension(packedFixed32ExtensionLite , 0));
+ assertEqualsExactType(608L , message.getExtension(packedFixed64ExtensionLite , 0));
+ assertEqualsExactType(609 , message.getExtension(packedSfixed32ExtensionLite, 0));
+ assertEqualsExactType(610L , message.getExtension(packedSfixed64ExtensionLite, 0));
+ assertEqualsExactType(611F , message.getExtension(packedFloatExtensionLite , 0));
+ assertEqualsExactType(612D , message.getExtension(packedDoubleExtensionLite , 0));
+ assertEqualsExactType(true , message.getExtension(packedBoolExtensionLite , 0));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAR,
+ message.getExtension(packedEnumExtensionLite, 0));
+ assertEqualsExactType(701 , message.getExtension(packedInt32ExtensionLite , 1));
+ assertEqualsExactType(702L , message.getExtension(packedInt64ExtensionLite , 1));
+ assertEqualsExactType(703 , message.getExtension(packedUint32ExtensionLite , 1));
+ assertEqualsExactType(704L , message.getExtension(packedUint64ExtensionLite , 1));
+ assertEqualsExactType(705 , message.getExtension(packedSint32ExtensionLite , 1));
+ assertEqualsExactType(706L , message.getExtension(packedSint64ExtensionLite , 1));
+ assertEqualsExactType(707 , message.getExtension(packedFixed32ExtensionLite , 1));
+ assertEqualsExactType(708L , message.getExtension(packedFixed64ExtensionLite , 1));
+ assertEqualsExactType(709 , message.getExtension(packedSfixed32ExtensionLite, 1));
+ assertEqualsExactType(710L , message.getExtension(packedSfixed64ExtensionLite, 1));
+ assertEqualsExactType(711F , message.getExtension(packedFloatExtensionLite , 1));
+ assertEqualsExactType(712D , message.getExtension(packedDoubleExtensionLite , 1));
+ assertEqualsExactType(false, message.getExtension(packedBoolExtensionLite , 1));
+ assertEqualsExactType(ForeignEnumLite.FOREIGN_LITE_BAZ,
+ message.getExtension(packedEnumExtensionLite, 1));
+ }
+
+ // =================================================================
+
+ /**
+ * Performs the same things that the methods of {@code TestUtil} do, but
+ * via the reflection interface. This is its own class because it needs
+ * to know what descriptor to use.
+ */
+ public static class ReflectionTester {
+ private final Descriptors.Descriptor baseDescriptor;
+ private final ExtensionRegistry extensionRegistry;
+
+ private final Descriptors.FileDescriptor file;
+ private final Descriptors.FileDescriptor importFile;
+
+ private final Descriptors.Descriptor optionalGroup;
+ private final Descriptors.Descriptor repeatedGroup;
+ private final Descriptors.Descriptor nestedMessage;
+ private final Descriptors.Descriptor foreignMessage;
+ private final Descriptors.Descriptor importMessage;
+
+ private final Descriptors.FieldDescriptor groupA;
+ private final Descriptors.FieldDescriptor repeatedGroupA;
+ private final Descriptors.FieldDescriptor nestedB;
+ private final Descriptors.FieldDescriptor foreignC;
+ private final Descriptors.FieldDescriptor importD;
+
+ private final Descriptors.EnumDescriptor nestedEnum;
+ private final Descriptors.EnumDescriptor foreignEnum;
+ private final Descriptors.EnumDescriptor importEnum;
+
+ private final Descriptors.EnumValueDescriptor nestedFoo;
+ private final Descriptors.EnumValueDescriptor nestedBar;
+ private final Descriptors.EnumValueDescriptor nestedBaz;
+ private final Descriptors.EnumValueDescriptor foreignFoo;
+ private final Descriptors.EnumValueDescriptor foreignBar;
+ private final Descriptors.EnumValueDescriptor foreignBaz;
+ private final Descriptors.EnumValueDescriptor importFoo;
+ private final Descriptors.EnumValueDescriptor importBar;
+ private final Descriptors.EnumValueDescriptor importBaz;
+
+ /**
+ * Construct a {@code ReflectionTester} that will expect messages using
+ * the given descriptor.
+ *
+ * Normally {@code baseDescriptor} should be a descriptor for the type
+ * {@code TestAllTypes}, defined in
+ * {@code google/protobuf/unittest.proto}. However, if
+ * {@code extensionRegistry} is non-null, then {@code baseDescriptor} should
+ * be for {@code TestAllExtensions} instead, and instead of reading and
+ * writing normal fields, the tester will read and write extensions.
+ * All of {@code TestAllExtensions}' extensions must be registered in the
+ * registry.
+ */
+ public ReflectionTester(Descriptors.Descriptor baseDescriptor,
+ ExtensionRegistry extensionRegistry) {
+ this.baseDescriptor = baseDescriptor;
+ this.extensionRegistry = extensionRegistry;
+
+ this.file = baseDescriptor.getFile();
+ Assert.assertEquals(1, file.getDependencies().size());
+ this.importFile = file.getDependencies().get(0);
+
+ Descriptors.Descriptor testAllTypes;
+ if (baseDescriptor.getName() == "TestAllTypes") {
+ testAllTypes = baseDescriptor;
+ } else {
+ testAllTypes = file.findMessageTypeByName("TestAllTypes");
+ Assert.assertNotNull(testAllTypes);
+ }
+
+ if (extensionRegistry == null) {
+ // Use testAllTypes, rather than baseDescriptor, to allow
+ // initialization using TestPackedTypes descriptors. These objects
+ // won't be used by the methods for packed fields.
+ this.optionalGroup =
+ testAllTypes.findNestedTypeByName("OptionalGroup");
+ this.repeatedGroup =
+ testAllTypes.findNestedTypeByName("RepeatedGroup");
+ } else {
+ this.optionalGroup =
+ file.findMessageTypeByName("OptionalGroup_extension");
+ this.repeatedGroup =
+ file.findMessageTypeByName("RepeatedGroup_extension");
+ }
+ this.nestedMessage = testAllTypes.findNestedTypeByName("NestedMessage");
+ this.foreignMessage = file.findMessageTypeByName("ForeignMessage");
+ this.importMessage = importFile.findMessageTypeByName("ImportMessage");
+
+ this.nestedEnum = testAllTypes.findEnumTypeByName("NestedEnum");
+ this.foreignEnum = file.findEnumTypeByName("ForeignEnum");
+ this.importEnum = importFile.findEnumTypeByName("ImportEnum");
+
+ Assert.assertNotNull(optionalGroup );
+ Assert.assertNotNull(repeatedGroup );
+ Assert.assertNotNull(nestedMessage );
+ Assert.assertNotNull(foreignMessage);
+ Assert.assertNotNull(importMessage );
+ Assert.assertNotNull(nestedEnum );
+ Assert.assertNotNull(foreignEnum );
+ Assert.assertNotNull(importEnum );
+
+ this.nestedB = nestedMessage .findFieldByName("bb");
+ this.foreignC = foreignMessage.findFieldByName("c");
+ this.importD = importMessage .findFieldByName("d");
+ this.nestedFoo = nestedEnum.findValueByName("FOO");
+ this.nestedBar = nestedEnum.findValueByName("BAR");
+ this.nestedBaz = nestedEnum.findValueByName("BAZ");
+ this.foreignFoo = foreignEnum.findValueByName("FOREIGN_FOO");
+ this.foreignBar = foreignEnum.findValueByName("FOREIGN_BAR");
+ this.foreignBaz = foreignEnum.findValueByName("FOREIGN_BAZ");
+ this.importFoo = importEnum.findValueByName("IMPORT_FOO");
+ this.importBar = importEnum.findValueByName("IMPORT_BAR");
+ this.importBaz = importEnum.findValueByName("IMPORT_BAZ");
+
+ this.groupA = optionalGroup.findFieldByName("a");
+ this.repeatedGroupA = repeatedGroup.findFieldByName("a");
+
+ Assert.assertNotNull(groupA );
+ Assert.assertNotNull(repeatedGroupA);
+ Assert.assertNotNull(nestedB );
+ Assert.assertNotNull(foreignC );
+ Assert.assertNotNull(importD );
+ Assert.assertNotNull(nestedFoo );
+ Assert.assertNotNull(nestedBar );
+ Assert.assertNotNull(nestedBaz );
+ Assert.assertNotNull(foreignFoo );
+ Assert.assertNotNull(foreignBar );
+ Assert.assertNotNull(foreignBaz );
+ Assert.assertNotNull(importFoo );
+ Assert.assertNotNull(importBar );
+ Assert.assertNotNull(importBaz );
+ }
+
+ /**
+ * Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
+ */
+ private Descriptors.FieldDescriptor f(String name) {
+ Descriptors.FieldDescriptor result;
+ if (extensionRegistry == null) {
+ result = baseDescriptor.findFieldByName(name);
+ } else {
+ result = file.findExtensionByName(name + "_extension");
+ }
+ Assert.assertNotNull(result);
+ return result;
+ }
+
+ /**
+ * Calls {@code parent.newBuilderForField()} or uses the
+ * {@code ExtensionRegistry} to find an appropriate builder, depending
+ * on what type is being tested.
+ */
+ private Message.Builder newBuilderForField(
+ Message.Builder parent, Descriptors.FieldDescriptor field) {
+ if (extensionRegistry == null) {
+ return parent.newBuilderForField(field);
+ } else {
+ ExtensionRegistry.ExtensionInfo extension =
+ extensionRegistry.findExtensionByNumber(field.getContainingType(),
+ field.getNumber());
+ Assert.assertNotNull(extension);
+ Assert.assertNotNull(extension.defaultInstance);
+ return extension.defaultInstance.newBuilderForType();
+ }
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Set every field of {@code message} to the values expected by
+ * {@code assertAllFieldsSet()}, using the {@link Message.Builder}
+ * reflection interface.
+ */
+ void setAllFieldsViaReflection(Message.Builder message) {
+ message.setField(f("optional_int32" ), 101 );
+ message.setField(f("optional_int64" ), 102L);
+ message.setField(f("optional_uint32" ), 103 );
+ message.setField(f("optional_uint64" ), 104L);
+ message.setField(f("optional_sint32" ), 105 );
+ message.setField(f("optional_sint64" ), 106L);
+ message.setField(f("optional_fixed32" ), 107 );
+ message.setField(f("optional_fixed64" ), 108L);
+ message.setField(f("optional_sfixed32"), 109 );
+ message.setField(f("optional_sfixed64"), 110L);
+ message.setField(f("optional_float" ), 111F);
+ message.setField(f("optional_double" ), 112D);
+ message.setField(f("optional_bool" ), true);
+ message.setField(f("optional_string" ), "115");
+ message.setField(f("optional_bytes" ), toBytes("116"));
+
+ message.setField(f("optionalgroup"),
+ newBuilderForField(message, f("optionalgroup"))
+ .setField(groupA, 117).build());
+ message.setField(f("optional_nested_message"),
+ newBuilderForField(message, f("optional_nested_message"))
+ .setField(nestedB, 118).build());
+ message.setField(f("optional_foreign_message"),
+ newBuilderForField(message, f("optional_foreign_message"))
+ .setField(foreignC, 119).build());
+ message.setField(f("optional_import_message"),
+ newBuilderForField(message, f("optional_import_message"))
+ .setField(importD, 120).build());
+
+ message.setField(f("optional_nested_enum" ), nestedBaz);
+ message.setField(f("optional_foreign_enum"), foreignBaz);
+ message.setField(f("optional_import_enum" ), importBaz);
+
+ message.setField(f("optional_string_piece" ), "124");
+ message.setField(f("optional_cord" ), "125");
+
+ // -----------------------------------------------------------------
+
+ message.addRepeatedField(f("repeated_int32" ), 201 );
+ message.addRepeatedField(f("repeated_int64" ), 202L);
+ message.addRepeatedField(f("repeated_uint32" ), 203 );
+ message.addRepeatedField(f("repeated_uint64" ), 204L);
+ message.addRepeatedField(f("repeated_sint32" ), 205 );
+ message.addRepeatedField(f("repeated_sint64" ), 206L);
+ message.addRepeatedField(f("repeated_fixed32" ), 207 );
+ message.addRepeatedField(f("repeated_fixed64" ), 208L);
+ message.addRepeatedField(f("repeated_sfixed32"), 209 );
+ message.addRepeatedField(f("repeated_sfixed64"), 210L);
+ message.addRepeatedField(f("repeated_float" ), 211F);
+ message.addRepeatedField(f("repeated_double" ), 212D);
+ message.addRepeatedField(f("repeated_bool" ), true);
+ message.addRepeatedField(f("repeated_string" ), "215");
+ message.addRepeatedField(f("repeated_bytes" ), toBytes("216"));
+
+ message.addRepeatedField(f("repeatedgroup"),
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 217).build());
+ message.addRepeatedField(f("repeated_nested_message"),
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 218).build());
+ message.addRepeatedField(f("repeated_foreign_message"),
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 219).build());
+ message.addRepeatedField(f("repeated_import_message"),
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 220).build());
+
+ message.addRepeatedField(f("repeated_nested_enum" ), nestedBar);
+ message.addRepeatedField(f("repeated_foreign_enum"), foreignBar);
+ message.addRepeatedField(f("repeated_import_enum" ), importBar);
+
+ message.addRepeatedField(f("repeated_string_piece" ), "224");
+ message.addRepeatedField(f("repeated_cord" ), "225");
+
+ // Add a second one of each field.
+ message.addRepeatedField(f("repeated_int32" ), 301 );
+ message.addRepeatedField(f("repeated_int64" ), 302L);
+ message.addRepeatedField(f("repeated_uint32" ), 303 );
+ message.addRepeatedField(f("repeated_uint64" ), 304L);
+ message.addRepeatedField(f("repeated_sint32" ), 305 );
+ message.addRepeatedField(f("repeated_sint64" ), 306L);
+ message.addRepeatedField(f("repeated_fixed32" ), 307 );
+ message.addRepeatedField(f("repeated_fixed64" ), 308L);
+ message.addRepeatedField(f("repeated_sfixed32"), 309 );
+ message.addRepeatedField(f("repeated_sfixed64"), 310L);
+ message.addRepeatedField(f("repeated_float" ), 311F);
+ message.addRepeatedField(f("repeated_double" ), 312D);
+ message.addRepeatedField(f("repeated_bool" ), false);
+ message.addRepeatedField(f("repeated_string" ), "315");
+ message.addRepeatedField(f("repeated_bytes" ), toBytes("316"));
+
+ message.addRepeatedField(f("repeatedgroup"),
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 317).build());
+ message.addRepeatedField(f("repeated_nested_message"),
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 318).build());
+ message.addRepeatedField(f("repeated_foreign_message"),
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 319).build());
+ message.addRepeatedField(f("repeated_import_message"),
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 320).build());
+
+ message.addRepeatedField(f("repeated_nested_enum" ), nestedBaz);
+ message.addRepeatedField(f("repeated_foreign_enum"), foreignBaz);
+ message.addRepeatedField(f("repeated_import_enum" ), importBaz);
+
+ message.addRepeatedField(f("repeated_string_piece" ), "324");
+ message.addRepeatedField(f("repeated_cord" ), "325");
+
+ // -----------------------------------------------------------------
+
+ message.setField(f("default_int32" ), 401 );
+ message.setField(f("default_int64" ), 402L);
+ message.setField(f("default_uint32" ), 403 );
+ message.setField(f("default_uint64" ), 404L);
+ message.setField(f("default_sint32" ), 405 );
+ message.setField(f("default_sint64" ), 406L);
+ message.setField(f("default_fixed32" ), 407 );
+ message.setField(f("default_fixed64" ), 408L);
+ message.setField(f("default_sfixed32"), 409 );
+ message.setField(f("default_sfixed64"), 410L);
+ message.setField(f("default_float" ), 411F);
+ message.setField(f("default_double" ), 412D);
+ message.setField(f("default_bool" ), false);
+ message.setField(f("default_string" ), "415");
+ message.setField(f("default_bytes" ), toBytes("416"));
+
+ message.setField(f("default_nested_enum" ), nestedFoo);
+ message.setField(f("default_foreign_enum"), foreignFoo);
+ message.setField(f("default_import_enum" ), importFoo);
+
+ message.setField(f("default_string_piece" ), "424");
+ message.setField(f("default_cord" ), "425");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Modify the repeated fields of {@code message} to contain the values
+ * expected by {@code assertRepeatedFieldsModified()}, using the
+ * {@link Message.Builder} reflection interface.
+ */
+ void modifyRepeatedFieldsViaReflection(Message.Builder message) {
+ message.setRepeatedField(f("repeated_int32" ), 1, 501 );
+ message.setRepeatedField(f("repeated_int64" ), 1, 502L);
+ message.setRepeatedField(f("repeated_uint32" ), 1, 503 );
+ message.setRepeatedField(f("repeated_uint64" ), 1, 504L);
+ message.setRepeatedField(f("repeated_sint32" ), 1, 505 );
+ message.setRepeatedField(f("repeated_sint64" ), 1, 506L);
+ message.setRepeatedField(f("repeated_fixed32" ), 1, 507 );
+ message.setRepeatedField(f("repeated_fixed64" ), 1, 508L);
+ message.setRepeatedField(f("repeated_sfixed32"), 1, 509 );
+ message.setRepeatedField(f("repeated_sfixed64"), 1, 510L);
+ message.setRepeatedField(f("repeated_float" ), 1, 511F);
+ message.setRepeatedField(f("repeated_double" ), 1, 512D);
+ message.setRepeatedField(f("repeated_bool" ), 1, true);
+ message.setRepeatedField(f("repeated_string" ), 1, "515");
+ message.setRepeatedField(f("repeated_bytes" ), 1, toBytes("516"));
+
+ message.setRepeatedField(f("repeatedgroup"), 1,
+ newBuilderForField(message, f("repeatedgroup"))
+ .setField(repeatedGroupA, 517).build());
+ message.setRepeatedField(f("repeated_nested_message"), 1,
+ newBuilderForField(message, f("repeated_nested_message"))
+ .setField(nestedB, 518).build());
+ message.setRepeatedField(f("repeated_foreign_message"), 1,
+ newBuilderForField(message, f("repeated_foreign_message"))
+ .setField(foreignC, 519).build());
+ message.setRepeatedField(f("repeated_import_message"), 1,
+ newBuilderForField(message, f("repeated_import_message"))
+ .setField(importD, 520).build());
+
+ message.setRepeatedField(f("repeated_nested_enum" ), 1, nestedFoo);
+ message.setRepeatedField(f("repeated_foreign_enum"), 1, foreignFoo);
+ message.setRepeatedField(f("repeated_import_enum" ), 1, importFoo);
+
+ message.setRepeatedField(f("repeated_string_piece"), 1, "524");
+ message.setRepeatedField(f("repeated_cord"), 1, "525");
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are set to the values assigned by {@code setAllFields},
+ * using the {@link Message} reflection interface.
+ */
+ public void assertAllFieldsSetViaReflection(Message message) {
+ Assert.assertTrue(message.hasField(f("optional_int32" )));
+ Assert.assertTrue(message.hasField(f("optional_int64" )));
+ Assert.assertTrue(message.hasField(f("optional_uint32" )));
+ Assert.assertTrue(message.hasField(f("optional_uint64" )));
+ Assert.assertTrue(message.hasField(f("optional_sint32" )));
+ Assert.assertTrue(message.hasField(f("optional_sint64" )));
+ Assert.assertTrue(message.hasField(f("optional_fixed32" )));
+ Assert.assertTrue(message.hasField(f("optional_fixed64" )));
+ Assert.assertTrue(message.hasField(f("optional_sfixed32")));
+ Assert.assertTrue(message.hasField(f("optional_sfixed64")));
+ Assert.assertTrue(message.hasField(f("optional_float" )));
+ Assert.assertTrue(message.hasField(f("optional_double" )));
+ Assert.assertTrue(message.hasField(f("optional_bool" )));
+ Assert.assertTrue(message.hasField(f("optional_string" )));
+ Assert.assertTrue(message.hasField(f("optional_bytes" )));
+
+ Assert.assertTrue(message.hasField(f("optionalgroup" )));
+ Assert.assertTrue(message.hasField(f("optional_nested_message" )));
+ Assert.assertTrue(message.hasField(f("optional_foreign_message")));
+ Assert.assertTrue(message.hasField(f("optional_import_message" )));
+
+ Assert.assertTrue(
+ ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_nested_message")))
+ .hasField(nestedB));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_foreign_message")))
+ .hasField(foreignC));
+ Assert.assertTrue(
+ ((Message)message.getField(f("optional_import_message")))
+ .hasField(importD));
+
+ Assert.assertTrue(message.hasField(f("optional_nested_enum" )));
+ Assert.assertTrue(message.hasField(f("optional_foreign_enum")));
+ Assert.assertTrue(message.hasField(f("optional_import_enum" )));
+
+ Assert.assertTrue(message.hasField(f("optional_string_piece")));
+ Assert.assertTrue(message.hasField(f("optional_cord")));
+
+ Assert.assertEquals(101 , message.getField(f("optional_int32" )));
+ Assert.assertEquals(102L , message.getField(f("optional_int64" )));
+ Assert.assertEquals(103 , message.getField(f("optional_uint32" )));
+ Assert.assertEquals(104L , message.getField(f("optional_uint64" )));
+ Assert.assertEquals(105 , message.getField(f("optional_sint32" )));
+ Assert.assertEquals(106L , message.getField(f("optional_sint64" )));
+ Assert.assertEquals(107 , message.getField(f("optional_fixed32" )));
+ Assert.assertEquals(108L , message.getField(f("optional_fixed64" )));
+ Assert.assertEquals(109 , message.getField(f("optional_sfixed32")));
+ Assert.assertEquals(110L , message.getField(f("optional_sfixed64")));
+ Assert.assertEquals(111F , message.getField(f("optional_float" )));
+ Assert.assertEquals(112D , message.getField(f("optional_double" )));
+ Assert.assertEquals(true , message.getField(f("optional_bool" )));
+ Assert.assertEquals("115", message.getField(f("optional_string" )));
+ Assert.assertEquals(toBytes("116"), message.getField(f("optional_bytes")));
+
+ Assert.assertEquals(117,
+ ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+ Assert.assertEquals(118,
+ ((Message)message.getField(f("optional_nested_message")))
+ .getField(nestedB));
+ Assert.assertEquals(119,
+ ((Message)message.getField(f("optional_foreign_message")))
+ .getField(foreignC));
+ Assert.assertEquals(120,
+ ((Message)message.getField(f("optional_import_message")))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBaz, message.getField(f("optional_nested_enum" )));
+ Assert.assertEquals(foreignBaz, message.getField(f("optional_foreign_enum")));
+ Assert.assertEquals( importBaz, message.getField(f("optional_import_enum" )));
+
+ Assert.assertEquals("124", message.getField(f("optional_string_piece")));
+ Assert.assertEquals("125", message.getField(f("optional_cord")));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ Assert.assertEquals(201 , message.getRepeatedField(f("repeated_int32" ), 0));
+ Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64" ), 0));
+ Assert.assertEquals(203 , message.getRepeatedField(f("repeated_uint32" ), 0));
+ Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64" ), 0));
+ Assert.assertEquals(205 , message.getRepeatedField(f("repeated_sint32" ), 0));
+ Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64" ), 0));
+ Assert.assertEquals(207 , message.getRepeatedField(f("repeated_fixed32" ), 0));
+ Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+ Assert.assertEquals(209 , message.getRepeatedField(f("repeated_sfixed32"), 0));
+ Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+ Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float" ), 0));
+ Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double" ), 0));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 0));
+ Assert.assertEquals("215", message.getRepeatedField(f("repeated_string" ), 0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+ Assert.assertEquals(217,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(218,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+ .getField(nestedB));
+ Assert.assertEquals(219,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+ .getField(foreignC));
+ Assert.assertEquals(220,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+ Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+ Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+ Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+ Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+ Assert.assertEquals(301 , message.getRepeatedField(f("repeated_int32" ), 1));
+ Assert.assertEquals(302L , message.getRepeatedField(f("repeated_int64" ), 1));
+ Assert.assertEquals(303 , message.getRepeatedField(f("repeated_uint32" ), 1));
+ Assert.assertEquals(304L , message.getRepeatedField(f("repeated_uint64" ), 1));
+ Assert.assertEquals(305 , message.getRepeatedField(f("repeated_sint32" ), 1));
+ Assert.assertEquals(306L , message.getRepeatedField(f("repeated_sint64" ), 1));
+ Assert.assertEquals(307 , message.getRepeatedField(f("repeated_fixed32" ), 1));
+ Assert.assertEquals(308L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+ Assert.assertEquals(309 , message.getRepeatedField(f("repeated_sfixed32"), 1));
+ Assert.assertEquals(310L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+ Assert.assertEquals(311F , message.getRepeatedField(f("repeated_float" ), 1));
+ Assert.assertEquals(312D , message.getRepeatedField(f("repeated_double" ), 1));
+ Assert.assertEquals(false, message.getRepeatedField(f("repeated_bool" ), 1));
+ Assert.assertEquals("315", message.getRepeatedField(f("repeated_string" ), 1));
+ Assert.assertEquals(toBytes("316"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+ Assert.assertEquals(317,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(318,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+ .getField(nestedB));
+ Assert.assertEquals(319,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+ .getField(foreignC));
+ Assert.assertEquals(320,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBaz, message.getRepeatedField(f("repeated_nested_enum" ),1));
+ Assert.assertEquals(foreignBaz, message.getRepeatedField(f("repeated_foreign_enum"),1));
+ Assert.assertEquals( importBaz, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+ Assert.assertEquals("324", message.getRepeatedField(f("repeated_string_piece"), 1));
+ Assert.assertEquals("325", message.getRepeatedField(f("repeated_cord"), 1));
+
+ // -----------------------------------------------------------------
+
+ Assert.assertTrue(message.hasField(f("default_int32" )));
+ Assert.assertTrue(message.hasField(f("default_int64" )));
+ Assert.assertTrue(message.hasField(f("default_uint32" )));
+ Assert.assertTrue(message.hasField(f("default_uint64" )));
+ Assert.assertTrue(message.hasField(f("default_sint32" )));
+ Assert.assertTrue(message.hasField(f("default_sint64" )));
+ Assert.assertTrue(message.hasField(f("default_fixed32" )));
+ Assert.assertTrue(message.hasField(f("default_fixed64" )));
+ Assert.assertTrue(message.hasField(f("default_sfixed32")));
+ Assert.assertTrue(message.hasField(f("default_sfixed64")));
+ Assert.assertTrue(message.hasField(f("default_float" )));
+ Assert.assertTrue(message.hasField(f("default_double" )));
+ Assert.assertTrue(message.hasField(f("default_bool" )));
+ Assert.assertTrue(message.hasField(f("default_string" )));
+ Assert.assertTrue(message.hasField(f("default_bytes" )));
+
+ Assert.assertTrue(message.hasField(f("default_nested_enum" )));
+ Assert.assertTrue(message.hasField(f("default_foreign_enum")));
+ Assert.assertTrue(message.hasField(f("default_import_enum" )));
+
+ Assert.assertTrue(message.hasField(f("default_string_piece")));
+ Assert.assertTrue(message.hasField(f("default_cord")));
+
+ Assert.assertEquals(401 , message.getField(f("default_int32" )));
+ Assert.assertEquals(402L , message.getField(f("default_int64" )));
+ Assert.assertEquals(403 , message.getField(f("default_uint32" )));
+ Assert.assertEquals(404L , message.getField(f("default_uint64" )));
+ Assert.assertEquals(405 , message.getField(f("default_sint32" )));
+ Assert.assertEquals(406L , message.getField(f("default_sint64" )));
+ Assert.assertEquals(407 , message.getField(f("default_fixed32" )));
+ Assert.assertEquals(408L , message.getField(f("default_fixed64" )));
+ Assert.assertEquals(409 , message.getField(f("default_sfixed32")));
+ Assert.assertEquals(410L , message.getField(f("default_sfixed64")));
+ Assert.assertEquals(411F , message.getField(f("default_float" )));
+ Assert.assertEquals(412D , message.getField(f("default_double" )));
+ Assert.assertEquals(false, message.getField(f("default_bool" )));
+ Assert.assertEquals("415", message.getField(f("default_string" )));
+ Assert.assertEquals(toBytes("416"), message.getField(f("default_bytes")));
+
+ Assert.assertEquals( nestedFoo, message.getField(f("default_nested_enum" )));
+ Assert.assertEquals(foreignFoo, message.getField(f("default_foreign_enum")));
+ Assert.assertEquals( importFoo, message.getField(f("default_import_enum" )));
+
+ Assert.assertEquals("424", message.getField(f("default_string_piece")));
+ Assert.assertEquals("425", message.getField(f("default_cord")));
+ }
+
+ // -------------------------------------------------------------------
+
+ /**
+ * Assert (using {@code junit.framework.Assert}} that all fields of
+ * {@code message} are cleared, and that getting the fields returns their
+ * default values, using the {@link Message} reflection interface.
+ */
+ public void assertClearViaReflection(Message message) {
+ // has_blah() should initially be false for all optional fields.
+ Assert.assertFalse(message.hasField(f("optional_int32" )));
+ Assert.assertFalse(message.hasField(f("optional_int64" )));
+ Assert.assertFalse(message.hasField(f("optional_uint32" )));
+ Assert.assertFalse(message.hasField(f("optional_uint64" )));
+ Assert.assertFalse(message.hasField(f("optional_sint32" )));
+ Assert.assertFalse(message.hasField(f("optional_sint64" )));
+ Assert.assertFalse(message.hasField(f("optional_fixed32" )));
+ Assert.assertFalse(message.hasField(f("optional_fixed64" )));
+ Assert.assertFalse(message.hasField(f("optional_sfixed32")));
+ Assert.assertFalse(message.hasField(f("optional_sfixed64")));
+ Assert.assertFalse(message.hasField(f("optional_float" )));
+ Assert.assertFalse(message.hasField(f("optional_double" )));
+ Assert.assertFalse(message.hasField(f("optional_bool" )));
+ Assert.assertFalse(message.hasField(f("optional_string" )));
+ Assert.assertFalse(message.hasField(f("optional_bytes" )));
+
+ Assert.assertFalse(message.hasField(f("optionalgroup" )));
+ Assert.assertFalse(message.hasField(f("optional_nested_message" )));
+ Assert.assertFalse(message.hasField(f("optional_foreign_message")));
+ Assert.assertFalse(message.hasField(f("optional_import_message" )));
+
+ Assert.assertFalse(message.hasField(f("optional_nested_enum" )));
+ Assert.assertFalse(message.hasField(f("optional_foreign_enum")));
+ Assert.assertFalse(message.hasField(f("optional_import_enum" )));
+
+ Assert.assertFalse(message.hasField(f("optional_string_piece")));
+ Assert.assertFalse(message.hasField(f("optional_cord")));
+
+ // Optional fields without defaults are set to zero or something like it.
+ Assert.assertEquals(0 , message.getField(f("optional_int32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_int64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_uint32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_uint64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_sint32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_sint64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_fixed32" )));
+ Assert.assertEquals(0L , message.getField(f("optional_fixed64" )));
+ Assert.assertEquals(0 , message.getField(f("optional_sfixed32")));
+ Assert.assertEquals(0L , message.getField(f("optional_sfixed64")));
+ Assert.assertEquals(0F , message.getField(f("optional_float" )));
+ Assert.assertEquals(0D , message.getField(f("optional_double" )));
+ Assert.assertEquals(false, message.getField(f("optional_bool" )));
+ Assert.assertEquals("" , message.getField(f("optional_string" )));
+ Assert.assertEquals(ByteString.EMPTY, message.getField(f("optional_bytes")));
+
+ // Embedded messages should also be clear.
+ Assert.assertFalse(
+ ((Message)message.getField(f("optionalgroup"))).hasField(groupA));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_nested_message")))
+ .hasField(nestedB));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_foreign_message")))
+ .hasField(foreignC));
+ Assert.assertFalse(
+ ((Message)message.getField(f("optional_import_message")))
+ .hasField(importD));
+
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optionalgroup"))).getField(groupA));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_nested_message")))
+ .getField(nestedB));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_foreign_message")))
+ .getField(foreignC));
+ Assert.assertEquals(0,
+ ((Message)message.getField(f("optional_import_message")))
+ .getField(importD));
+
+ // Enums without defaults are set to the first value in the enum.
+ Assert.assertEquals( nestedFoo, message.getField(f("optional_nested_enum" )));
+ Assert.assertEquals(foreignFoo, message.getField(f("optional_foreign_enum")));
+ Assert.assertEquals( importFoo, message.getField(f("optional_import_enum" )));
+
+ Assert.assertEquals("", message.getField(f("optional_string_piece")));
+ Assert.assertEquals("", message.getField(f("optional_cord")));
+
+ // Repeated fields are empty.
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(0, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ // has_blah() should also be false for all default fields.
+ Assert.assertFalse(message.hasField(f("default_int32" )));
+ Assert.assertFalse(message.hasField(f("default_int64" )));
+ Assert.assertFalse(message.hasField(f("default_uint32" )));
+ Assert.assertFalse(message.hasField(f("default_uint64" )));
+ Assert.assertFalse(message.hasField(f("default_sint32" )));
+ Assert.assertFalse(message.hasField(f("default_sint64" )));
+ Assert.assertFalse(message.hasField(f("default_fixed32" )));
+ Assert.assertFalse(message.hasField(f("default_fixed64" )));
+ Assert.assertFalse(message.hasField(f("default_sfixed32")));
+ Assert.assertFalse(message.hasField(f("default_sfixed64")));
+ Assert.assertFalse(message.hasField(f("default_float" )));
+ Assert.assertFalse(message.hasField(f("default_double" )));
+ Assert.assertFalse(message.hasField(f("default_bool" )));
+ Assert.assertFalse(message.hasField(f("default_string" )));
+ Assert.assertFalse(message.hasField(f("default_bytes" )));
+
+ Assert.assertFalse(message.hasField(f("default_nested_enum" )));
+ Assert.assertFalse(message.hasField(f("default_foreign_enum")));
+ Assert.assertFalse(message.hasField(f("default_import_enum" )));
+
+ Assert.assertFalse(message.hasField(f("default_string_piece" )));
+ Assert.assertFalse(message.hasField(f("default_cord" )));
+
+ // Fields with defaults have their default values (duh).
+ Assert.assertEquals( 41 , message.getField(f("default_int32" )));
+ Assert.assertEquals( 42L , message.getField(f("default_int64" )));
+ Assert.assertEquals( 43 , message.getField(f("default_uint32" )));
+ Assert.assertEquals( 44L , message.getField(f("default_uint64" )));
+ Assert.assertEquals(-45 , message.getField(f("default_sint32" )));
+ Assert.assertEquals( 46L , message.getField(f("default_sint64" )));
+ Assert.assertEquals( 47 , message.getField(f("default_fixed32" )));
+ Assert.assertEquals( 48L , message.getField(f("default_fixed64" )));
+ Assert.assertEquals( 49 , message.getField(f("default_sfixed32")));
+ Assert.assertEquals(-50L , message.getField(f("default_sfixed64")));
+ Assert.assertEquals( 51.5F , message.getField(f("default_float" )));
+ Assert.assertEquals( 52e3D , message.getField(f("default_double" )));
+ Assert.assertEquals(true , message.getField(f("default_bool" )));
+ Assert.assertEquals("hello", message.getField(f("default_string" )));
+ Assert.assertEquals(toBytes("world"), message.getField(f("default_bytes")));
+
+ Assert.assertEquals( nestedBar, message.getField(f("default_nested_enum" )));
+ Assert.assertEquals(foreignBar, message.getField(f("default_foreign_enum")));
+ Assert.assertEquals( importBar, message.getField(f("default_import_enum" )));
+
+ Assert.assertEquals("abc", message.getField(f("default_string_piece")));
+ Assert.assertEquals("123", message.getField(f("default_cord")));
+ }
+
+ // ---------------------------------------------------------------
+
+ public void assertRepeatedFieldsModifiedViaReflection(Message message) {
+ // ModifyRepeatedFields only sets the second repeated element of each
+ // field. In addition to verifying this, we also verify that the first
+ // element and size were *not* modified.
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_int64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_uint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_fixed64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed32")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_sfixed64")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_float" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_double" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bool" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_bytes" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeatedgroup" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_message")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_message" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_nested_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_foreign_enum" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_import_enum" )));
+
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_string_piece")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("repeated_cord")));
+
+ Assert.assertEquals(201 , message.getRepeatedField(f("repeated_int32" ), 0));
+ Assert.assertEquals(202L , message.getRepeatedField(f("repeated_int64" ), 0));
+ Assert.assertEquals(203 , message.getRepeatedField(f("repeated_uint32" ), 0));
+ Assert.assertEquals(204L , message.getRepeatedField(f("repeated_uint64" ), 0));
+ Assert.assertEquals(205 , message.getRepeatedField(f("repeated_sint32" ), 0));
+ Assert.assertEquals(206L , message.getRepeatedField(f("repeated_sint64" ), 0));
+ Assert.assertEquals(207 , message.getRepeatedField(f("repeated_fixed32" ), 0));
+ Assert.assertEquals(208L , message.getRepeatedField(f("repeated_fixed64" ), 0));
+ Assert.assertEquals(209 , message.getRepeatedField(f("repeated_sfixed32"), 0));
+ Assert.assertEquals(210L , message.getRepeatedField(f("repeated_sfixed64"), 0));
+ Assert.assertEquals(211F , message.getRepeatedField(f("repeated_float" ), 0));
+ Assert.assertEquals(212D , message.getRepeatedField(f("repeated_double" ), 0));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 0));
+ Assert.assertEquals("215", message.getRepeatedField(f("repeated_string" ), 0));
+ Assert.assertEquals(toBytes("216"), message.getRepeatedField(f("repeated_bytes"), 0));
+
+ Assert.assertEquals(217,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 0))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(218,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 0))
+ .getField(nestedB));
+ Assert.assertEquals(219,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 0))
+ .getField(foreignC));
+ Assert.assertEquals(220,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 0))
+ .getField(importD));
+
+ Assert.assertEquals( nestedBar, message.getRepeatedField(f("repeated_nested_enum" ),0));
+ Assert.assertEquals(foreignBar, message.getRepeatedField(f("repeated_foreign_enum"),0));
+ Assert.assertEquals( importBar, message.getRepeatedField(f("repeated_import_enum" ),0));
+
+ Assert.assertEquals("224", message.getRepeatedField(f("repeated_string_piece"), 0));
+ Assert.assertEquals("225", message.getRepeatedField(f("repeated_cord"), 0));
+
+ Assert.assertEquals(501 , message.getRepeatedField(f("repeated_int32" ), 1));
+ Assert.assertEquals(502L , message.getRepeatedField(f("repeated_int64" ), 1));
+ Assert.assertEquals(503 , message.getRepeatedField(f("repeated_uint32" ), 1));
+ Assert.assertEquals(504L , message.getRepeatedField(f("repeated_uint64" ), 1));
+ Assert.assertEquals(505 , message.getRepeatedField(f("repeated_sint32" ), 1));
+ Assert.assertEquals(506L , message.getRepeatedField(f("repeated_sint64" ), 1));
+ Assert.assertEquals(507 , message.getRepeatedField(f("repeated_fixed32" ), 1));
+ Assert.assertEquals(508L , message.getRepeatedField(f("repeated_fixed64" ), 1));
+ Assert.assertEquals(509 , message.getRepeatedField(f("repeated_sfixed32"), 1));
+ Assert.assertEquals(510L , message.getRepeatedField(f("repeated_sfixed64"), 1));
+ Assert.assertEquals(511F , message.getRepeatedField(f("repeated_float" ), 1));
+ Assert.assertEquals(512D , message.getRepeatedField(f("repeated_double" ), 1));
+ Assert.assertEquals(true , message.getRepeatedField(f("repeated_bool" ), 1));
+ Assert.assertEquals("515", message.getRepeatedField(f("repeated_string" ), 1));
+ Assert.assertEquals(toBytes("516"), message.getRepeatedField(f("repeated_bytes"), 1));
+
+ Assert.assertEquals(517,
+ ((Message)message.getRepeatedField(f("repeatedgroup"), 1))
+ .getField(repeatedGroupA));
+ Assert.assertEquals(518,
+ ((Message)message.getRepeatedField(f("repeated_nested_message"), 1))
+ .getField(nestedB));
+ Assert.assertEquals(519,
+ ((Message)message.getRepeatedField(f("repeated_foreign_message"), 1))
+ .getField(foreignC));
+ Assert.assertEquals(520,
+ ((Message)message.getRepeatedField(f("repeated_import_message"), 1))
+ .getField(importD));
+
+ Assert.assertEquals( nestedFoo, message.getRepeatedField(f("repeated_nested_enum" ),1));
+ Assert.assertEquals(foreignFoo, message.getRepeatedField(f("repeated_foreign_enum"),1));
+ Assert.assertEquals( importFoo, message.getRepeatedField(f("repeated_import_enum" ),1));
+
+ Assert.assertEquals("524", message.getRepeatedField(f("repeated_string_piece"), 1));
+ Assert.assertEquals("525", message.getRepeatedField(f("repeated_cord"), 1));
+ }
+
+ public void setPackedFieldsViaReflection(Message.Builder message) {
+ message.addRepeatedField(f("packed_int32" ), 601 );
+ message.addRepeatedField(f("packed_int64" ), 602L);
+ message.addRepeatedField(f("packed_uint32" ), 603 );
+ message.addRepeatedField(f("packed_uint64" ), 604L);
+ message.addRepeatedField(f("packed_sint32" ), 605 );
+ message.addRepeatedField(f("packed_sint64" ), 606L);
+ message.addRepeatedField(f("packed_fixed32" ), 607 );
+ message.addRepeatedField(f("packed_fixed64" ), 608L);
+ message.addRepeatedField(f("packed_sfixed32"), 609 );
+ message.addRepeatedField(f("packed_sfixed64"), 610L);
+ message.addRepeatedField(f("packed_float" ), 611F);
+ message.addRepeatedField(f("packed_double" ), 612D);
+ message.addRepeatedField(f("packed_bool" ), true);
+ message.addRepeatedField(f("packed_enum" ), foreignBar);
+ // Add a second one of each field.
+ message.addRepeatedField(f("packed_int32" ), 701 );
+ message.addRepeatedField(f("packed_int64" ), 702L);
+ message.addRepeatedField(f("packed_uint32" ), 703 );
+ message.addRepeatedField(f("packed_uint64" ), 704L);
+ message.addRepeatedField(f("packed_sint32" ), 705 );
+ message.addRepeatedField(f("packed_sint64" ), 706L);
+ message.addRepeatedField(f("packed_fixed32" ), 707 );
+ message.addRepeatedField(f("packed_fixed64" ), 708L);
+ message.addRepeatedField(f("packed_sfixed32"), 709 );
+ message.addRepeatedField(f("packed_sfixed64"), 710L);
+ message.addRepeatedField(f("packed_float" ), 711F);
+ message.addRepeatedField(f("packed_double" ), 712D);
+ message.addRepeatedField(f("packed_bool" ), false);
+ message.addRepeatedField(f("packed_enum" ), foreignBaz);
+ }
+
+ public void assertPackedFieldsSetViaReflection(Message message) {
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_int64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_uint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sint64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed32" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_fixed64" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed32")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_sfixed64")));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_float" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_double" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_bool" )));
+ Assert.assertEquals(2, message.getRepeatedFieldCount(f("packed_enum" )));
+ Assert.assertEquals(601 , message.getRepeatedField(f("packed_int32" ), 0));
+ Assert.assertEquals(602L , message.getRepeatedField(f("packed_int64" ), 0));
+ Assert.assertEquals(603 , message.getRepeatedField(f("packed_uint32" ), 0));
+ Assert.assertEquals(604L , message.getRepeatedField(f("packed_uint64" ), 0));
+ Assert.assertEquals(605 , message.getRepeatedField(f("packed_sint32" ), 0));
+ Assert.assertEquals(606L , message.getRepeatedField(f("packed_sint64" ), 0));
+ Assert.assertEquals(607 , message.getRepeatedField(f("packed_fixed32" ), 0));
+ Assert.assertEquals(608L , message.getRepeatedField(f("packed_fixed64" ), 0));
+ Assert.assertEquals(609 , message.getRepeatedField(f("packed_sfixed32"), 0));
+ Assert.assertEquals(610L , message.getRepeatedField(f("packed_sfixed64"), 0));
+ Assert.assertEquals(611F , message.getRepeatedField(f("packed_float" ), 0));
+ Assert.assertEquals(612D , message.getRepeatedField(f("packed_double" ), 0));
+ Assert.assertEquals(true , message.getRepeatedField(f("packed_bool" ), 0));
+ Assert.assertEquals(foreignBar, message.getRepeatedField(f("packed_enum" ),0));
+ Assert.assertEquals(701 , message.getRepeatedField(f("packed_int32" ), 1));
+ Assert.assertEquals(702L , message.getRepeatedField(f("packed_int64" ), 1));
+ Assert.assertEquals(703 , message.getRepeatedField(f("packed_uint32" ), 1));
+ Assert.assertEquals(704L , message.getRepeatedField(f("packed_uint64" ), 1));
+ Assert.assertEquals(705 , message.getRepeatedField(f("packed_sint32" ), 1));
+ Assert.assertEquals(706L , message.getRepeatedField(f("packed_sint64" ), 1));
+ Assert.assertEquals(707 , message.getRepeatedField(f("packed_fixed32" ), 1));
+ Assert.assertEquals(708L , message.getRepeatedField(f("packed_fixed64" ), 1));
+ Assert.assertEquals(709 , message.getRepeatedField(f("packed_sfixed32"), 1));
+ Assert.assertEquals(710L , message.getRepeatedField(f("packed_sfixed64"), 1));
+ Assert.assertEquals(711F , message.getRepeatedField(f("packed_float" ), 1));
+ Assert.assertEquals(712D , message.getRepeatedField(f("packed_double" ), 1));
+ Assert.assertEquals(false, message.getRepeatedField(f("packed_bool" ), 1));
+ Assert.assertEquals(foreignBaz, message.getRepeatedField(f("packed_enum" ),1));
+ }
+
+ /**
+ * Verifies that the reflection setters for the given.Builder object throw a
+ * NullPointerException if they are passed a null value. Uses Assert to throw an
+ * appropriate assertion failure, if the condition is not verified.
+ */
+ public void assertReflectionSettersRejectNull(Message.Builder builder)
+ throws Exception {
+ try {
+ builder.setField(f("optional_string"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setField(f("optional_bytes"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setField(f("optional_nested_enum"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setField(f("optional_nested_message"),
+ (TestAllTypes.NestedMessage) null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.setField(f("optional_nested_message"),
+ (TestAllTypes.NestedMessage.Builder) null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ try {
+ builder.addRepeatedField(f("repeated_string"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedField(f("repeated_bytes"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedField(f("repeated_nested_enum"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ try {
+ builder.addRepeatedField(f("repeated_nested_message"), null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
+
+ /**
+ * Verifies that the reflection repeated setters for the given Builder object throw a
+ * NullPointerException if they are passed a null value. Uses Assert to throw an appropriate
+ * assertion failure, if the condition is not verified.
+ */
+ public void assertReflectionRepeatedSettersRejectNull(Message.Builder builder)
+ throws Exception {
+ builder.addRepeatedField(f("repeated_string"), "one");
+ try {
+ builder.setRepeatedField(f("repeated_string"), 0, null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedField(f("repeated_bytes"), toBytes("one"));
+ try {
+ builder.setRepeatedField(f("repeated_bytes"), 0, null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedField(f("repeated_nested_enum"), nestedBaz);
+ try {
+ builder.setRepeatedField(f("repeated_nested_enum"), 0, null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+
+ builder.addRepeatedField(
+ f("repeated_nested_message"),
+ TestAllTypes.NestedMessage.newBuilder().setBb(218).build());
+ try {
+ builder.setRepeatedField(f("repeated_nested_message"), 0, null);
+ Assert.fail("Exception was not thrown");
+ } catch (NullPointerException e) {
+ // We expect this exception.
+ }
+ }
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static String readTextFromFile(String filePath) {
+ return readBytesFromFile(filePath).toStringUtf8();
+ }
+
+ private static File getTestDataDir() {
+ // Search each parent directory looking for "src/google/protobuf".
+ File ancestor = new File(".");
+ try {
+ ancestor = ancestor.getCanonicalFile();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Couldn't get canonical name of working directory.", e);
+ }
+ while (ancestor != null && ancestor.exists()) {
+ if (new File(ancestor, "src/google/protobuf").exists()) {
+ return new File(ancestor, "src/google/protobuf/testdata");
+ }
+ ancestor = ancestor.getParentFile();
+ }
+
+ throw new RuntimeException(
+ "Could not find golden files. This test must be run from within the " +
+ "protobuf source package so that it can read test data files from the " +
+ "C++ source tree.");
+ }
+
+ /**
+ * @param filePath The path relative to
+ * {@link com.google.testing.util.TestUtil#getDefaultSrcDir}.
+ */
+ public static ByteString readBytesFromFile(String filename) {
+ File fullPath = new File(getTestDataDir(), filename);
+ try {
+ RandomAccessFile file = new RandomAccessFile(fullPath, "r");
+ byte[] content = new byte[(int) file.length()];
+ file.readFully(content);
+ return ByteString.copyFrom(content);
+ } catch (IOException e) {
+ // Throw a RuntimeException here so that we can call this function from
+ // static initializers.
+ throw new IllegalArgumentException(
+ "Couldn't read file: " + fullPath.getPath(), e);
+ }
+ }
+
+ /**
+ * Get the bytes of the "golden message". This is a serialized TestAllTypes
+ * with all fields set as they would be by
+ * {@link setAllFields(TestAllTypes.Builder)}, but it is loaded from a file
+ * on disk rather than generated dynamically. The file is actually generated
+ * by C++ code, so testing against it verifies compatibility with C++.
+ */
+ public static ByteString getGoldenMessage() {
+ if (goldenMessage == null) {
+ goldenMessage = readBytesFromFile("golden_message");
+ }
+ return goldenMessage;
+ }
+ private static ByteString goldenMessage = null;
+
+ /**
+ * Get the bytes of the "golden packed fields message". This is a serialized
+ * TestPackedTypes with all fields set as they would be by
+ * {@link setPackedFields(TestPackedTypes.Builder)}, but it is loaded from a
+ * file on disk rather than generated dynamically. The file is actually
+ * generated by C++ code, so testing against it verifies compatibility with
+ * C++.
+ */
+ public static ByteString getGoldenPackedFieldsMessage() {
+ if (goldenPackedFieldsMessage == null) {
+ goldenPackedFieldsMessage =
+ readBytesFromFile("golden_packed_fields_message");
+ }
+ return goldenPackedFieldsMessage;
+ }
+ private static ByteString goldenPackedFieldsMessage = null;
+}
diff --git a/java/src/test/java/com/google/protobuf/TextFormatTest.java b/java/src/test/java/com/google/protobuf/TextFormatTest.java
new file mode 100644
index 0000000..1d73165
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/TextFormatTest.java
@@ -0,0 +1,636 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import com.google.protobuf.Descriptors.FieldDescriptor;
+import protobuf_unittest.UnittestProto.OneString;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+
+/**
+ * Test case for {@link TextFormat}.
+ *
+ * TODO(wenboz): ExtensionTest and rest of text_format_unittest.cc.
+ *
+ * @author wenboz@google.com (Wenbo Zhu)
+ */
+public class TextFormatTest extends TestCase {
+
+ // A basic string with different escapable characters for testing.
+ private final static String kEscapeTestString =
+ "\"A string with ' characters \n and \r newlines and \t tabs and \001 "
+ + "slashes \\";
+
+ // A representation of the above string with all the characters escaped.
+ private final static String kEscapeTestStringEscaped =
+ "\"\\\"A string with \\' characters \\n and \\r newlines "
+ + "and \\t tabs and \\001 slashes \\\\\"";
+
+ private static String allFieldsSetText = TestUtil.readTextFromFile(
+ "text_format_unittest_data.txt");
+ private static String allExtensionsSetText = TestUtil.readTextFromFile(
+ "text_format_unittest_extensions_data.txt");
+
+ private String exoticText =
+ "repeated_int32: -1\n" +
+ "repeated_int32: -2147483648\n" +
+ "repeated_int64: -1\n" +
+ "repeated_int64: -9223372036854775808\n" +
+ "repeated_uint32: 4294967295\n" +
+ "repeated_uint32: 2147483648\n" +
+ "repeated_uint64: 18446744073709551615\n" +
+ "repeated_uint64: 9223372036854775808\n" +
+ "repeated_double: 123.0\n" +
+ "repeated_double: 123.5\n" +
+ "repeated_double: 0.125\n" +
+ "repeated_double: 1.23E17\n" +
+ "repeated_double: 1.235E22\n" +
+ "repeated_double: 1.235E-18\n" +
+ "repeated_double: 123.456789\n" +
+ "repeated_double: Infinity\n" +
+ "repeated_double: -Infinity\n" +
+ "repeated_double: NaN\n" +
+ "repeated_string: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"" +
+ "\\341\\210\\264\"\n" +
+ "repeated_bytes: \"\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"\\376\"\n";
+
+ private String messageSetText =
+ "[protobuf_unittest.TestMessageSetExtension1] {\n" +
+ " i: 123\n" +
+ "}\n" +
+ "[protobuf_unittest.TestMessageSetExtension2] {\n" +
+ " str: \"foo\"\n" +
+ "}\n";
+
+ /** Print TestAllTypes and compare with golden file. */
+ public void testPrintMessage() throws Exception {
+ String javaText = TextFormat.printToString(TestUtil.getAllSet());
+
+ // Java likes to add a trailing ".0" to floats and doubles. C printf
+ // (with %g format) does not. Our golden files are used for both
+ // C++ and Java TextFormat classes, so we need to conform.
+ javaText = javaText.replace(".0\n", "\n");
+
+ assertEquals(allFieldsSetText, javaText);
+ }
+
+ /** Print TestAllExtensions and compare with golden file. */
+ public void testPrintExtensions() throws Exception {
+ String javaText = TextFormat.printToString(TestUtil.getAllExtensionsSet());
+
+ // Java likes to add a trailing ".0" to floats and doubles. C printf
+ // (with %g format) does not. Our golden files are used for both
+ // C++ and Java TextFormat classes, so we need to conform.
+ javaText = javaText.replace(".0\n", "\n");
+
+ assertEquals(allExtensionsSetText, javaText);
+ }
+
+ public void testPrintUnknownFields() throws Exception {
+ // Test printing of unknown fields in a message.
+
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(5,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1)
+ .addFixed32(2)
+ .addFixed64(3)
+ .addLengthDelimited(ByteString.copyFromUtf8("4"))
+ .addGroup(
+ UnknownFieldSet.newBuilder()
+ .addField(10,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(5)
+ .build())
+ .build())
+ .build())
+ .addField(8,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1)
+ .addVarint(2)
+ .addVarint(3)
+ .build())
+ .addField(15,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(0xABCDEF1234567890L)
+ .addFixed32(0xABCD1234)
+ .addFixed64(0xABCDEF1234567890L)
+ .build())
+ .build())
+ .build();
+
+ assertEquals(
+ "5: 1\n" +
+ "5: 0x00000002\n" +
+ "5: 0x0000000000000003\n" +
+ "5: \"4\"\n" +
+ "5 {\n" +
+ " 10: 5\n" +
+ "}\n" +
+ "8: 1\n" +
+ "8: 2\n" +
+ "8: 3\n" +
+ "15: 12379813812177893520\n" +
+ "15: 0xabcd1234\n" +
+ "15: 0xabcdef1234567890\n",
+ TextFormat.printToString(message));
+ }
+
+ public void testPrintField() throws Exception {
+ final FieldDescriptor dataField =
+ OneString.getDescriptor().findFieldByName("data");
+ assertEquals(
+ "data: \"test data\"\n",
+ TextFormat.printFieldToString(dataField, "test data"));
+
+ final FieldDescriptor optionalField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_message");
+ final Object value = NestedMessage.newBuilder().setBb(42).build();
+
+ assertEquals(
+ "optional_nested_message {\n bb: 42\n}\n",
+ TextFormat.printFieldToString(optionalField, value));
+ }
+
+ /**
+ * Helper to construct a ByteString from a String containing only 8-bit
+ * characters. The characters are converted directly to bytes, *not*
+ * encoded using UTF-8.
+ */
+ private ByteString bytes(String str) throws Exception {
+ return ByteString.copyFrom(str.getBytes("ISO-8859-1"));
+ }
+
+ /**
+ * Helper to construct a ByteString from a bunch of bytes. The inputs are
+ * actually ints so that I can use hex notation and not get stupid errors
+ * about precision.
+ */
+ private ByteString bytes(int... bytesAsInts) {
+ byte[] bytes = new byte[bytesAsInts.length];
+ for (int i = 0; i < bytesAsInts.length; i++) {
+ bytes[i] = (byte) bytesAsInts[i];
+ }
+ return ByteString.copyFrom(bytes);
+ }
+
+ public void testPrintExotic() throws Exception {
+ Message message = TestAllTypes.newBuilder()
+ // Signed vs. unsigned numbers.
+ .addRepeatedInt32 (-1)
+ .addRepeatedUint32(-1)
+ .addRepeatedInt64 (-1)
+ .addRepeatedUint64(-1)
+
+ .addRepeatedInt32 (1 << 31)
+ .addRepeatedUint32(1 << 31)
+ .addRepeatedInt64 (1l << 63)
+ .addRepeatedUint64(1l << 63)
+
+ // Floats of various precisions and exponents.
+ .addRepeatedDouble(123)
+ .addRepeatedDouble(123.5)
+ .addRepeatedDouble(0.125)
+ .addRepeatedDouble(123e15)
+ .addRepeatedDouble(123.5e20)
+ .addRepeatedDouble(123.5e-20)
+ .addRepeatedDouble(123.456789)
+ .addRepeatedDouble(Double.POSITIVE_INFINITY)
+ .addRepeatedDouble(Double.NEGATIVE_INFINITY)
+ .addRepeatedDouble(Double.NaN)
+
+ // Strings and bytes that needing escaping.
+ .addRepeatedString("\0\001\007\b\f\n\r\t\013\\\'\"\u1234")
+ .addRepeatedBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe"))
+ .build();
+
+ assertEquals(exoticText, message.toString());
+ }
+
+ public void testPrintMessageSet() throws Exception {
+ TestMessageSet messageSet =
+ TestMessageSet.newBuilder()
+ .setExtension(
+ TestMessageSetExtension1.messageSetExtension,
+ TestMessageSetExtension1.newBuilder().setI(123).build())
+ .setExtension(
+ TestMessageSetExtension2.messageSetExtension,
+ TestMessageSetExtension2.newBuilder().setStr("foo").build())
+ .build();
+
+ assertEquals(messageSetText, messageSet.toString());
+ }
+
+ // =================================================================
+
+ public void testParse() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(allFieldsSetText, builder);
+ TestUtil.assertAllFieldsSet(builder.build());
+ }
+
+ public void testParseReader() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(new StringReader(allFieldsSetText), builder);
+ TestUtil.assertAllFieldsSet(builder.build());
+ }
+
+ public void testParseExtensions() throws Exception {
+ TestAllExtensions.Builder builder = TestAllExtensions.newBuilder();
+ TextFormat.merge(allExtensionsSetText,
+ TestUtil.getExtensionRegistry(),
+ builder);
+ TestUtil.assertAllExtensionsSet(builder.build());
+ }
+
+ public void testParseCompatibility() throws Exception {
+ String original = "repeated_float: inf\n" +
+ "repeated_float: -inf\n" +
+ "repeated_float: nan\n" +
+ "repeated_float: inff\n" +
+ "repeated_float: -inff\n" +
+ "repeated_float: nanf\n" +
+ "repeated_float: 1.0f\n" +
+ "repeated_float: infinityf\n" +
+ "repeated_float: -Infinityf\n" +
+ "repeated_double: infinity\n" +
+ "repeated_double: -infinity\n" +
+ "repeated_double: nan\n";
+ String canonical = "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_float: NaN\n" +
+ "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_float: NaN\n" +
+ "repeated_float: 1.0\n" +
+ "repeated_float: Infinity\n" +
+ "repeated_float: -Infinity\n" +
+ "repeated_double: Infinity\n" +
+ "repeated_double: -Infinity\n" +
+ "repeated_double: NaN\n";
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(original, builder);
+ assertEquals(canonical, builder.build().toString());
+ }
+
+ public void testParseExotic() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(exoticText, builder);
+
+ // Too lazy to check things individually. Don't try to debug this
+ // if testPrintExotic() is failing.
+ assertEquals(exoticText, builder.build().toString());
+ }
+
+ public void testParseMessageSet() throws Exception {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+ extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+ TestMessageSet.Builder builder = TestMessageSet.newBuilder();
+ TextFormat.merge(messageSetText, extensionRegistry, builder);
+ TestMessageSet messageSet = builder.build();
+
+ assertTrue(messageSet.hasExtension(
+ TestMessageSetExtension1.messageSetExtension));
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ assertTrue(messageSet.hasExtension(
+ TestMessageSetExtension2.messageSetExtension));
+ assertEquals("foo", messageSet.getExtension(
+ TestMessageSetExtension2.messageSetExtension).getStr());
+ }
+
+ public void testParseNumericEnum() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("optional_nested_enum: 2", builder);
+ assertEquals(TestAllTypes.NestedEnum.BAR, builder.getOptionalNestedEnum());
+ }
+
+ public void testParseAngleBrackets() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("OptionalGroup: < a: 1 >", builder);
+ assertTrue(builder.hasOptionalGroup());
+ assertEquals(1, builder.getOptionalGroup().getA());
+ }
+
+ public void testParseComment() throws Exception {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge(
+ "# this is a comment\n" +
+ "optional_int32: 1 # another comment\n" +
+ "optional_int64: 2\n" +
+ "# EOF comment", builder);
+ assertEquals(1, builder.getOptionalInt32());
+ assertEquals(2, builder.getOptionalInt64());
+ }
+
+ private void assertParseError(String error, String text) {
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ try {
+ TextFormat.merge(text, TestUtil.getExtensionRegistry(), builder);
+ fail("Expected parse exception.");
+ } catch (TextFormat.ParseException e) {
+ assertEquals(error, e.getMessage());
+ }
+ }
+
+ public void testParseErrors() throws Exception {
+ assertParseError(
+ "1:16: Expected \":\".",
+ "optional_int32 123");
+ assertParseError(
+ "1:23: Expected identifier.",
+ "optional_nested_enum: ?");
+ assertParseError(
+ "1:18: Couldn't parse integer: Number must be positive: -1",
+ "optional_uint32: -1");
+ assertParseError(
+ "1:17: Couldn't parse integer: Number out of range for 32-bit signed " +
+ "integer: 82301481290849012385230157",
+ "optional_int32: 82301481290849012385230157");
+ assertParseError(
+ "1:16: Expected \"true\" or \"false\".",
+ "optional_bool: maybe");
+ assertParseError(
+ "1:18: Expected string.",
+ "optional_string: 123");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe\n" +
+ "optional_int32: 123");
+ assertParseError(
+ "1:18: Invalid escape sequence: '\\z'",
+ "optional_string: \"\\z\"");
+ assertParseError(
+ "1:18: String missing ending quote.",
+ "optional_string: \"ueoauaoe\n" +
+ "optional_int32: 123");
+ assertParseError(
+ "1:2: Extension \"nosuchext\" not found in the ExtensionRegistry.",
+ "[nosuchext]: 123");
+ assertParseError(
+ "1:20: Extension \"protobuf_unittest.optional_int32_extension\" does " +
+ "not extend message type \"protobuf_unittest.TestAllTypes\".",
+ "[protobuf_unittest.optional_int32_extension]: 123");
+ assertParseError(
+ "1:1: Message type \"protobuf_unittest.TestAllTypes\" has no field " +
+ "named \"nosuchfield\".",
+ "nosuchfield: 123");
+ assertParseError(
+ "1:21: Expected \">\".",
+ "OptionalGroup < a: 1");
+ assertParseError(
+ "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+ "value named \"NO_SUCH_VALUE\".",
+ "optional_nested_enum: NO_SUCH_VALUE");
+ assertParseError(
+ "1:23: Enum type \"protobuf_unittest.TestAllTypes.NestedEnum\" has no " +
+ "value with number 123.",
+ "optional_nested_enum: 123");
+
+ // Delimiters must match.
+ assertParseError(
+ "1:22: Expected identifier.",
+ "OptionalGroup < a: 1 }");
+ assertParseError(
+ "1:22: Expected identifier.",
+ "OptionalGroup { a: 1 >");
+ }
+
+ // =================================================================
+
+ public void testEscape() throws Exception {
+ // Escape sequences.
+ assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
+ TextFormat.escapeBytes(bytes("\0\001\007\b\f\n\r\t\013\\\'\"")));
+ assertEquals("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\"",
+ TextFormat.escapeText("\0\001\007\b\f\n\r\t\013\\\'\""));
+ assertEquals(bytes("\0\001\007\b\f\n\r\t\013\\\'\""),
+ TextFormat.unescapeBytes("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+ assertEquals("\0\001\007\b\f\n\r\t\013\\\'\"",
+ TextFormat.unescapeText("\\000\\001\\a\\b\\f\\n\\r\\t\\v\\\\\\'\\\""));
+
+ // Unicode handling.
+ assertEquals("\\341\\210\\264", TextFormat.escapeText("\u1234"));
+ assertEquals("\\341\\210\\264",
+ TextFormat.escapeBytes(bytes(0xe1, 0x88, 0xb4)));
+ assertEquals("\u1234", TextFormat.unescapeText("\\341\\210\\264"));
+ assertEquals(bytes(0xe1, 0x88, 0xb4),
+ TextFormat.unescapeBytes("\\341\\210\\264"));
+ assertEquals("\u1234", TextFormat.unescapeText("\\xe1\\x88\\xb4"));
+ assertEquals(bytes(0xe1, 0x88, 0xb4),
+ TextFormat.unescapeBytes("\\xe1\\x88\\xb4"));
+
+ // Errors.
+ try {
+ TextFormat.unescapeText("\\x");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequenceException e) {
+ // success
+ }
+
+ try {
+ TextFormat.unescapeText("\\z");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequenceException e) {
+ // success
+ }
+
+ try {
+ TextFormat.unescapeText("\\");
+ fail("Should have thrown an exception.");
+ } catch (TextFormat.InvalidEscapeSequenceException e) {
+ // success
+ }
+ }
+
+ public void testParseInteger() throws Exception {
+ assertEquals( 0, TextFormat.parseInt32( "0"));
+ assertEquals( 1, TextFormat.parseInt32( "1"));
+ assertEquals( -1, TextFormat.parseInt32( "-1"));
+ assertEquals( 12345, TextFormat.parseInt32( "12345"));
+ assertEquals( -12345, TextFormat.parseInt32( "-12345"));
+ assertEquals( 2147483647, TextFormat.parseInt32( "2147483647"));
+ assertEquals(-2147483648, TextFormat.parseInt32("-2147483648"));
+
+ assertEquals( 0, TextFormat.parseUInt32( "0"));
+ assertEquals( 1, TextFormat.parseUInt32( "1"));
+ assertEquals( 12345, TextFormat.parseUInt32( "12345"));
+ assertEquals( 2147483647, TextFormat.parseUInt32("2147483647"));
+ assertEquals((int) 2147483648L, TextFormat.parseUInt32("2147483648"));
+ assertEquals((int) 4294967295L, TextFormat.parseUInt32("4294967295"));
+
+ assertEquals( 0L, TextFormat.parseInt64( "0"));
+ assertEquals( 1L, TextFormat.parseInt64( "1"));
+ assertEquals( -1L, TextFormat.parseInt64( "-1"));
+ assertEquals( 12345L, TextFormat.parseInt64( "12345"));
+ assertEquals( -12345L, TextFormat.parseInt64( "-12345"));
+ assertEquals( 2147483647L, TextFormat.parseInt64( "2147483647"));
+ assertEquals(-2147483648L, TextFormat.parseInt64("-2147483648"));
+ assertEquals( 4294967295L, TextFormat.parseInt64( "4294967295"));
+ assertEquals( 4294967296L, TextFormat.parseInt64( "4294967296"));
+ assertEquals(9223372036854775807L,
+ TextFormat.parseInt64("9223372036854775807"));
+ assertEquals(-9223372036854775808L,
+ TextFormat.parseInt64("-9223372036854775808"));
+
+ assertEquals( 0L, TextFormat.parseUInt64( "0"));
+ assertEquals( 1L, TextFormat.parseUInt64( "1"));
+ assertEquals( 12345L, TextFormat.parseUInt64( "12345"));
+ assertEquals( 2147483647L, TextFormat.parseUInt64( "2147483647"));
+ assertEquals( 4294967295L, TextFormat.parseUInt64( "4294967295"));
+ assertEquals( 4294967296L, TextFormat.parseUInt64( "4294967296"));
+ assertEquals(9223372036854775807L,
+ TextFormat.parseUInt64("9223372036854775807"));
+ assertEquals(-9223372036854775808L,
+ TextFormat.parseUInt64("9223372036854775808"));
+ assertEquals(-1L, TextFormat.parseUInt64("18446744073709551615"));
+
+ // Hex
+ assertEquals(0x1234abcd, TextFormat.parseInt32("0x1234abcd"));
+ assertEquals(-0x1234abcd, TextFormat.parseInt32("-0x1234abcd"));
+ assertEquals(-1, TextFormat.parseUInt64("0xffffffffffffffff"));
+ assertEquals(0x7fffffffffffffffL,
+ TextFormat.parseInt64("0x7fffffffffffffff"));
+
+ // Octal
+ assertEquals(01234567, TextFormat.parseInt32("01234567"));
+
+ // Out-of-range
+ try {
+ TextFormat.parseInt32("2147483648");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt32("-2147483649");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt32("4294967296");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt32("-1");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt64("9223372036854775808");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseInt64("-9223372036854775809");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt64("18446744073709551616");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ try {
+ TextFormat.parseUInt64("-1");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+
+ // Not a number.
+ try {
+ TextFormat.parseInt32("abcd");
+ fail("Should have thrown an exception.");
+ } catch (NumberFormatException e) {
+ // success
+ }
+ }
+
+ public void testParseLongString() throws Exception {
+ String longText =
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890" +
+ "123456789012345678901234567890123456789012345678901234567890";
+
+ TestAllTypes.Builder builder = TestAllTypes.newBuilder();
+ TextFormat.merge("optional_string: \"" + longText + "\"", builder);
+ assertEquals(longText, builder.getOptionalString());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
new file mode 100644
index 0000000..ea088b3
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
@@ -0,0 +1,437 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestEmptyMessage;
+import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Tests related to unknown field handling.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class UnknownFieldSetTest extends TestCase {
+ public void setUp() throws Exception {
+ descriptor = TestAllTypes.getDescriptor();
+ allFields = TestUtil.getAllSet();
+ allFieldsData = allFields.toByteString();
+ emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
+ unknownFields = emptyMessage.getUnknownFields();
+ }
+
+ UnknownFieldSet.Field getField(String name) {
+ Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
+ assertNotNull(field);
+ return unknownFields.getField(field.getNumber());
+ }
+
+ // Constructs a protocol buffer which contains fields with all the same
+ // numbers as allFieldsData except that each field is some other wire
+ // type.
+ ByteString getBizarroData() throws Exception {
+ UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
+
+ UnknownFieldSet.Field varintField =
+ UnknownFieldSet.Field.newBuilder().addVarint(1).build();
+ UnknownFieldSet.Field fixed32Field =
+ UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
+
+ for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
+ unknownFields.asMap().entrySet()) {
+ if (entry.getValue().getVarintList().isEmpty()) {
+ // Original field is not a varint, so use a varint.
+ bizarroFields.addField(entry.getKey(), varintField);
+ } else {
+ // Original field *is* a varint, so use something else.
+ bizarroFields.addField(entry.getKey(), fixed32Field);
+ }
+ }
+
+ return bizarroFields.build().toByteString();
+ }
+
+ Descriptors.Descriptor descriptor;
+ TestAllTypes allFields;
+ ByteString allFieldsData;
+
+ // An empty message that has been parsed from allFieldsData. So, it has
+ // unknown fields of every type.
+ TestEmptyMessage emptyMessage;
+ UnknownFieldSet unknownFields;
+
+ // =================================================================
+
+ public void testVarint() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_int32");
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(allFields.getOptionalInt32(),
+ (long) field.getVarintList().get(0));
+ }
+
+ public void testFixed32() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_fixed32");
+ assertEquals(1, field.getFixed32List().size());
+ assertEquals(allFields.getOptionalFixed32(),
+ (int) field.getFixed32List().get(0));
+ }
+
+ public void testFixed64() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_fixed64");
+ assertEquals(1, field.getFixed64List().size());
+ assertEquals(allFields.getOptionalFixed64(),
+ (long) field.getFixed64List().get(0));
+ }
+
+ public void testLengthDelimited() throws Exception {
+ UnknownFieldSet.Field field = getField("optional_bytes");
+ assertEquals(1, field.getLengthDelimitedList().size());
+ assertEquals(allFields.getOptionalBytes(),
+ field.getLengthDelimitedList().get(0));
+ }
+
+ public void testGroup() throws Exception {
+ Descriptors.FieldDescriptor nestedFieldDescriptor =
+ TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
+ assertNotNull(nestedFieldDescriptor);
+
+ UnknownFieldSet.Field field = getField("optionalgroup");
+ assertEquals(1, field.getGroupList().size());
+
+ UnknownFieldSet group = field.getGroupList().get(0);
+ assertEquals(1, group.asMap().size());
+ assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
+
+ UnknownFieldSet.Field nestedField =
+ group.getField(nestedFieldDescriptor.getNumber());
+ assertEquals(1, nestedField.getVarintList().size());
+ assertEquals(allFields.getOptionalGroup().getA(),
+ (long) nestedField.getVarintList().get(0));
+ }
+
+ public void testSerialize() throws Exception {
+ // Check that serializing the UnknownFieldSet produces the original data
+ // again.
+ ByteString data = emptyMessage.toByteString();
+ assertEquals(allFieldsData, data);
+ }
+
+ public void testCopyFrom() throws Exception {
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
+
+ assertEquals(emptyMessage.toString(), message.toString());
+ }
+
+ public void testMergeFrom() throws Exception {
+ TestEmptyMessage source =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(2,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(2).build())
+ .addField(3,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(4).build())
+ .build())
+ .build();
+ TestEmptyMessage destination =
+ TestEmptyMessage.newBuilder()
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(1,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1).build())
+ .addField(3,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(3).build())
+ .build())
+ .mergeFrom(source)
+ .build();
+
+ assertEquals(
+ "1: 1\n" +
+ "2: 2\n" +
+ "3: 3\n" +
+ "3: 4\n",
+ destination.toString());
+ }
+
+ public void testClear() throws Exception {
+ UnknownFieldSet fields =
+ UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
+ assertTrue(fields.asMap().isEmpty());
+ }
+
+ public void testClearMessage() throws Exception {
+ TestEmptyMessage message =
+ TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
+ assertEquals(0, message.getSerializedSize());
+ }
+
+ public void testParseKnownAndUnknown() throws Exception {
+ // Test mixing known and unknown fields when parsing.
+
+ UnknownFieldSet fields =
+ UnknownFieldSet.newBuilder(unknownFields)
+ .addField(123456,
+ UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
+ .build();
+
+ ByteString data = fields.toByteString();
+ TestAllTypes destination = TestAllTypes.parseFrom(data);
+
+ TestUtil.assertAllFieldsSet(destination);
+ assertEquals(1, destination.getUnknownFields().asMap().size());
+
+ UnknownFieldSet.Field field =
+ destination.getUnknownFields().getField(123456);
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(654321, (long) field.getVarintList().get(0));
+ }
+
+ public void testWrongTypeTreatedAsUnknown() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
+ TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the debug strings
+ // should be the same.
+ assertEquals(emptyMessage.toString(), allTypesMessage.toString());
+ }
+
+ public void testUnknownExtensions() throws Exception {
+ // Make sure fields are properly parsed to the UnknownFieldSet even when
+ // they are declared as extension numbers.
+
+ TestEmptyMessageWithExtensions message =
+ TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
+
+ assertEquals(unknownFields.asMap().size(),
+ message.getUnknownFields().asMap().size());
+ assertEquals(allFieldsData, message.toByteString());
+ }
+
+ public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
+ // Test that fields of the wrong wire type are treated like unknown fields
+ // when parsing extensions.
+
+ ByteString bizarroData = getBizarroData();
+ TestAllExtensions allExtensionsMessage =
+ TestAllExtensions.parseFrom(bizarroData);
+ TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
+
+ // All fields should have been interpreted as unknown, so the debug strings
+ // should be the same.
+ assertEquals(emptyMessage.toString(),
+ allExtensionsMessage.toString());
+ }
+
+ public void testParseUnknownEnumValue() throws Exception {
+ Descriptors.FieldDescriptor singularField =
+ TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
+ Descriptors.FieldDescriptor repeatedField =
+ TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
+ assertNotNull(singularField);
+ assertNotNull(repeatedField);
+
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(singularField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
+ .addVarint(5) // not valid
+ .build())
+ .addField(repeatedField.getNumber(),
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
+ .addVarint(4) // not valid
+ .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
+ .addVarint(6) // not valid
+ .build())
+ .build()
+ .toByteString();
+
+ {
+ TestAllTypes message = TestAllTypes.parseFrom(data);
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getOptionalNestedEnum());
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getRepeatedNestedEnumList());
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+
+ {
+ TestAllExtensions message =
+ TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
+ assertEquals(TestAllTypes.NestedEnum.BAR,
+ message.getExtension(UnittestProto.optionalNestedEnumExtension));
+ assertEquals(
+ Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
+ message.getExtension(UnittestProto.repeatedNestedEnumExtension));
+ assertEquals(Arrays.asList(5L),
+ message.getUnknownFields()
+ .getField(singularField.getNumber())
+ .getVarintList());
+ assertEquals(Arrays.asList(4L, 6L),
+ message.getUnknownFields()
+ .getField(repeatedField.getNumber())
+ .getVarintList());
+ }
+ }
+
+ public void testLargeVarint() throws Exception {
+ ByteString data =
+ UnknownFieldSet.newBuilder()
+ .addField(1,
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(0x7FFFFFFFFFFFFFFFL)
+ .build())
+ .build()
+ .toByteString();
+ UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
+ UnknownFieldSet.Field field = parsed.getField(1);
+ assertEquals(1, field.getVarintList().size());
+ assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
+ }
+
+ public void testEqualsAndHashCode() {
+ UnknownFieldSet.Field fixed32Field =
+ UnknownFieldSet.Field.newBuilder()
+ .addFixed32(1)
+ .build();
+ UnknownFieldSet.Field fixed64Field =
+ UnknownFieldSet.Field.newBuilder()
+ .addFixed64(1)
+ .build();
+ UnknownFieldSet.Field varIntField =
+ UnknownFieldSet.Field.newBuilder()
+ .addVarint(1)
+ .build();
+ UnknownFieldSet.Field lengthDelimitedField =
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(ByteString.EMPTY)
+ .build();
+ UnknownFieldSet.Field groupField =
+ UnknownFieldSet.Field.newBuilder()
+ .addGroup(unknownFields)
+ .build();
+
+ UnknownFieldSet a =
+ UnknownFieldSet.newBuilder()
+ .addField(1, fixed32Field)
+ .build();
+ UnknownFieldSet b =
+ UnknownFieldSet.newBuilder()
+ .addField(1, fixed64Field)
+ .build();
+ UnknownFieldSet c =
+ UnknownFieldSet.newBuilder()
+ .addField(1, varIntField)
+ .build();
+ UnknownFieldSet d =
+ UnknownFieldSet.newBuilder()
+ .addField(1, lengthDelimitedField)
+ .build();
+ UnknownFieldSet e =
+ UnknownFieldSet.newBuilder()
+ .addField(1, groupField)
+ .build();
+
+ checkEqualsIsConsistent(a);
+ checkEqualsIsConsistent(b);
+ checkEqualsIsConsistent(c);
+ checkEqualsIsConsistent(d);
+ checkEqualsIsConsistent(e);
+
+ checkNotEqual(a, b);
+ checkNotEqual(a, c);
+ checkNotEqual(a, d);
+ checkNotEqual(a, e);
+ checkNotEqual(b, c);
+ checkNotEqual(b, d);
+ checkNotEqual(b, e);
+ checkNotEqual(c, d);
+ checkNotEqual(c, e);
+ checkNotEqual(d, e);
+ }
+
+ /**
+ * Asserts that the given field sets are not equal and have different
+ * hash codes.
+ *
+ * @warning It's valid for non-equal objects to have the same hash code, so
+ * this test is stricter than it needs to be. However, this should happen
+ * relatively rarely.
+ */
+ private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
+ String equalsError = String.format("%s should not be equal to %s", s1, s2);
+ assertFalse(equalsError, s1.equals(s2));
+ assertFalse(equalsError, s2.equals(s1));
+
+ assertFalse(
+ String.format("%s should have a different hash code from %s", s1, s2),
+ s1.hashCode() == s2.hashCode());
+ }
+
+ /**
+ * Asserts that the given field sets are equal and have identical hash codes.
+ */
+ private void checkEqualsIsConsistent(UnknownFieldSet set) {
+ // Object should be equal to itself.
+ assertEquals(set, set);
+
+ // Object should be equal to a copy of itself.
+ UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
+ assertEquals(set, copy);
+ assertEquals(copy, set);
+ assertEquals(set.hashCode(), copy.hashCode());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/WireFormatTest.java b/java/src/test/java/com/google/protobuf/WireFormatTest.java
new file mode 100644
index 0000000..bd1c6db
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/WireFormatTest.java
@@ -0,0 +1,402 @@
+// 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 junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import protobuf_unittest.UnittestProto;
+import protobuf_unittest.UnittestProto.TestAllExtensions;
+import protobuf_unittest.UnittestProto.TestAllTypes;
+import protobuf_unittest.UnittestProto.TestFieldOrderings;
+import protobuf_unittest.UnittestProto.TestPackedExtensions;
+import protobuf_unittest.UnittestProto.TestPackedTypes;
+import protobuf_unittest.UnittestMset.TestMessageSet;
+import protobuf_unittest.UnittestMset.RawMessageSet;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension1;
+import protobuf_unittest.UnittestMset.TestMessageSetExtension2;
+import com.google.protobuf.UnittestLite.TestAllExtensionsLite;
+import com.google.protobuf.UnittestLite.TestPackedExtensionsLite;
+
+/**
+ * Tests related to parsing and serialization.
+ *
+ * @author kenton@google.com (Kenton Varda)
+ */
+public class WireFormatTest extends TestCase {
+ public void testSerialization() throws Exception {
+ TestAllTypes message = TestUtil.getAllSet();
+
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ public void testSerializationPacked() throws Exception {
+ TestPackedTypes message = TestUtil.getPackedSet();
+
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes);
+
+ TestUtil.assertPackedFieldsSet(message2);
+ }
+
+ public void testSerializeExtensions() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+ // it should work.
+
+ TestAllExtensions message = TestUtil.getAllExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ public void testSerializePackedExtensions() throws Exception {
+ // TestPackedTypes and TestPackedExtensions should have compatible wire
+ // formats; check that they serialize to the same string.
+ TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+
+ TestPackedTypes message2 = TestUtil.getPackedSet();
+ ByteString rawBytes2 = message2.toByteString();
+
+ assertEquals(rawBytes, rawBytes2);
+ }
+
+ public void testSerializeExtensionsLite() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serialize a TestAllExtensions then parse it as TestAllTypes
+ // it should work.
+
+ TestAllExtensionsLite message = TestUtil.getAllLiteExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+ assertEquals(rawBytes.size(), message.getSerializedSize());
+
+ TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
+
+ TestUtil.assertAllFieldsSet(message2);
+ }
+
+ public void testSerializePackedExtensionsLite() throws Exception {
+ // TestPackedTypes and TestPackedExtensions should have compatible wire
+ // formats; check that they serialize to the same string.
+ TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+
+ TestPackedTypes message2 = TestUtil.getPackedSet();
+ ByteString rawBytes2 = message2.toByteString();
+
+ assertEquals(rawBytes, rawBytes2);
+ }
+
+ public void testParseExtensions() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+ // it should work.
+
+ TestAllTypes message = TestUtil.getAllSet();
+ ByteString rawBytes = message.toByteString();
+
+ ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+ TestAllExtensions message2 =
+ TestAllExtensions.parseFrom(rawBytes, registry);
+
+ TestUtil.assertAllExtensionsSet(message2);
+ }
+
+ public void testParsePackedExtensions() throws Exception {
+ // Ensure that packed extensions can be properly parsed.
+ TestPackedExtensions message = TestUtil.getPackedExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+
+ ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+ TestPackedExtensions message2 =
+ TestPackedExtensions.parseFrom(rawBytes, registry);
+
+ TestUtil.assertPackedExtensionsSet(message2);
+ }
+
+ public void testParseExtensionsLite() throws Exception {
+ // TestAllTypes and TestAllExtensions should have compatible wire formats,
+ // so if we serialize a TestAllTypes then parse it as TestAllExtensions
+ // it should work.
+
+ TestAllTypes message = TestUtil.getAllSet();
+ ByteString rawBytes = message.toByteString();
+
+ ExtensionRegistryLite registry_lite = TestUtil.getExtensionRegistryLite();
+
+ TestAllExtensionsLite message2 =
+ TestAllExtensionsLite.parseFrom(rawBytes, registry_lite);
+
+ TestUtil.assertAllExtensionsSet(message2);
+
+ // Try again using a full extension registry.
+ ExtensionRegistry registry = TestUtil.getExtensionRegistry();
+
+ TestAllExtensionsLite message3 =
+ TestAllExtensionsLite.parseFrom(rawBytes, registry);
+
+ TestUtil.assertAllExtensionsSet(message3);
+ }
+
+ public void testParsePackedExtensionsLite() throws Exception {
+ // Ensure that packed extensions can be properly parsed.
+ TestPackedExtensionsLite message = TestUtil.getLitePackedExtensionsSet();
+ ByteString rawBytes = message.toByteString();
+
+ ExtensionRegistryLite registry = TestUtil.getExtensionRegistryLite();
+
+ TestPackedExtensionsLite message2 =
+ TestPackedExtensionsLite.parseFrom(rawBytes, registry);
+
+ TestUtil.assertPackedExtensionsSet(message2);
+ }
+
+ public void testExtensionsSerializedSize() throws Exception {
+ assertEquals(TestUtil.getAllSet().getSerializedSize(),
+ TestUtil.getAllExtensionsSet().getSerializedSize());
+ }
+
+ public void testSerializeDelimited() throws Exception {
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ TestUtil.getAllSet().writeDelimitedTo(output);
+ output.write(12);
+ TestUtil.getPackedSet().writeDelimitedTo(output);
+ output.write(34);
+
+ ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray());
+
+ TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input));
+ assertEquals(12, input.read());
+ TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input));
+ assertEquals(34, input.read());
+ assertEquals(-1, input.read());
+ }
+
+ private void assertFieldsInOrder(ByteString data) throws Exception {
+ CodedInputStream input = data.newCodedInput();
+ int previousTag = 0;
+
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+
+ assertTrue(tag > previousTag);
+ previousTag = tag;
+ input.skipField(tag);
+ }
+ }
+
+ public void testInterleavedFieldsAndExtensions() throws Exception {
+ // Tests that fields are written in order even when extension ranges
+ // are interleaved with field numbers.
+ ByteString data =
+ TestFieldOrderings.newBuilder()
+ .setMyInt(1)
+ .setMyString("foo")
+ .setMyFloat(1.0F)
+ .setExtension(UnittestProto.myExtensionInt, 23)
+ .setExtension(UnittestProto.myExtensionString, "bar")
+ .build().toByteString();
+ assertFieldsInOrder(data);
+
+ Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+ ByteString dynamic_data =
+ DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+ .setField(descriptor.findFieldByName("my_int"), 1L)
+ .setField(descriptor.findFieldByName("my_string"), "foo")
+ .setField(descriptor.findFieldByName("my_float"), 1.0F)
+ .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+ .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+ .build().toByteString();
+ assertFieldsInOrder(dynamic_data);
+ }
+
+ private ExtensionRegistry getTestFieldOrderingsRegistry() {
+ ExtensionRegistry result = ExtensionRegistry.newInstance();
+ result.add(UnittestProto.myExtensionInt);
+ result.add(UnittestProto.myExtensionString);
+ return result;
+ }
+
+ public void testParseMultipleExtensionRanges() throws Exception {
+ // Make sure we can parse a message that contains multiple extensions
+ // ranges.
+ TestFieldOrderings source =
+ TestFieldOrderings.newBuilder()
+ .setMyInt(1)
+ .setMyString("foo")
+ .setMyFloat(1.0F)
+ .setExtension(UnittestProto.myExtensionInt, 23)
+ .setExtension(UnittestProto.myExtensionString, "bar")
+ .build();
+ TestFieldOrderings dest =
+ TestFieldOrderings.parseFrom(source.toByteString(),
+ getTestFieldOrderingsRegistry());
+ assertEquals(source, dest);
+ }
+
+ public void testParseMultipleExtensionRangesDynamic() throws Exception {
+ // Same as above except with DynamicMessage.
+ Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor();
+ DynamicMessage source =
+ DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor())
+ .setField(descriptor.findFieldByName("my_int"), 1L)
+ .setField(descriptor.findFieldByName("my_string"), "foo")
+ .setField(descriptor.findFieldByName("my_float"), 1.0F)
+ .setField(UnittestProto.myExtensionInt.getDescriptor(), 23)
+ .setField(UnittestProto.myExtensionString.getDescriptor(), "bar")
+ .build();
+ DynamicMessage dest =
+ DynamicMessage.parseFrom(descriptor, source.toByteString(),
+ getTestFieldOrderingsRegistry());
+ assertEquals(source, dest);
+ }
+
+ private static final int UNKNOWN_TYPE_ID = 1550055;
+ private static final int TYPE_ID_1 =
+ TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber();
+ private static final int TYPE_ID_2 =
+ TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber();
+
+ public void testSerializeMessageSet() throws Exception {
+ // Set up a TestMessageSet with two known messages and an unknown one.
+ TestMessageSet messageSet =
+ TestMessageSet.newBuilder()
+ .setExtension(
+ TestMessageSetExtension1.messageSetExtension,
+ TestMessageSetExtension1.newBuilder().setI(123).build())
+ .setExtension(
+ TestMessageSetExtension2.messageSetExtension,
+ TestMessageSetExtension2.newBuilder().setStr("foo").build())
+ .setUnknownFields(
+ UnknownFieldSet.newBuilder()
+ .addField(UNKNOWN_TYPE_ID,
+ UnknownFieldSet.Field.newBuilder()
+ .addLengthDelimited(ByteString.copyFromUtf8("bar"))
+ .build())
+ .build())
+ .build();
+
+ ByteString data = messageSet.toByteString();
+
+ // Parse back using RawMessageSet and check the contents.
+ RawMessageSet raw = RawMessageSet.parseFrom(data);
+
+ assertTrue(raw.getUnknownFields().asMap().isEmpty());
+
+ assertEquals(3, raw.getItemCount());
+ assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId());
+ assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId());
+ assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId());
+
+ TestMessageSetExtension1 message1 =
+ TestMessageSetExtension1.parseFrom(
+ raw.getItem(0).getMessage().toByteArray());
+ assertEquals(123, message1.getI());
+
+ TestMessageSetExtension2 message2 =
+ TestMessageSetExtension2.parseFrom(
+ raw.getItem(1).getMessage().toByteArray());
+ assertEquals("foo", message2.getStr());
+
+ assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8());
+ }
+
+ public void testParseMessageSet() throws Exception {
+ ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();
+ extensionRegistry.add(TestMessageSetExtension1.messageSetExtension);
+ extensionRegistry.add(TestMessageSetExtension2.messageSetExtension);
+
+ // Set up a RawMessageSet with two known messages and an unknown one.
+ RawMessageSet raw =
+ RawMessageSet.newBuilder()
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_1)
+ .setMessage(
+ TestMessageSetExtension1.newBuilder()
+ .setI(123)
+ .build().toByteString())
+ .build())
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(TYPE_ID_2)
+ .setMessage(
+ TestMessageSetExtension2.newBuilder()
+ .setStr("foo")
+ .build().toByteString())
+ .build())
+ .addItem(
+ RawMessageSet.Item.newBuilder()
+ .setTypeId(UNKNOWN_TYPE_ID)
+ .setMessage(ByteString.copyFromUtf8("bar"))
+ .build())
+ .build();
+
+ ByteString data = raw.toByteString();
+
+ // Parse as a TestMessageSet and check the contents.
+ TestMessageSet messageSet =
+ TestMessageSet.parseFrom(data, extensionRegistry);
+
+ assertEquals(123, messageSet.getExtension(
+ TestMessageSetExtension1.messageSetExtension).getI());
+ assertEquals("foo", messageSet.getExtension(
+ TestMessageSetExtension2.messageSetExtension).getStr());
+
+ // Check for unknown field with type LENGTH_DELIMITED,
+ // number UNKNOWN_TYPE_ID, and contents "bar".
+ UnknownFieldSet unknownFields = messageSet.getUnknownFields();
+ assertEquals(1, unknownFields.asMap().size());
+ assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID));
+
+ UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID);
+ assertEquals(1, field.getLengthDelimitedList().size());
+ assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8());
+ }
+}
diff --git a/java/src/test/java/com/google/protobuf/multiple_files_test.proto b/java/src/test/java/com/google/protobuf/multiple_files_test.proto
new file mode 100644
index 0000000..060f159
--- /dev/null
+++ b/java/src/test/java/com/google/protobuf/multiple_files_test.proto
@@ -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.
+
+// Author: kenton@google.com (Kenton Varda)
+//
+// A proto file which tests the java_multiple_files option.
+
+
+import "google/protobuf/unittest.proto";
+
+package protobuf_unittest;
+
+option java_multiple_files = true;
+option java_outer_classname = "MultipleFilesTestProto";
+
+message MessageWithNoOuter {
+ message NestedMessage {
+ optional int32 i = 1;
+ }
+ enum NestedEnum {
+ BAZ = 3;
+ }
+ optional NestedMessage nested = 1;
+ repeated TestAllTypes foreign = 2;
+ optional NestedEnum nested_enum = 3;
+ optional EnumWithNoOuter foreign_enum = 4;
+}
+
+enum EnumWithNoOuter {
+ FOO = 1;
+ BAR = 2;
+}
+
+service ServiceWithNoOuter {
+ rpc Foo(MessageWithNoOuter) returns(TestAllTypes);
+}
+
+extend TestAllExtensions {
+ optional int32 extension_with_outer = 1234567;
+}