aboutsummaryrefslogtreecommitdiff
path: root/javanano
diff options
context:
space:
mode:
Diffstat (limited to 'javanano')
-rw-r--r--javanano/README.md (renamed from javanano/README.txt)85
-rw-r--r--javanano/pom.xml65
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java40
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java124
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/Extension.java73
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/InternalNano.java222
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MapFactories.java67
-rw-r--r--javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java14
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/NanoTest.java635
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/map_test.proto70
-rw-r--r--javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto9
11 files changed, 1294 insertions, 110 deletions
diff --git a/javanano/README.txt b/javanano/README.md
index 5a05b865..7d696aa7 100644
--- a/javanano/README.txt
+++ b/javanano/README.md
@@ -1,10 +1,14 @@
Protocol Buffers - Google's data interchange format
+===================================================
+
+[![Build Status](https://travis-ci.org/google/protobuf.svg?branch=master)](https://travis-ci.org/google/protobuf)
+
Copyright 2008 Google Inc.
This directory contains the Java Protocol Buffers Nano runtime library.
Installation - With Maven
-=========================
+-------------------------
The Protocol Buffers build is managed using Maven. If you would
rather build without Maven, see below.
@@ -41,7 +45,7 @@ rather build without Maven, see below.
The .jar will be placed in the "target" directory.
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
@@ -66,20 +70,22 @@ running unit tests.
4) Install the classes wherever you prefer.
Nano version
-============================
+------------
-Nano is a special code generator and runtime library designed specially
-for Android, and is very resource-friendly in both the amount of code
-and the runtime overhead. An overview of Nano features:
+JavaNano is a special code generator and runtime library designed specially for
+resource-restricted systems, like Android. It is very resource-friendly in both
+the amount of code and the runtime overhead. Here is an overview of JavaNano
+features compared with the official Java protobuf:
- No descriptors or message builders.
- All messages are mutable; fields are public Java fields.
- For optional fields only, encapsulation behind setter/getter/hazzer/
clearer functions is opt-in, which provide proper 'has' state support.
-- If not opted in, has state is not available. Serialization outputs
- all fields not equal to their defaults (see important implications
- below).
-- Required fields are always serialized.
+- For proto2, if not opted in, has state (field presence) is not available.
+ Serialization outputs all fields not equal to their defaults
+ (see important implications below).
+ The behavior is consistent with proto3 semantics.
+- Required fields (proto2 only) are always serialized.
- Enum constants are integers; protection against invalid values only
when parsing from the wire.
- Enum constants can be generated into container interfaces bearing
@@ -88,8 +94,8 @@ and the runtime overhead. An overview of Nano features:
- Similarly CodedOutputByteBufferNano can only write to byte[].
- Repeated fields are in arrays, not ArrayList or Vector. Null array
elements are allowed and silently ignored.
-- Full support of serializing/deserializing repeated packed fields.
-- Support of extensions.
+- Full support for serializing/deserializing repeated packed fields.
+- Support extensions (in proto2).
- Unset messages/groups are null, not an immutable empty default
instance.
- toByteArray(...) and mergeFrom(...) are now static functions of
@@ -128,7 +134,9 @@ penalty. This is not a problem if the field has no default or is an
empty default.
Nano Generator options
+----------------------
+```
java_package -> <file-name>|<package-name>
java_outer_classname -> <file-name>|<package-name>
java_multiple_files -> true or false
@@ -137,8 +145,10 @@ optional_field_style -> default or accessors
enum_style -> c or java
ignore_services -> true or false
parcelable_messages -> true or false
+```
+
+**java_package=\<file-name\>|\<package-name\>** (no default)
-java_package=<file-name>|<package-name> (no default)
This allows overriding the 'java_package' option value
for the given file from the command line. Use multiple
java_package options to override the option for multiple
@@ -147,7 +157,8 @@ java_package=<file-name>|<package-name> (no default)
the same option defined in the file if present, or the
proto package if present, or the default Java package.
-java_outer_classname=<file-name>|<outer-classname> (no default)
+**java_outer_classname=\<file-name\>|\<outer-classname\>** (no default)
+
This allows overriding the 'java_outer_classname' option
for the given file from the command line. Use multiple
java_outer_classname options to override the option for
@@ -158,7 +169,8 @@ java_outer_classname=<file-name>|<outer-classname> (no default)
outer class will nest all classes and integer constants
generated from file-scope messages and enums.
-java_multiple_files={true,false} (no default)
+**java_multiple_files={true,false}** (no default)
+
This allows overriding the 'java_multiple_files' option
in all source files and their imported files from the
command line. The final value of this option for each
@@ -176,10 +188,11 @@ java_multiple_files={true,false} (no default)
incorrect references to the imported messages and enum
constants.
-java_nano_generate_has={true,false} (default: false)
+**java_nano_generate_has={true,false}** (default: false)
+
DEPRECATED. Use optional_field_style=accessors.
- If true, generates a public boolean variable has<fieldname>
+ If true, generates a public boolean variable has\<fieldname\>
accompanying each optional or required field (not present for
repeated fields, groups or messages). It is set to false initially
and upon clear(). If parseFrom(...) reads the field from the wire,
@@ -193,20 +206,21 @@ java_nano_generate_has={true,false} (default: false)
many cases reading the default works and determining whether the
field was received over the wire is irrelevant.
-optional_field_style={default,accessors,reftypes} (default: default)
+**optional_field_style={default,accessors,reftypes}** (default: default)
+
Defines the style of the generated code for fields.
- * default *
+ * default
In the default style, optional fields translate into public mutable
Java fields, and the serialization process is as discussed in the
- "IMPORTANT" section above.
+ "IMPORTANT" section above.
- * accessors *
+ * accessors
When set to 'accessors', each optional field is encapsulated behind
- 4 accessors, namely get<fieldname>(), set<fieldname>(), has<fieldname>()
- and clear<fieldname>() methods, with the standard semantics. The hazzer's
+ 4 accessors, namely get\<fieldname\>(), set\<fieldname\>(), has\<fieldname\>()
+ and clear\<fieldname\>() methods, with the standard semantics. The hazzer's
return value determines whether a field is serialized, so this style is
useful when you need to serialize a field with the default value, or check
if a field has been explicitly set to its default value from the wire.
@@ -222,7 +236,7 @@ optional_field_style={default,accessors,reftypes} (default: default)
reducing the final code size.
TODO(maxtroy): find ProGuard config that would work the best.
- * reftypes *
+ * reftypes
When set to 'reftypes', each proto field is generated as a public Java
field. For primitive types, these fields use the Java reference types
@@ -252,10 +266,11 @@ optional_field_style={default,accessors,reftypes} (default: default)
required field (you have no reason to), you can only use
java_nano_generate_has=true.
-enum_style={c,java} (default: c)
+**enum_style={c,java}** (default: c)
+
Defines where to put the int constants generated from enum members.
- * c *
+ * c
Use C-style, so the enum constants are available at the scope where
the enum is defined. A file-scope enum's members are referenced like
@@ -263,7 +278,7 @@ enum_style={c,java} (default: c)
referenced as 'Message.ENUM_VALUE'. The enum name is unavailable.
This complies with the Micro code generator's behavior.
- * java *
+ * java
Use Java-style, so the enum constants are available under the enum
name and referenced like 'EnumName.ENUM_VALUE' (they are still int
@@ -275,18 +290,21 @@ enum_style={c,java} (default: c)
compiler inlines all referenced enum constants into the call sites,
the interface remains unused and can be removed by ProGuard.
-ignore_services={true,false} (default: false)
+**ignore_services={true,false}** (default: false)
+
Skips services definitions.
Nano doesn't support services. By default, if a service is defined
it will generate a compilation error. If this flag is set to true,
services will be silently ignored, instead.
-parcelable_messages={true,false} (default: false)
+**parcelable_messages={true,false}** (default: false)
+
Android-specific option to generate Parcelable messages.
To use nano protobufs within the Android repo:
+----------------------------------------------
- Set 'LOCAL_PROTOC_OPTIMIZE_TYPE := nano' in your local .mk file.
When building a Java library or an app (package) target, the build
@@ -311,17 +329,20 @@ To use nano protobufs within the Android repo:
the two above.
To use nano protobufs outside of Android repo:
+----------------------------------------------
- Link with the generated jar file
- <protobuf-root>java/target/protobuf-java-2.3.0-nano.jar.
+ \<protobuf-root\>java/target/protobuf-java-2.3.0-nano.jar.
- Invoke with --javanano_out, e.g.:
-
+```
./protoc '--javanano_out=\
java_package=src/proto/simple-data.proto|my_package,\
java_outer_classname=src/proto/simple-data.proto|OuterName\
:.' src/proto/simple-data.proto
+```
Contributing to nano:
+---------------------
Please add/edit tests in NanoTest.java.
@@ -346,7 +367,7 @@ Please run the following steps to test:
- "make -j12" and check for build errors
Usage
-=====
+-----
The complete documentation for Protocol Buffers is available via the
web at:
diff --git a/javanano/pom.xml b/javanano/pom.xml
index 3d98a5e0..7a2be9df 100644
--- a/javanano/pom.xml
+++ b/javanano/pom.xml
@@ -10,7 +10,7 @@
</parent>
<groupId>com.google.protobuf.nano</groupId>
<artifactId>protobuf-javanano</artifactId>
- <version>2.6.2-pre</version>
+ <version>3.0.0-alpha-3-pre</version>
<packaging>bundle</packaging>
<name>Protocol Buffer JavaNano API</name>
<description>
@@ -94,6 +94,7 @@
<arg value="src/test/java/com/google/protobuf/nano/unittest_multiple_nameclash_nano.proto" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_enum_class_nano.proto" />
<arg value="src/test/java/com/google/protobuf/nano/unittest_repeated_merge_nano.proto" />
+ <arg value="src/test/java/com/google/protobuf/nano/map_test.proto" />
</exec>
<exec executable="../src/protoc">
<arg value="--javanano_out=store_unknown_fields=true,generate_equals=true:target/generated-test-sources" />
@@ -155,10 +156,70 @@
<instructions>
<Bundle-DocURL>https://developers.google.com/protocol-buffers/</Bundle-DocURL>
<Bundle-SymbolicName>com.google.protobuf</Bundle-SymbolicName>
- <Export-Package>com.google.protobuf;version=2.6.2-pre</Export-Package>
+ <Export-Package>com.google.protobuf;version=3.0.0-alpha-3-pre</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
+ <profiles>
+ <profile>
+ <id>release</id>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-source-plugin</artifactId>
+ <version>2.2.1</version>
+ <executions>
+ <execution>
+ <id>attach-sources</id>
+ <goals>
+ <goal>jar-no-fork</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <version>2.9.1</version>
+ <executions>
+ <execution>
+ <id>attach-javadocs</id>
+ <goals>
+ <goal>jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-gpg-plugin</artifactId>
+ <version>1.5</version>
+ <executions>
+ <execution>
+ <id>sign-artifacts</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>sign</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.sonatype.plugins</groupId>
+ <artifactId>nexus-staging-maven-plugin</artifactId>
+ <version>1.6.3</version>
+ <extensions>true</extensions>
+ <configuration>
+ <serverId>sonatype-nexus-staging</serverId>
+ <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+ <autoReleaseAfterClose>false</autoReleaseAfterClose>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
</project>
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
index b147f69d..b4f20fde 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -638,4 +638,44 @@ public final class CodedInputByteBufferNano {
throw InvalidProtocolBufferNanoException.truncatedMessage();
}
}
+
+ // Read a primitive type.
+ Object readPrimitiveField(int type) throws IOException {
+ switch (type) {
+ case InternalNano.TYPE_DOUBLE:
+ return readDouble();
+ case InternalNano.TYPE_FLOAT:
+ return readFloat();
+ case InternalNano.TYPE_INT64:
+ return readInt64();
+ case InternalNano.TYPE_UINT64:
+ return readUInt64();
+ case InternalNano.TYPE_INT32:
+ return readInt32();
+ case InternalNano.TYPE_FIXED64:
+ return readFixed64();
+ case InternalNano.TYPE_FIXED32:
+ return readFixed32();
+ case InternalNano.TYPE_BOOL:
+ return readBool();
+ case InternalNano.TYPE_STRING:
+ return readString();
+ case InternalNano.TYPE_BYTES:
+ return readBytes();
+ case InternalNano.TYPE_UINT32:
+ return readUInt32();
+ case InternalNano.TYPE_ENUM:
+ return readEnum();
+ case InternalNano.TYPE_SFIXED32:
+ return readSFixed32();
+ case InternalNano.TYPE_SFIXED64:
+ return readSFixed64();
+ case InternalNano.TYPE_SINT32:
+ return readSInt32();
+ case InternalNano.TYPE_SINT64:
+ return readSInt64();
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
index 37982b57..2777f34c 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -876,4 +876,128 @@ public final class CodedOutputByteBufferNano {
// Note: the right-shift must be arithmetic
return (n << 1) ^ (n >> 63);
}
+
+ static int computeFieldSize(int number, int type, Object object) {
+ switch (type) {
+ case InternalNano.TYPE_BOOL:
+ return computeBoolSize(number, (Boolean) object);
+ case InternalNano.TYPE_BYTES:
+ return computeBytesSize(number, (byte[]) object);
+ case InternalNano.TYPE_STRING:
+ return computeStringSize(number, (String) object);
+ case InternalNano.TYPE_FLOAT:
+ return computeFloatSize(number, (Float) object);
+ case InternalNano.TYPE_DOUBLE:
+ return computeDoubleSize(number, (Double) object);
+ case InternalNano.TYPE_ENUM:
+ return computeEnumSize(number, (Integer) object);
+ case InternalNano.TYPE_FIXED32:
+ return computeFixed32Size(number, (Integer) object);
+ case InternalNano.TYPE_INT32:
+ return computeInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_UINT32:
+ return computeUInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_SINT32:
+ return computeSInt32Size(number, (Integer) object);
+ case InternalNano.TYPE_SFIXED32:
+ return computeSFixed32Size(number, (Integer) object);
+ case InternalNano.TYPE_INT64:
+ return computeInt64Size(number, (Long) object);
+ case InternalNano.TYPE_UINT64:
+ return computeUInt64Size(number, (Long) object);
+ case InternalNano.TYPE_SINT64:
+ return computeSInt64Size(number, (Long) object);
+ case InternalNano.TYPE_FIXED64:
+ return computeFixed64Size(number, (Long) object);
+ case InternalNano.TYPE_SFIXED64:
+ return computeSFixed64Size(number, (Long) object);
+ case InternalNano.TYPE_MESSAGE:
+ return computeMessageSize(number, (MessageNano) object);
+ case InternalNano.TYPE_GROUP:
+ return computeGroupSize(number, (MessageNano) object);
+ default:
+ throw new IllegalArgumentException("Unknown type: " + type);
+ }
+ }
+
+ void writeField(int number, int type, Object value)
+ throws IOException {
+ switch (type) {
+ case InternalNano.TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ writeDouble(number, doubleValue);
+ break;
+ case InternalNano.TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ writeFloat(number, floatValue);
+ break;
+ case InternalNano.TYPE_INT64:
+ Long int64Value = (Long) value;
+ writeInt64(number, int64Value);
+ break;
+ case InternalNano.TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ writeUInt64(number, uint64Value);
+ break;
+ case InternalNano.TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ writeInt32(number, int32Value);
+ break;
+ case InternalNano.TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ writeFixed64(number, fixed64Value);
+ break;
+ case InternalNano.TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ writeFixed32(number, fixed32Value);
+ break;
+ case InternalNano.TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ writeBool(number, boolValue);
+ break;
+ case InternalNano.TYPE_STRING:
+ String stringValue = (String) value;
+ writeString(number, stringValue);
+ break;
+ case InternalNano.TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ writeBytes(number, bytesValue);
+ break;
+ case InternalNano.TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ writeUInt32(number, uint32Value);
+ break;
+ case InternalNano.TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ writeEnum(number, enumValue);
+ break;
+ case InternalNano.TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ writeSFixed32(number, sfixed32Value);
+ break;
+ case InternalNano.TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ writeSFixed64(number, sfixed64Value);
+ break;
+ case InternalNano.TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ writeSInt32(number, sint32Value);
+ break;
+ case InternalNano.TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ writeSInt64(number, sint64Value);
+ break;
+ case InternalNano.TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ writeMessage(number, messageValue);
+ break;
+ case InternalNano.TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ writeGroup(number, groupValue);
+ break;
+ default:
+ throw new IOException("Unknown type: " + type);
+ }
+ }
+
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/Extension.java b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
index 5d18ae6e..c29b030f 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/Extension.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/Extension.java
@@ -55,24 +55,24 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
* PrimitiveExtension // for primitive/enum typed extensions
*/
- public static final int TYPE_DOUBLE = 1;
- public static final int TYPE_FLOAT = 2;
- public static final int TYPE_INT64 = 3;
- public static final int TYPE_UINT64 = 4;
- public static final int TYPE_INT32 = 5;
- public static final int TYPE_FIXED64 = 6;
- public static final int TYPE_FIXED32 = 7;
- public static final int TYPE_BOOL = 8;
- public static final int TYPE_STRING = 9;
- public static final int TYPE_GROUP = 10;
- public static final int TYPE_MESSAGE = 11;
- public static final int TYPE_BYTES = 12;
- public static final int TYPE_UINT32 = 13;
- public static final int TYPE_ENUM = 14;
- public static final int TYPE_SFIXED32 = 15;
- public static final int TYPE_SFIXED64 = 16;
- public static final int TYPE_SINT32 = 17;
- public static final int TYPE_SINT64 = 18;
+ public static final int TYPE_DOUBLE = InternalNano.TYPE_DOUBLE;
+ public static final int TYPE_FLOAT = InternalNano.TYPE_FLOAT;
+ public static final int TYPE_INT64 = InternalNano.TYPE_INT64;
+ public static final int TYPE_UINT64 = InternalNano.TYPE_UINT64;
+ public static final int TYPE_INT32 = InternalNano.TYPE_INT32;
+ public static final int TYPE_FIXED64 = InternalNano.TYPE_FIXED64;
+ public static final int TYPE_FIXED32 = InternalNano.TYPE_FIXED32;
+ public static final int TYPE_BOOL = InternalNano.TYPE_BOOL;
+ public static final int TYPE_STRING = InternalNano.TYPE_STRING;
+ public static final int TYPE_GROUP = InternalNano.TYPE_GROUP;
+ public static final int TYPE_MESSAGE = InternalNano.TYPE_MESSAGE;
+ public static final int TYPE_BYTES = InternalNano.TYPE_BYTES;
+ public static final int TYPE_UINT32 = InternalNano.TYPE_UINT32;
+ public static final int TYPE_ENUM = InternalNano.TYPE_ENUM;
+ public static final int TYPE_SFIXED32 = InternalNano.TYPE_SFIXED32;
+ public static final int TYPE_SFIXED64 = InternalNano.TYPE_SFIXED64;
+ public static final int TYPE_SINT32 = InternalNano.TYPE_SINT32;
+ public static final int TYPE_SINT64 = InternalNano.TYPE_SINT64;
/**
* Creates an {@code Extension} of the given message type and tag number.
@@ -338,42 +338,7 @@ public class Extension<M extends ExtendableMessageNano<M>, T> {
@Override
protected Object readData(CodedInputByteBufferNano input) {
try {
- switch (type) {
- case TYPE_DOUBLE:
- return input.readDouble();
- case TYPE_FLOAT:
- return input.readFloat();
- case TYPE_INT64:
- return input.readInt64();
- case TYPE_UINT64:
- return input.readUInt64();
- case TYPE_INT32:
- return input.readInt32();
- case TYPE_FIXED64:
- return input.readFixed64();
- case TYPE_FIXED32:
- return input.readFixed32();
- case TYPE_BOOL:
- return input.readBool();
- case TYPE_STRING:
- return input.readString();
- case TYPE_BYTES:
- return input.readBytes();
- case TYPE_UINT32:
- return input.readUInt32();
- case TYPE_ENUM:
- return input.readEnum();
- case TYPE_SFIXED32:
- return input.readSFixed32();
- case TYPE_SFIXED64:
- return input.readSFixed64();
- case TYPE_SINT32:
- return input.readSInt32();
- case TYPE_SINT64:
- return input.readSInt64();
- default:
- throw new IllegalArgumentException("Unknown type " + type);
- }
+ return input.readPrimitiveField(type);
} catch (IOException e) {
throw new IllegalArgumentException("Error reading extension field", e);
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
index e08bb4b7..4a08bb58 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/InternalNano.java
@@ -30,8 +30,13 @@
package com.google.protobuf.nano;
+import com.google.protobuf.nano.MapFactories.MapFactory;
+
+import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
/**
* The classes contained within are used internally by the Protocol Buffer
@@ -43,6 +48,26 @@ import java.util.Arrays;
*/
public final class InternalNano {
+ public static final int TYPE_DOUBLE = 1;
+ public static final int TYPE_FLOAT = 2;
+ public static final int TYPE_INT64 = 3;
+ public static final int TYPE_UINT64 = 4;
+ public static final int TYPE_INT32 = 5;
+ public static final int TYPE_FIXED64 = 6;
+ public static final int TYPE_FIXED32 = 7;
+ public static final int TYPE_BOOL = 8;
+ public static final int TYPE_STRING = 9;
+ public static final int TYPE_GROUP = 10;
+ public static final int TYPE_MESSAGE = 11;
+ public static final int TYPE_BYTES = 12;
+ public static final int TYPE_UINT32 = 13;
+ public static final int TYPE_ENUM = 14;
+ public static final int TYPE_SFIXED32 = 15;
+ public static final int TYPE_SFIXED64 = 16;
+ public static final int TYPE_SINT32 = 17;
+ public static final int TYPE_SINT64 = 18;
+
+
private InternalNano() {}
/**
@@ -329,5 +354,202 @@ public final class InternalNano {
}
return result;
}
+ private static Object primitiveDefaultValue(int type) {
+ switch (type) {
+ case TYPE_BOOL:
+ return Boolean.FALSE;
+ case TYPE_BYTES:
+ return WireFormatNano.EMPTY_BYTES;
+ case TYPE_STRING:
+ return "";
+ case TYPE_FLOAT:
+ return Float.valueOf(0);
+ case TYPE_DOUBLE:
+ return Double.valueOf(0);
+ case TYPE_ENUM:
+ case TYPE_FIXED32:
+ case TYPE_INT32:
+ case TYPE_UINT32:
+ case TYPE_SINT32:
+ case TYPE_SFIXED32:
+ return Integer.valueOf(0);
+ case TYPE_INT64:
+ case TYPE_UINT64:
+ case TYPE_SINT64:
+ case TYPE_FIXED64:
+ case TYPE_SFIXED64:
+ return Long.valueOf(0L);
+ case TYPE_MESSAGE:
+ case TYPE_GROUP:
+ default:
+ throw new IllegalArgumentException(
+ "Type: " + type + " is not a primitive type.");
+ }
+ }
+
+ /**
+ * Merges the map entry into the map field. Note this is only supposed to
+ * be called by generated messages.
+ *
+ * @param map the map field; may be null, in which case a map will be
+ * instantiated using the {@link MapFactories.MapFactory}
+ * @param input the input byte buffer
+ * @param keyType key type, as defined in InternalNano.TYPE_*
+ * @param valueType value type, as defined in InternalNano.TYPE_*
+ * @param value an new instance of the value, if the value is a TYPE_MESSAGE;
+ * otherwise this parameter can be null and will be ignored.
+ * @param keyTag wire tag for the key
+ * @param valueTag wire tag for the value
+ * @return the map field
+ * @throws IOException
+ */
+ @SuppressWarnings("unchecked")
+ public static final <K, V> Map<K, V> mergeMapEntry(
+ CodedInputByteBufferNano input,
+ Map<K, V> map,
+ MapFactory mapFactory,
+ int keyType,
+ int valueType,
+ V value,
+ int keyTag,
+ int valueTag) throws IOException {
+ map = mapFactory.forMap(map);
+ final int length = input.readRawVarint32();
+ final int oldLimit = input.pushLimit(length);
+ K key = null;
+ while (true) {
+ int tag = input.readTag();
+ if (tag == 0) {
+ break;
+ }
+ if (tag == keyTag) {
+ key = (K) input.readPrimitiveField(keyType);
+ } else if (tag == valueTag) {
+ if (valueType == TYPE_MESSAGE) {
+ input.readMessage((MessageNano) value);
+ } else {
+ value = (V) input.readPrimitiveField(valueType);
+ }
+ } else {
+ if (!input.skipField(tag)) {
+ break;
+ }
+ }
+ }
+ input.checkLastTagWas(0);
+ input.popLimit(oldLimit);
+
+ if (key == null) {
+ // key can only be primitive types.
+ key = (K) primitiveDefaultValue(keyType);
+ }
+
+ if (value == null) {
+ // message type value will be initialized by code-gen.
+ value = (V) primitiveDefaultValue(valueType);
+ }
+
+ map.put(key, value);
+ return map;
+ }
+
+ public static <K, V> void serializeMapField(
+ CodedOutputByteBufferNano output,
+ Map<K, V> map, int number, int keyType, int valueType)
+ throws IOException {
+ for (Entry<K, V> entry: map.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (key == null || value == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ int entrySize =
+ CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+ CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+ output.writeTag(number, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(entrySize);
+ output.writeField(1, keyType, key);
+ output.writeField(2, valueType, value);
+ }
+ }
+
+ public static <K, V> int computeMapFieldSize(
+ Map<K, V> map, int number, int keyType, int valueType) {
+ int size = 0;
+ int tagSize = CodedOutputByteBufferNano.computeTagSize(number);
+ for (Entry<K, V> entry: map.entrySet()) {
+ K key = entry.getKey();
+ V value = entry.getValue();
+ if (key == null || value == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ int entrySize =
+ CodedOutputByteBufferNano.computeFieldSize(1, keyType, key) +
+ CodedOutputByteBufferNano.computeFieldSize(2, valueType, value);
+ size += tagSize + entrySize
+ + CodedOutputByteBufferNano.computeRawVarint32Size(entrySize);
+ }
+ return size;
+ }
+
+ /**
+ * Checks whether two {@link Map} are equal. We don't use the default equals
+ * method of {@link Map} because it compares by identity not by content for
+ * byte arrays.
+ */
+ public static <K, V> boolean equals(Map<K, V> a, Map<K, V> b) {
+ if (a == b) {
+ return true;
+ }
+ if (a == null) {
+ return b.size() == 0;
+ }
+ if (b == null) {
+ return a.size() == 0;
+ }
+ if (a.size() != b.size()) {
+ return false;
+ }
+ for (Entry<K, V> entry : a.entrySet()) {
+ if (!b.containsKey(entry.getKey())) {
+ return false;
+ }
+ if (!equalsMapValue(entry.getValue(), b.get(entry.getKey()))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static boolean equalsMapValue(Object a, Object b) {
+ if (a == null || b == null) {
+ throw new IllegalStateException(
+ "keys and values in maps cannot be null");
+ }
+ if (a instanceof byte[] && b instanceof byte[]) {
+ return Arrays.equals((byte[]) a, (byte[]) b);
+ }
+ return a.equals(b);
+ }
+
+ public static <K, V> int hashCode(Map<K, V> map) {
+ if (map == null) {
+ return 0;
+ }
+ int result = 0;
+ for (Entry<K, V> entry : map.entrySet()) {
+ result += hashCodeForMap(entry.getKey())
+ ^ hashCodeForMap(entry.getValue());
+ }
+ return result;
+ }
+ private static int hashCodeForMap(Object o) {
+ if (o instanceof byte[]) {
+ return Arrays.hashCode((byte[]) o);
+ }
+ return o.hashCode();
+ }
}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
new file mode 100644
index 00000000..98fa4877
--- /dev/null
+++ b/javanano/src/main/java/com/google/protobuf/nano/MapFactories.java
@@ -0,0 +1,67 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+package com.google.protobuf.nano;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Utility class for maps support.
+ */
+public final class MapFactories {
+ public static interface MapFactory {
+ <K, V> Map<K, V> forMap(Map<K, V> oldMap);
+ }
+
+ // NOTE(liujisi): The factory setter is temporarily marked as package private.
+ // The way to provide customized implementations of maps for different
+ // platforms are still under discussion. Mark it as private to avoid exposing
+ // the API in proto3 alpha release.
+ /* public */ static void setMapFactory(MapFactory newMapFactory) {
+ mapFactory = newMapFactory;
+ }
+
+ public static MapFactory getMapFactory() {
+ return mapFactory;
+ }
+
+ private static class DefaultMapFactory implements MapFactory {
+ public <K, V> Map<K, V> forMap(Map<K, V> oldMap) {
+ if (oldMap == null) {
+ return new HashMap<K, V>();
+ }
+ return oldMap;
+ }
+ }
+ private static volatile MapFactory mapFactory = new DefaultMapFactory();
+
+ private MapFactories() {}
+}
diff --git a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
index dd43cdbb..c4b2ad3d 100644
--- a/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
+++ b/javanano/src/main/java/com/google/protobuf/nano/MessageNanoPrinter.java
@@ -35,6 +35,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Map;
/**
* Static helper methods for printing nano protos.
@@ -170,6 +171,19 @@ public final class MessageNanoPrinter {
indentBuf.setLength(origIndentBufLength);
buf.append(indentBuf).append(">\n");
}
+ } else if (object instanceof Map) {
+ Map<?,?> map = (Map<?,?>) object;
+ identifier = deCamelCaseify(identifier);
+
+ for (Map.Entry<?,?> entry : map.entrySet()) {
+ buf.append(indentBuf).append(identifier).append(" <\n");
+ int origIndentBufLength = indentBuf.length();
+ indentBuf.append(INDENT);
+ print("key", entry.getKey(), indentBuf, buf);
+ print("value", entry.getValue(), indentBuf, buf);
+ indentBuf.setLength(origIndentBufLength);
+ buf.append(indentBuf).append(">\n");
+ }
} else {
// Non-null primitive value
identifier = deCamelCaseify(identifier);
diff --git a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
index 442f0b74..4cc77226 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
+++ b/javanano/src/test/java/com/google/protobuf/nano/NanoTest.java
@@ -30,31 +30,11 @@
package com.google.protobuf.nano;
-import com.google.protobuf.nano.CodedInputByteBufferNano;
-import com.google.protobuf.nano.EnumClassNanoMultiple;
-import com.google.protobuf.nano.EnumClassNanos;
-import com.google.protobuf.nano.EnumValidity;
-import com.google.protobuf.nano.EnumValidityAccessors;
-import com.google.protobuf.nano.FileScopeEnumMultiple;
-import com.google.protobuf.nano.FileScopeEnumRefNano;
-import com.google.protobuf.nano.InternalNano;
-import com.google.protobuf.nano.InvalidProtocolBufferNanoException;
-import com.google.protobuf.nano.MessageNano;
-import com.google.protobuf.nano.MessageScopeEnumRefNano;
-import com.google.protobuf.nano.MultipleImportingNonMultipleNano1;
-import com.google.protobuf.nano.MultipleImportingNonMultipleNano2;
-import com.google.protobuf.nano.MultipleNameClashNano;
+import com.google.protobuf.nano.MapTestProto.TestMap;
+import com.google.protobuf.nano.MapTestProto.TestMap.MessageValue;
import com.google.protobuf.nano.NanoAccessorsOuterClass.TestNanoAccessors;
import com.google.protobuf.nano.NanoHasOuterClass.TestAllTypesNanoHas;
-import com.google.protobuf.nano.NanoOuterClass;
import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
-import com.google.protobuf.nano.NanoReferenceTypes;
-import com.google.protobuf.nano.NanoRepeatedPackables;
-import com.google.protobuf.nano.PackedExtensions;
-import com.google.protobuf.nano.RepeatedExtensions;
-import com.google.protobuf.nano.SingularExtensions;
-import com.google.protobuf.nano.TestRepeatedMergeNano;
-import com.google.protobuf.nano.UnittestMultipleNano;
import com.google.protobuf.nano.UnittestRecursiveNano.RecursiveMessageNano;
import com.google.protobuf.nano.UnittestSimpleNano.SimpleMessageNano;
import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
@@ -67,6 +47,8 @@ import junit.framework.TestCase;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.Map;
+import java.util.TreeMap;
/**
* Test nano runtime.
@@ -2688,6 +2670,7 @@ public class NanoTest extends TestCase {
msg.repeatedNestedEnum[0] = TestAllTypesNano.BAR;
msg.repeatedNestedEnum[1] = TestAllTypesNano.FOO;
msg.repeatedStringPiece = new String[] {null, "world"};
+ msg.setOneofString("hello");
String protoPrint = msg.toString();
assertTrue(protoPrint.contains("optional_int32: 14"));
@@ -2711,6 +2694,7 @@ public class NanoTest extends TestCase {
assertTrue(protoPrint.contains("default_string: \"hello\""));
assertFalse(protoPrint.contains("repeated_string_piece: \"\"")); // null should be dropped
assertTrue(protoPrint.contains("repeated_string_piece: \"world\""));
+ assertTrue(protoPrint.contains("oneof_string: \"hello\""));
}
public void testMessageNanoPrinterAccessors() throws Exception {
@@ -2749,6 +2733,45 @@ public class NanoTest extends TestCase {
assertTrue(protoPrint.contains("id: 33"));
}
+ public void testMessageNanoPrinterForMaps() throws Exception {
+ TestMap msg = new TestMap();
+ MessageValue msgValues[] = new MessageValue[] {
+ new MessageValue(), new MessageValue()
+ };
+ msgValues[0].value = 1;
+ msgValues[1].value = 2;
+ msg.int32ToBytesField = new HashMap<Integer, byte[]>();
+ msg.int32ToBytesField.put(1, new byte[] {'"', '\0'});
+ msg.int32ToBytesField.put(2, new byte[] {1, 8});
+ msg.stringToInt32Field = new HashMap<String, Integer>();
+ msg.stringToInt32Field.put("hello", 1);
+ msg.stringToInt32Field.put("world", 2);
+ msg.int32ToMessageField = new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ msg.int32ToMessageField.put(0, msgValues[0]);
+ msg.int32ToMessageField.put(1, msgValues[1]);
+ msg.int32ToEnumField = new HashMap<Integer, Integer>();
+ msg.int32ToEnumField.put(1, 2);
+ msg.int32ToEnumField.put(2, 3);
+ String protoPrint = msg.toString();
+
+ assertTrue(protoPrint.contains(
+ "int32_to_bytes_field <\n key: 1\n value: \"\\\"\\000\"\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_bytes_field <\n key: 2\n value: \"\\001\\010\"\n>"));
+ assertTrue(protoPrint.contains(
+ "string_to_int32_field <\n key: \"hello\"\n value: 1\n>"));
+ assertTrue(protoPrint.contains(
+ "string_to_int32_field <\n key: \"world\"\n value: 2\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_message_field <\n key: 0\n value <\n value: 1\n"));
+ assertTrue(protoPrint.contains(
+ "int32_to_message_field <\n key: 1\n value <\n value: 2\n"));
+ assertTrue(protoPrint.contains(
+ "int32_to_enum_field <\n key: 1\n value: 2\n>"));
+ assertTrue(protoPrint.contains(
+ "int32_to_enum_field <\n key: 2\n value: 3\n>"));
+ }
+
public void testExtensions() throws Exception {
Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
message.field = 5;
@@ -3340,6 +3363,7 @@ public class NanoTest extends TestCase {
TestAllTypesNano.BAR,
TestAllTypesNano.BAZ
};
+ message.setOneofUint32(3);
return message;
}
@@ -3538,6 +3562,259 @@ public class NanoTest extends TestCase {
new NanoReferenceTypes.TestAllTypesNano(), MessageNano.toByteArray(m7))));
}
+ private static TestAllTypesNano generateMessageForOneof(int caseNumber) {
+ TestAllTypesNano result = new TestAllTypesNano();
+ TestAllTypesNano.NestedMessage nested =
+ new TestAllTypesNano.NestedMessage();
+ nested.bb = 2;
+ switch (caseNumber) {
+ case TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER:
+ result.setOneofUint32(1);
+ break;
+ case TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER:
+ result.setOneofEnum(TestAllTypesNano.BAR);
+ break;
+ case TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER:
+ result.setOneofNestedMessage(nested);
+ break;
+ case TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER:
+ result.setOneofBytes(new byte[] {1, 2});
+ break;
+ case TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER:
+ result.setOneofString("hello");
+ break;
+ case TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER:
+ result.setOneofFixed64(-1L);
+ break;
+ default:
+ throw new RuntimeException("unexpected case number: " + caseNumber);
+ }
+ return result;
+ }
+
+ public void testOneofHashCodeEquals() throws Exception {
+ TestAllTypesNano m1 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(m1, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER));
+ assertFalse(m1.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m2 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(m2, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER));
+ assertFalse(m2.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m3 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(m3, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER));
+ assertFalse(m3.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m4 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertEquals(m4, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER));
+ assertFalse(m4.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m5 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+ assertEquals(m5, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER));
+ assertFalse(m5.equals(new TestAllTypesNano()));
+
+ TestAllTypesNano m6 = generateMessageForOneof(
+ TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(m6, generateMessageForOneof(
+ TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER));
+ assertFalse(m6.equals(new TestAllTypesNano()));
+
+ Map<TestAllTypesNano, Integer> map =
+ new HashMap<TestAllTypesNano, Integer>();
+ map.put(m1, 1);
+ map.put(m2, 2);
+ map.put(m3, 3);
+ map.put(m4, 4);
+ map.put(m5, 5);
+ map.put(m6, 6);
+
+ assertEquals(6, map.size());
+ }
+
+ private void checkOneofCase(TestAllTypesNano nano, int field)
+ throws Exception {
+ assertEquals(field, nano.getOneofFieldCase());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER,
+ nano.hasOneofBytes());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER,
+ nano.hasOneofEnum());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER,
+ nano.hasOneofFixed64());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER,
+ nano.hasOneofNestedMessage());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER,
+ nano.hasOneofString());
+ assertEquals(
+ field == TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER,
+ nano.hasOneofUint32());
+
+ }
+
+ public void testOneofDefault() throws Exception {
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ checkOneofCase(m1, 0);
+ assertEquals(WireFormatNano.EMPTY_BYTES, m1.getOneofBytes());
+ assertEquals(TestAllTypesNano.FOO, m1.getOneofEnum());
+ assertEquals(0L, m1.getOneofFixed64());
+ assertEquals(null, m1.getOneofNestedMessage());
+ assertEquals("", m1.getOneofString());
+ assertEquals(0, m1.getOneofUint32());
+ }
+
+ public void testOneofExclusiveness() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ checkOneofCase(m, 0);
+
+ m.setOneofBytes(new byte[]{0, 1});
+ checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, m.getOneofBytes()));
+
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ assertEquals(WireFormatNano.EMPTY_BYTES, m.getOneofBytes());
+
+ m.setOneofFixed64(-1L);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(-1L, m.getOneofFixed64());
+ assertEquals(TestAllTypesNano.FOO, m.getOneofEnum());
+
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(
+ new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+ assertEquals(0L, m.getOneofFixed64());
+
+ m.setOneofString("hello");
+ checkOneofCase(m, TestAllTypesNano.ONEOF_STRING_FIELD_NUMBER);
+ assertEquals("hello", m.getOneofString());
+ assertNull(m.getOneofNestedMessage());
+
+ m.setOneofUint32(10);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(10, m.getOneofUint32());
+ assertEquals("", m.getOneofString());
+
+ m.setOneofBytes(new byte[]{0, 1});
+ checkOneofCase(m, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, m.getOneofBytes()));
+ assertEquals(0, m.getOneofUint32());
+ }
+
+ public void testOneofClear() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ m.setOneofBytes(new byte[]{0, 1});
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofFixed64(-1L);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofString("hello");
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+
+ m.setOneofUint32(10);
+ m.clearOneofField();
+ checkOneofCase(m, 0);
+ }
+
+ public void testOneofMarshaling() throws Exception {
+ TestAllTypesNano m = new TestAllTypesNano();
+ TestAllTypesNano parsed = new TestAllTypesNano();
+ {
+ m.setOneofBytes(new byte[]{0, 1});
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(parsed, TestAllTypesNano.ONEOF_BYTES_FIELD_NUMBER);
+ assertTrue(Arrays.equals(new byte[]{0, 1}, parsed.getOneofBytes()));
+ }
+ {
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ }
+ {
+ m.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, m.getOneofEnum());
+ }
+ {
+ m.setOneofFixed64(-1L);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_FIXED64_FIELD_NUMBER);
+ assertEquals(-1L, m.getOneofFixed64());
+ }
+ {
+ m.setOneofNestedMessage(new TestAllTypesNano.NestedMessage());
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_NESTED_MESSAGE_FIELD_NUMBER);
+ assertEquals(
+ new TestAllTypesNano.NestedMessage(), m.getOneofNestedMessage());
+ }
+ {
+ m.setOneofString("hello");
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ assertEquals("hello", m.getOneofString());
+ assertNull(m.getOneofNestedMessage());
+ }
+ {
+ m.setOneofUint32(10);
+ byte[] serialized = MessageNano.toByteArray(m);
+ MessageNano.mergeFrom(parsed, serialized);
+ checkOneofCase(m, TestAllTypesNano.ONEOF_UINT32_FIELD_NUMBER);
+ assertEquals(10, m.getOneofUint32());
+ }
+ }
+
+ public void testOneofSerializedConcat() throws Exception {
+ TestAllTypesNano m1 = new TestAllTypesNano();
+ m1.setOneofBytes(new byte[] {0, 1});
+ byte[] b1 = MessageNano.toByteArray(m1);
+ TestAllTypesNano m2 = new TestAllTypesNano();
+ m2.setOneofEnum(TestAllTypesNano.BAZ);
+ byte[] b2 = MessageNano.toByteArray(m2);
+ byte[] b3 = new byte[b1.length + b2.length];
+ System.arraycopy(b1, 0, b3, 0, b1.length);
+ System.arraycopy(b2, 0, b3, b1.length, b2.length);
+ TestAllTypesNano parsed = new TestAllTypesNano();
+ MessageNano.mergeFrom(parsed, b3);
+ // the last on the wire wins.
+ checkOneofCase(parsed, TestAllTypesNano.ONEOF_ENUM_FIELD_NUMBER);
+ assertEquals(TestAllTypesNano.BAZ, parsed.getOneofEnum());
+ }
+
public void testNullRepeatedFields() throws Exception {
// Check that serialization after explicitly setting a repeated field
// to null doesn't NPE.
@@ -3754,6 +4031,320 @@ public class NanoTest extends TestCase {
assertTrue(Arrays.equals(new boolean[] {false, true, false, true}, nonPacked.bools));
}
+ public void testMapsSerializeAndParse() throws Exception {
+ TestMap origin = new TestMap();
+ setMapMessage(origin);
+ assertMapMessageSet(origin);
+
+ byte[] output = MessageNano.toByteArray(origin);
+ TestMap parsed = new TestMap();
+ MessageNano.mergeFrom(parsed, output);
+ }
+
+ public void testMapSerializeRejectNull() throws Exception {
+ TestMap primitiveMap = new TestMap();
+ primitiveMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+ primitiveMap.int32ToInt32Field.put(null, 1);
+ try {
+ MessageNano.toByteArray(primitiveMap);
+ fail("should reject null keys");
+ } catch (IllegalStateException e) {
+ // pass.
+ }
+
+ TestMap messageMap = new TestMap();
+ messageMap.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ messageMap.int32ToMessageField.put(0, null);
+ try {
+ MessageNano.toByteArray(messageMap);
+ fail("should reject null values");
+ } catch (IllegalStateException e) {
+ // pass.
+ }
+ }
+
+ /**
+ * Tests that merging bytes containing conflicting keys with override the
+ * message value instead of merging the message value into the existing entry.
+ */
+ public void testMapMergeOverrideMessageValues() throws Exception {
+ TestMap.MessageValue origValue = new TestMap.MessageValue();
+ origValue.value = 1;
+ origValue.value2 = 2;
+ TestMap.MessageValue newValue = new TestMap.MessageValue();
+ newValue.value = 3;
+
+ TestMap origMessage = new TestMap();
+ origMessage.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ origMessage.int32ToMessageField.put(1, origValue);
+
+ TestMap newMessage = new TestMap();
+ newMessage.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ newMessage.int32ToMessageField.put(1, newValue);
+ MessageNano.mergeFrom(origMessage,
+ MessageNano.toByteArray(newMessage));
+ TestMap.MessageValue mergedValue = origMessage.int32ToMessageField.get(1);
+ assertEquals(3, mergedValue.value);
+ assertEquals(0, mergedValue.value2);
+ }
+
+ /**
+ * Tests that when merging with empty entries,
+ * we will use default for the key and value, instead of null.
+ */
+ public void testMapMergeEmptyEntry() throws Exception {
+ TestMap testMap = new TestMap();
+ byte[] buffer = new byte[1024];
+ CodedOutputByteBufferNano output =
+ CodedOutputByteBufferNano.newInstance(buffer);
+ // An empty entry for int32_to_int32 map.
+ output.writeTag(1, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(0);
+ // An empty entry for int32_to_message map.
+ output.writeTag(5, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
+ output.writeRawVarint32(0);
+
+ CodedInputByteBufferNano input = CodedInputByteBufferNano.newInstance(
+ buffer, 0, buffer.length - output.spaceLeft());
+ testMap.mergeFrom(input);
+ assertNotNull(testMap.int32ToInt32Field);;
+ assertEquals(1, testMap.int32ToInt32Field.size());
+ assertEquals(Integer.valueOf(0), testMap.int32ToInt32Field.get(0));
+ assertNotNull(testMap.int32ToMessageField);
+ assertEquals(1, testMap.int32ToMessageField.size());
+ TestMap.MessageValue messageValue = testMap.int32ToMessageField.get(0);
+ assertNotNull(messageValue);
+ assertEquals(0, messageValue.value);
+ assertEquals(0, messageValue.value2);
+ }
+
+ public void testMapEquals() throws Exception {
+ TestMap a = new TestMap();
+ TestMap b = new TestMap();
+
+ // empty and null map fields are equal.
+ assertTestMapEqual(a, b);
+ a.int32ToBytesField = new HashMap<Integer, byte[]>();
+ assertTestMapEqual(a, b);
+
+ a.int32ToInt32Field = new HashMap<Integer, Integer>();
+ b.int32ToInt32Field = new HashMap<Integer, Integer>();
+ setMap(a.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+ setMap(b.int32ToInt32Field, deepCopy(int32Values), deepCopy(int32Values));
+ assertTestMapEqual(a, b);
+
+ a.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ b.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ setMap(a.int32ToMessageField,
+ deepCopy(int32Values), deepCopy(messageValues));
+ setMap(b.int32ToMessageField,
+ deepCopy(int32Values), deepCopy(messageValues));
+ assertTestMapEqual(a, b);
+
+ a.stringToInt32Field = new HashMap<String, Integer>();
+ b.stringToInt32Field = new HashMap<String, Integer>();
+ setMap(a.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+ setMap(b.stringToInt32Field, deepCopy(stringValues), deepCopy(int32Values));
+ assertTestMapEqual(a, b);
+
+ a.int32ToBytesField = new HashMap<Integer, byte[]>();
+ b.int32ToBytesField = new HashMap<Integer, byte[]>();
+ setMap(a.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+ setMap(b.int32ToBytesField, deepCopy(int32Values), deepCopy(bytesValues));
+ assertTestMapEqual(a, b);
+
+ // Make sure the map implementation does not matter.
+ a.int32ToStringField = new TreeMap<Integer, String>();
+ b.int32ToStringField = new HashMap<Integer, String>();
+ setMap(a.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+ setMap(b.int32ToStringField, deepCopy(int32Values), deepCopy(stringValues));
+ assertTestMapEqual(a, b);
+
+ a.clear();
+ b.clear();
+
+ // unequal cases: different value
+ a.int32ToInt32Field = new HashMap<Integer, Integer>();
+ b.int32ToInt32Field = new HashMap<Integer, Integer>();
+ a.int32ToInt32Field.put(1, 1);
+ b.int32ToInt32Field.put(1, 2);
+ assertTestMapUnequal(a, b);
+ // unequal case: additional entry
+ b.int32ToInt32Field.put(1, 1);
+ b.int32ToInt32Field.put(2, 1);
+ assertTestMapUnequal(a, b);
+ a.int32ToInt32Field.put(2, 1);
+ assertTestMapEqual(a, b);
+
+ // unequal case: different message value.
+ a.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ b.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ MessageValue va = new MessageValue();
+ va.value = 1;
+ MessageValue vb = new MessageValue();
+ vb.value = 1;
+ a.int32ToMessageField.put(1, va);
+ b.int32ToMessageField.put(1, vb);
+ assertTestMapEqual(a, b);
+ vb.value = 2;
+ assertTestMapUnequal(a, b);
+ }
+
+ private static void assertTestMapEqual(TestMap a, TestMap b)
+ throws Exception {
+ assertEquals(a.hashCode(), b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ private static void assertTestMapUnequal(TestMap a, TestMap b)
+ throws Exception {
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+
+ private static final Integer[] int32Values = new Integer[] {
+ 0, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE,
+ };
+
+ private static final Long[] int64Values = new Long[] {
+ 0L, 1L, -1L, Long.MAX_VALUE, Long.MIN_VALUE,
+ };
+
+ private static final String[] stringValues = new String[] {
+ "", "hello", "world", "foo", "bar",
+ };
+
+ private static final byte[][] bytesValues = new byte[][] {
+ new byte[] {},
+ new byte[] {0},
+ new byte[] {1, -1},
+ new byte[] {127, -128},
+ new byte[] {'a', 'b', '0', '1'},
+ };
+
+ private static final Boolean[] boolValues = new Boolean[] {
+ false, true,
+ };
+
+ private static final Integer[] enumValues = new Integer[] {
+ TestMap.FOO, TestMap.BAR, TestMap.BAZ, TestMap.QUX,
+ Integer.MAX_VALUE /* unknown */,
+ };
+
+ private static final TestMap.MessageValue[] messageValues =
+ new TestMap.MessageValue[] {
+ newMapValueMessage(0),
+ newMapValueMessage(1),
+ newMapValueMessage(-1),
+ newMapValueMessage(Integer.MAX_VALUE),
+ newMapValueMessage(Integer.MIN_VALUE),
+ };
+
+ private static TestMap.MessageValue newMapValueMessage(int value) {
+ TestMap.MessageValue result = new TestMap.MessageValue();
+ result.value = value;
+ return result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <T> T[] deepCopy(T[] orig) throws Exception {
+ if (orig instanceof MessageValue[]) {
+ MessageValue[] result = new MessageValue[orig.length];
+ for (int i = 0; i < orig.length; i++) {
+ result[i] = new MessageValue();
+ MessageNano.mergeFrom(
+ result[i], MessageNano.toByteArray((MessageValue) orig[i]));
+ }
+ return (T[]) result;
+ }
+ if (orig instanceof byte[][]) {
+ byte[][] result = new byte[orig.length][];
+ for (int i = 0; i < orig.length; i++) {
+ byte[] origBytes = (byte[]) orig[i];
+ result[i] = Arrays.copyOf(origBytes, origBytes.length);
+ }
+ }
+ return Arrays.copyOf(orig, orig.length);
+ }
+
+ private <K, V> void setMap(Map<K, V> map, K[] keys, V[] values) {
+ assert(keys.length == values.length);
+ for (int i = 0; i < keys.length; i++) {
+ map.put(keys[i], values[i]);
+ }
+ }
+
+ private <K, V> void assertMapSet(
+ Map<K, V> map, K[] keys, V[] values) throws Exception {
+ assert(keys.length == values.length);
+ for (int i = 0; i < values.length; i++) {
+ assertEquals(values[i], map.get(keys[i]));
+ }
+ assertEquals(keys.length, map.size());
+ }
+
+ private void setMapMessage(TestMap testMap) {
+ testMap.int32ToInt32Field = new HashMap<Integer, Integer>();
+ testMap.int32ToBytesField = new HashMap<Integer, byte[]>();
+ testMap.int32ToEnumField = new HashMap<Integer, Integer>();
+ testMap.int32ToMessageField =
+ new HashMap<Integer, MapTestProto.TestMap.MessageValue>();
+ testMap.int32ToStringField = new HashMap<Integer, String>();
+ testMap.stringToInt32Field = new HashMap<String, Integer>();
+ testMap.boolToBoolField = new HashMap<Boolean, Boolean>();
+ testMap.uint32ToUint32Field = new HashMap<Integer, Integer>();
+ testMap.sint32ToSint32Field = new HashMap<Integer, Integer>();
+ testMap.fixed32ToFixed32Field = new HashMap<Integer, Integer>();
+ testMap.sfixed32ToSfixed32Field = new HashMap<Integer, Integer>();
+ testMap.int64ToInt64Field = new HashMap<Long, Long>();
+ testMap.uint64ToUint64Field = new HashMap<Long, Long>();
+ testMap.sint64ToSint64Field = new HashMap<Long, Long>();
+ testMap.fixed64ToFixed64Field = new HashMap<Long, Long>();
+ testMap.sfixed64ToSfixed64Field = new HashMap<Long, Long>();
+ setMap(testMap.int32ToInt32Field, int32Values, int32Values);
+ setMap(testMap.int32ToBytesField, int32Values, bytesValues);
+ setMap(testMap.int32ToEnumField, int32Values, enumValues);
+ setMap(testMap.int32ToMessageField, int32Values, messageValues);
+ setMap(testMap.int32ToStringField, int32Values, stringValues);
+ setMap(testMap.stringToInt32Field, stringValues, int32Values);
+ setMap(testMap.boolToBoolField, boolValues, boolValues);
+ setMap(testMap.uint32ToUint32Field, int32Values, int32Values);
+ setMap(testMap.sint32ToSint32Field, int32Values, int32Values);
+ setMap(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+ setMap(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+ setMap(testMap.int64ToInt64Field, int64Values, int64Values);
+ setMap(testMap.uint64ToUint64Field, int64Values, int64Values);
+ setMap(testMap.sint64ToSint64Field, int64Values, int64Values);
+ setMap(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+ setMap(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+ }
+ private void assertMapMessageSet(TestMap testMap) throws Exception {
+ assertMapSet(testMap.int32ToInt32Field, int32Values, int32Values);
+ assertMapSet(testMap.int32ToBytesField, int32Values, bytesValues);
+ assertMapSet(testMap.int32ToEnumField, int32Values, enumValues);
+ assertMapSet(testMap.int32ToMessageField, int32Values, messageValues);
+ assertMapSet(testMap.int32ToStringField, int32Values, stringValues);
+ assertMapSet(testMap.stringToInt32Field, stringValues, int32Values);
+ assertMapSet(testMap.boolToBoolField, boolValues, boolValues);
+ assertMapSet(testMap.uint32ToUint32Field, int32Values, int32Values);
+ assertMapSet(testMap.sint32ToSint32Field, int32Values, int32Values);
+ assertMapSet(testMap.fixed32ToFixed32Field, int32Values, int32Values);
+ assertMapSet(testMap.sfixed32ToSfixed32Field, int32Values, int32Values);
+ assertMapSet(testMap.int64ToInt64Field, int64Values, int64Values);
+ assertMapSet(testMap.uint64ToUint64Field, int64Values, int64Values);
+ assertMapSet(testMap.sint64ToSint64Field, int64Values, int64Values);
+ assertMapSet(testMap.fixed64ToFixed64Field, int64Values, int64Values);
+ assertMapSet(testMap.sfixed64ToSfixed64Field, int64Values, int64Values);
+ }
+
private void assertRepeatedPackablesEqual(
NanoRepeatedPackables.NonPacked nonPacked, NanoRepeatedPackables.Packed packed) {
// Not using MessageNano.equals() -- that belongs to a separate test.
diff --git a/javanano/src/test/java/com/google/protobuf/nano/map_test.proto b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
new file mode 100644
index 00000000..f72833ad
--- /dev/null
+++ b/javanano/src/test/java/com/google/protobuf/nano/map_test.proto
@@ -0,0 +1,70 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+package map_test;
+
+option java_package = "com.google.protobuf.nano";
+option java_outer_classname = "MapTestProto";
+
+message TestMap {
+ message MessageValue {
+ int32 value = 1;
+ int32 value2 = 2;
+ }
+ enum EnumValue {
+ FOO = 0;
+ BAR = 1;
+ BAZ = 2;
+ QUX = 3;
+ }
+
+ map<int32, int32> int32_to_int32_field = 1;
+ map<int32, string> int32_to_string_field = 2;
+ map<int32, bytes> int32_to_bytes_field = 3;
+ map<int32, EnumValue> int32_to_enum_field = 4;
+ map<int32, MessageValue> int32_to_message_field = 5;
+ map<string, int32> string_to_int32_field = 6;
+ map<bool, bool> bool_to_bool_field = 7;
+
+ // Test all the other primitive types. As the key and value are not coupled in
+ // the implementation, we do not test all the combinations of key/value pairs,
+ // so that we can keep the number of test cases manageable
+ map<uint32, uint32> uint32_to_uint32_field = 11;
+ map<sint32, sint32> sint32_to_sint32_field = 12;
+ map<fixed32, fixed32> fixed32_to_fixed32_field = 13;
+ map<sfixed32, sfixed32> sfixed32_to_sfixed32_field = 14;
+ map<int64, int64> int64_to_int64_field = 15;
+ map<uint64, uint64> uint64_to_uint64_field = 16;
+ map<sint64, sint64> sint64_to_sint64_field = 17;
+ map<fixed64, fixed64> fixed64_to_fixed64_field = 18;
+ map<sfixed64, sfixed64> sfixed64_to_sfixed64_field = 19;
+}
diff --git a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
index 4519533c..efaf5269 100644
--- a/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
+++ b/javanano/src/test/java/com/google/protobuf/nano/unittest_nano.proto
@@ -167,6 +167,15 @@ message TestAllTypesNano {
// Try to fail with java reserved keywords
optional int32 synchronized = 96;
+
+ oneof oneof_field {
+ uint32 oneof_uint32 = 111;
+ NestedMessage oneof_nested_message = 112;
+ string oneof_string = 123;
+ bytes oneof_bytes = 124;
+ fixed64 oneof_fixed64 = 115;
+ NestedEnum oneof_enum = 116;
+ }
}
message ForeignMessageNano {