aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--java/pom.xml6
-rw-r--r--java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java17
-rw-r--r--java/src/main/java/com/google/protobuf/nano/Extension.java114
-rw-r--r--java/src/main/java/com/google/protobuf/nano/MessageNano.java2
-rw-r--r--java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java47
-rw-r--r--java/src/main/java/com/google/protobuf/nano/WireFormatNano.java225
-rw-r--r--java/src/test/java/com/google/protobuf/NanoTest.java96
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc96
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.h74
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_file.cc11
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc93
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h9
-rw-r--r--src/google/protobuf/unittest_extension_nano.proto44
15 files changed, 812 insertions, 25 deletions
diff --git a/Android.mk b/Android.mk
index dd48922..6a7c6c0 100644
--- a/Android.mk
+++ b/Android.mk
@@ -108,6 +108,7 @@ COMPILER_SRC_FILES := \
src/google/protobuf/compiler/javamicro/javamicro_primitive_field.cc \
src/google/protobuf/compiler/javanano/javanano_enum.cc \
src/google/protobuf/compiler/javanano/javanano_enum_field.cc \
+ src/google/protobuf/compiler/javanano/javanano_extension.cc \
src/google/protobuf/compiler/javanano/javanano_field.cc \
src/google/protobuf/compiler/javanano/javanano_file.cc \
src/google/protobuf/compiler/javanano/javanano_generator.cc \
diff --git a/java/pom.xml b/java/pom.xml
index 46fc764..0b9f6e4 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -138,6 +138,12 @@
<arg value="../src/google/protobuf/unittest_import_nano.proto" />
<arg value="../src/google/protobuf/unittest_enum_multiplejava_nano.proto" />
</exec>
+ <exec executable="../src/protoc">
+ <arg value="--javanano_out=store_unknown_fields=true:target/generated-test-sources" />
+ <arg value="--proto_path=../src" />
+ <arg value="--proto_path=src/test/java" />
+ <arg value="../src/google/protobuf/unittest_extension_nano.proto" />
+ </exec>
</tasks>
<testSourceRoot>target/generated-test-sources</testSourceRoot>
<!--testSourceRoot>target/generated-test-sources/opt-space</testSourceRoot-->
diff --git a/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
index ed38788..c5fea5a 100644
--- a/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/CodedInputByteBufferNano.java
@@ -541,6 +541,23 @@ public final class CodedInputByteBufferNano {
}
/**
+ * Retrieves a subset of data in the buffer. The returned array is not backed by the original
+ * buffer array.
+ *
+ * @param offset the position (relative to the buffer start position) to start at.
+ * @param length the number of bytes to retrieve.
+ */
+ public byte[] getData(int offset, int length) {
+ if (length == 0) {
+ return WireFormatNano.EMPTY_BYTES;
+ }
+ byte[] copy = new byte[length];
+ int start = bufferStart + offset;
+ System.arraycopy(buffer, start, copy, 0, length);
+ return copy;
+ }
+
+ /**
* Rewind to previous position. Cannot go forward.
*/
public void rewindToPosition(int position) {
diff --git a/java/src/main/java/com/google/protobuf/nano/Extension.java b/java/src/main/java/com/google/protobuf/nano/Extension.java
new file mode 100644
index 0000000..4512b01
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/nano/Extension.java
@@ -0,0 +1,114 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.List;
+
+/**
+ * Represents an extension.
+ *
+ * @author bduff@google.com (Brian Duff)
+ * @param <T> the type of the extension.
+ */
+public class Extension<T> {
+ public final int fieldNumber;
+ public boolean isRepeatedField;
+ public Class<T> fieldType;
+ public Class<T> listType;
+
+ private Extension(int fieldNumber, TypeLiteral<T> type) {
+ this.fieldNumber = fieldNumber;
+ isRepeatedField = type.isList();
+ fieldType = type.getTargetClass();
+ listType = isRepeatedField ? type.getListType() : null;
+ }
+
+ /**
+ * Creates a new instance of {@code Extension} for the specified {@code fieldNumber} and
+ * {@code type}.
+ */
+ public static <T> Extension<T> create(int fieldNumber, TypeLiteral<T> type) {
+ return new Extension<T>(fieldNumber, type);
+ }
+
+ /**
+ * Creates a new instance of {@code Extension} for the specified {@code fieldNumber} and
+ * {@code type}. This version is used for repeated fields.
+ */
+ public static <T> Extension<List<T>> createRepeated(int fieldNumber, TypeLiteral<List<T>> type) {
+ return new Extension<List<T>>(fieldNumber, type);
+ }
+
+ /**
+ * Represents a generic type literal. We can't typesafely reference a
+ * Class&lt;List&lt;Foo>>.class in Java, so we use this instead.
+ * See: http://gafter.blogspot.com/2006/12/super-type-tokens.html
+ *
+ * <p>Somewhat specialized because we only ever have a Foo or a List&lt;Foo>.
+ */
+ public static abstract class TypeLiteral<T> {
+ private final Type type;
+
+ protected TypeLiteral() {
+ Type superclass = getClass().getGenericSuperclass();
+ if (superclass instanceof Class) {
+ throw new RuntimeException("Missing type parameter");
+ }
+ this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
+ }
+
+ /**
+ * If the generic type is a list, returns {@code true}.
+ */
+ private boolean isList() {
+ return type instanceof ParameterizedType;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<T> getListType() {
+ return (Class<T>) ((ParameterizedType) type).getRawType();
+ }
+
+ /**
+ * If the generic type is a list, returns the type of element in the list. Otherwise,
+ * returns the actual type.
+ */
+ @SuppressWarnings("unchecked")
+ private Class<T> getTargetClass() {
+ if (isList()) {
+ return (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
+ }
+ return (Class<T>) type;
+ }
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/nano/MessageNano.java b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
index d6c1e9a..5c1eb2f 100644
--- a/java/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -93,7 +93,7 @@ public abstract class MessageNano {
output.checkNoSpaceLeft();
} catch (IOException e) {
throw new RuntimeException("Serializing to a byte array threw an IOException "
- + "(should never happen).");
+ + "(should never happen).", e);
}
}
diff --git a/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java b/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
new file mode 100644
index 0000000..0db2a83
--- /dev/null
+++ b/java/src/main/java/com/google/protobuf/nano/UnknownFieldData.java
@@ -0,0 +1,47 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2013 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.nano;
+
+/**
+ * Stores unknown fields. These might be extensions or fields that the generated API doesn't
+ * know about yet.
+ *
+ * @author bduff@google.com (Brian Duff)
+ */
+public final class UnknownFieldData {
+ final int tag;
+ final byte[] bytes;
+
+ UnknownFieldData(int tag, byte[] bytes) {
+ this.tag = tag;
+ this.bytes = bytes;
+ }
+}
diff --git a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
index 8fa3636..c901e59 100644
--- a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
@@ -31,6 +31,9 @@
package com.google.protobuf.nano;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
/**
* This class is used internally by the Protocol Buffer library and generated
@@ -97,8 +100,12 @@ public final class WireFormatNano {
public static final byte[] EMPTY_BYTES = {};
/**
- * Called by subclasses to parse an unknown field.
- * @return {@code true} unless the tag is an end-group tag.
+ * Parses an unknown field. This implementation skips the field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is off.
+ *
+ * @return {@literal true} unless the tag is an end-group tag.
*/
public static boolean parseUnknownField(
final CodedInputByteBufferNano input,
@@ -107,6 +114,30 @@ public final class WireFormatNano {
}
/**
+ * Stores the binary data of an unknown field.
+ *
+ * <p>Generated messages will call this for unknown fields if the store_unknown_fields
+ * option is on.
+ *
+ * @param data a Collection in which to store the data.
+ * @param input the input buffer.
+ * @param tag the tag of the field.
+
+ * @return {@literal true} unless the tag is an end-group tag.
+ */
+ public static boolean storeUnknownField(
+ final List<UnknownFieldData> data,
+ final CodedInputByteBufferNano input,
+ final int tag) throws IOException {
+ int startPos = input.getPosition();
+ boolean skip = input.skipField(tag);
+ int endPos = input.getPosition();
+ byte[] bytes = input.getData(startPos, endPos - startPos);
+ data.add(new UnknownFieldData(tag, bytes));
+ return skip;
+ }
+
+ /**
* Computes the array length of a repeated field. We assume that in the common case repeated
* fields are contiguously serialized but we still correctly handle interspersed values of a
* repeated field (but with extra allocations).
@@ -135,4 +166,194 @@ public final class WireFormatNano {
input.rewindToPosition(startPos);
return arrayLength;
}
+
+ /**
+ * Decodes the value of an extension.
+ */
+ public static <T> T getExtension(Extension<T> extension, List<UnknownFieldData> unknownFields) {
+ if (unknownFields == null) {
+ return null;
+ }
+ List<UnknownFieldData> dataForField = new ArrayList<UnknownFieldData>();
+ for (UnknownFieldData data : unknownFields) {
+ if (getTagFieldNumber(data.tag) == extension.fieldNumber) {
+ dataForField.add(data);
+ }
+ }
+ if (dataForField.isEmpty()) {
+ return null;
+ }
+
+ if (extension.isRepeatedField) {
+ List<Object> result = new ArrayList<Object>(dataForField.size());
+ for (UnknownFieldData data : dataForField) {
+ result.add(readData(extension.fieldType, data.bytes));
+ }
+ return extension.listType.cast(result);
+ }
+
+ // Normal fields. Note that the protobuf docs require us to handle multiple instances
+ // of the same field even for fields that are not repeated.
+ UnknownFieldData lastData = dataForField.get(dataForField.size() - 1);
+ return readData(extension.fieldType, lastData.bytes);
+ }
+
+ /**
+ * Reads (extension) data of the specified type from the specified byte array.
+ *
+ * @throws IllegalArgumentException if an error occurs while reading the data.
+ */
+ private static <T> T readData(Class<T> clazz, byte[] data) {
+ if (data.length == 0) {
+ return null;
+ }
+ CodedInputByteBufferNano buffer = CodedInputByteBufferNano.newInstance(data);
+ try {
+ if (clazz == String.class) {
+ return clazz.cast(buffer.readString());
+ } else if (clazz == Integer.class) {
+ return clazz.cast(buffer.readInt32());
+ } else if (clazz == Long.class) {
+ return clazz.cast(buffer.readInt64());
+ } else if (clazz == Boolean.class) {
+ return clazz.cast(buffer.readBool());
+ } else if (clazz == Float.class) {
+ return clazz.cast(buffer.readFloat());
+ } else if (clazz == Double.class) {
+ return clazz.cast(buffer.readDouble());
+ } else if (clazz == byte[].class) {
+ return clazz.cast(buffer.readBytes());
+ } else if (MessageNano.class.isAssignableFrom(clazz)) {
+ try {
+ MessageNano message = (MessageNano) clazz.newInstance();
+ buffer.readMessage(message);
+ return clazz.cast(message);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException("Error creating instance of class " + clazz, e);
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException("Error creating instance of class " + clazz, e);
+ }
+ } else {
+ throw new IllegalArgumentException("Unhandled extension field type: " + clazz);
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ public static <T> void setExtension(Extension<T> extension, T value,
+ List<UnknownFieldData> unknownFields) {
+ // First, remove all unknown fields with this tag.
+ for (Iterator<UnknownFieldData> i = unknownFields.iterator(); i.hasNext();) {
+ UnknownFieldData data = i.next();
+ if (extension.fieldNumber == getTagFieldNumber(data.tag)) {
+ i.remove();
+ }
+ }
+ if (value == null) {
+ return;
+ }
+ // Repeated field.
+ if (value instanceof List) {
+ for (Object item : (List<?>) value) {
+ unknownFields.add(write(extension.fieldNumber, item));
+ }
+ } else {
+ unknownFields.add(write(extension.fieldNumber, value));
+ }
+ }
+
+ /**
+ * Writes extension data and returns an {@link UnknownFieldData} containing
+ * bytes and a tag.
+ *
+ * @throws IllegalArgumentException if an error occurs while writing.
+ */
+ private static UnknownFieldData write(int fieldNumber, Object object) {
+ byte[] data;
+ int tag;
+ Class<?> clazz = object.getClass();
+ try {
+ if (clazz == String.class) {
+ String str = (String) object;
+ data = new byte[CodedOutputByteBufferNano.computeStringSizeNoTag(str)];
+ CodedOutputByteBufferNano.newInstance(data).writeStringNoTag(str);
+ tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
+ } else if (clazz == Integer.class) {
+ Integer integer = (Integer) object;
+ data = new byte[CodedOutputByteBufferNano.computeInt32SizeNoTag(integer)];
+ CodedOutputByteBufferNano.newInstance(data).writeInt32NoTag(integer);
+ tag = makeTag(fieldNumber, WIRETYPE_VARINT);
+ } else if (clazz == Long.class) {
+ Long longValue = (Long) object;
+ data = new byte[CodedOutputByteBufferNano.computeInt64SizeNoTag(longValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeInt64NoTag(longValue);
+ tag = makeTag(fieldNumber, WIRETYPE_VARINT);
+ } else if (clazz == Boolean.class) {
+ Boolean boolValue = (Boolean) object;
+ data = new byte[CodedOutputByteBufferNano.computeBoolSizeNoTag(boolValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeBoolNoTag(boolValue);
+ tag = makeTag(fieldNumber, WIRETYPE_VARINT);
+ } else if (clazz == Float.class) {
+ Float floatValue = (Float) object;
+ data = new byte[CodedOutputByteBufferNano.computeFloatSizeNoTag(floatValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeFloatNoTag(floatValue);
+ tag = makeTag(fieldNumber, WIRETYPE_FIXED32);
+ } else if (clazz == Double.class) {
+ Double doubleValue = (Double) object;
+ data = new byte[CodedOutputByteBufferNano.computeDoubleSizeNoTag(doubleValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeDoubleNoTag(doubleValue);
+ tag = makeTag(fieldNumber, WIRETYPE_FIXED64);
+ } else if (clazz == byte[].class) {
+ byte[] byteArrayValue = (byte[]) object;
+ data = new byte[CodedOutputByteBufferNano.computeByteArraySizeNoTag(byteArrayValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeByteArrayNoTag(byteArrayValue);
+ tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
+ } else if (MessageNano.class.isAssignableFrom(clazz)) {
+ MessageNano messageValue = (MessageNano) object;
+
+ int messageSize = messageValue.getSerializedSize();
+ int delimiterSize = CodedOutputByteBufferNano.computeRawVarint32Size(messageSize);
+ data = new byte[messageSize + delimiterSize];
+ CodedOutputByteBufferNano buffer = CodedOutputByteBufferNano.newInstance(data);
+ buffer.writeRawVarint32(messageSize);
+ buffer.writeRawBytes(MessageNano.toByteArray(messageValue));
+ tag = makeTag(fieldNumber, WIRETYPE_LENGTH_DELIMITED);
+ } else {
+ throw new IllegalArgumentException("Unhandled extension field type: " + clazz);
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return new UnknownFieldData(tag, data);
+ }
+
+ /**
+ * Given a set of unknown field data, compute the wire size.
+ */
+ public static int computeWireSize(List<UnknownFieldData> unknownFields) {
+ if (unknownFields == null) {
+ return 0;
+ }
+ int size = 0;
+ for (UnknownFieldData unknownField : unknownFields) {
+ size += CodedOutputByteBufferNano.computeRawVarint32Size(unknownField.tag);
+ size += unknownField.bytes.length;
+ }
+ return size;
+ }
+
+ /**
+ * Write unknown fields.
+ */
+ public static void writeUnknownFields(List<UnknownFieldData> unknownFields,
+ CodedOutputByteBufferNano outBuffer) throws IOException {
+ if (unknownFields == null) {
+ return;
+ }
+ for (UnknownFieldData data : unknownFields) {
+ outBuffer.writeTag(getTagFieldNumber(data.tag), getTagWireType(data.tag));
+ outBuffer.writeRawBytes(data.bytes);
+ }
+ }
}
diff --git a/java/src/test/java/com/google/protobuf/NanoTest.java b/java/src/test/java/com/google/protobuf/NanoTest.java
index da17a9e..38fafb9 100644
--- a/java/src/test/java/com/google/protobuf/NanoTest.java
+++ b/java/src/test/java/com/google/protobuf/NanoTest.java
@@ -30,6 +30,9 @@
package com.google.protobuf;
+import com.google.protobuf.nano.CodedInputByteBufferNano;
+import com.google.protobuf.nano.Extensions;
+import com.google.protobuf.nano.Extensions.AnotherMessage;
import com.google.protobuf.nano.InternalNano;
import com.google.protobuf.nano.MessageNano;
import com.google.protobuf.nano.NanoOuterClass;
@@ -37,10 +40,12 @@ import com.google.protobuf.nano.NanoOuterClass.TestAllTypesNano;
import com.google.protobuf.nano.RecursiveMessageNano;
import com.google.protobuf.nano.SimpleMessageNano;
import com.google.protobuf.nano.UnittestImportNano;
-import com.google.protobuf.nano.CodedInputByteBufferNano;
import junit.framework.TestCase;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Test nano runtime.
*
@@ -2155,4 +2160,93 @@ public class NanoTest extends TestCase {
assertTrue(protoPrint.contains(" default_int32: 41"));
assertTrue(protoPrint.contains(" default_string: \"hello\""));
}
+
+ public void testExtensions() throws Exception {
+ Extensions.ExtendableMessage message = new Extensions.ExtendableMessage();
+ message.field = 5;
+ message.setExtension(Extensions.someString, "Hello World!");
+ message.setExtension(Extensions.someBool, true);
+ message.setExtension(Extensions.someInt, 42);
+ message.setExtension(Extensions.someLong, 124234234234L);
+ message.setExtension(Extensions.someFloat, 42.0f);
+ message.setExtension(Extensions.someDouble, 422222.0);
+ message.setExtension(Extensions.someEnum, Extensions.FIRST_VALUE);
+ AnotherMessage another = new AnotherMessage();
+ another.string = "Foo";
+ another.value = true;
+ message.setExtension(Extensions.someMessage, another);
+
+ message.setExtension(Extensions.someRepeatedString, list("a", "bee", "seeya"));
+ message.setExtension(Extensions.someRepeatedBool, list(true, false, true));
+ message.setExtension(Extensions.someRepeatedInt, list(4, 8, 15, 16, 23, 42));
+ message.setExtension(Extensions.someRepeatedLong, list(4L, 8L, 15L, 16L, 23L, 42L));
+ message.setExtension(Extensions.someRepeatedFloat, list(1.0f, 3.0f));
+ message.setExtension(Extensions.someRepeatedDouble, list(55.133, 3.14159));
+ message.setExtension(Extensions.someRepeatedEnum, list(Extensions.FIRST_VALUE,
+ Extensions.SECOND_VALUE));
+ AnotherMessage second = new AnotherMessage();
+ second.string = "Whee";
+ second.value = false;
+ message.setExtension(Extensions.someRepeatedMessage, list(another, second));
+
+ byte[] data = MessageNano.toByteArray(message);
+
+ Extensions.ExtendableMessage deserialized = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, deserialized.field);
+ assertEquals("Hello World!", deserialized.getExtension(Extensions.someString));
+ assertEquals(Boolean.TRUE, deserialized.getExtension(Extensions.someBool));
+ assertEquals(Integer.valueOf(42), deserialized.getExtension(Extensions.someInt));
+ assertEquals(Long.valueOf(124234234234L), deserialized.getExtension(Extensions.someLong));
+ assertEquals(Float.valueOf(42.0f), deserialized.getExtension(Extensions.someFloat));
+ assertEquals(Double.valueOf(422222.0), deserialized.getExtension(Extensions.someDouble));
+ assertEquals(Integer.valueOf(Extensions.FIRST_VALUE),
+ deserialized.getExtension(Extensions.someEnum));
+ assertEquals(another.string, deserialized.getExtension(Extensions.someMessage).string);
+ assertEquals(another.value, deserialized.getExtension(Extensions.someMessage).value);
+ assertEquals(list("a", "bee", "seeya"), deserialized.getExtension(Extensions.someRepeatedString));
+ assertEquals(list(true, false, true), deserialized.getExtension(Extensions.someRepeatedBool));
+ assertEquals(list(4, 8, 15, 16, 23, 42), deserialized.getExtension(Extensions.someRepeatedInt));
+ assertEquals(list(4L, 8L, 15L, 16L, 23L, 42L), deserialized.getExtension(Extensions.someRepeatedLong));
+ assertEquals(list(1.0f, 3.0f), deserialized.getExtension(Extensions.someRepeatedFloat));
+ assertEquals(list(55.133, 3.14159), deserialized.getExtension(Extensions.someRepeatedDouble));
+ assertEquals(list(Extensions.FIRST_VALUE,
+ Extensions.SECOND_VALUE), deserialized.getExtension(Extensions.someRepeatedEnum));
+ assertEquals("Foo", deserialized.getExtension(Extensions.someRepeatedMessage).get(0).string);
+ assertEquals(true, deserialized.getExtension(Extensions.someRepeatedMessage).get(0).value);
+ assertEquals("Whee", deserialized.getExtension(Extensions.someRepeatedMessage).get(1).string);
+ assertEquals(false, deserialized.getExtension(Extensions.someRepeatedMessage).get(1).value);
+ }
+
+ public void testUnknownFields() throws Exception {
+ // Check that we roundtrip (serialize and deserialize) unrecognized fields.
+ AnotherMessage message = new AnotherMessage();
+ message.string = "Hello World";
+ message.value = false;
+
+ byte[] bytes = MessageNano.toByteArray(message);
+ int extraFieldSize = CodedOutputStream.computeStringSize(1001, "This is an unknown field");
+ byte[] newBytes = new byte[bytes.length + extraFieldSize];
+ System.arraycopy(bytes, 0, newBytes, 0, bytes.length);
+ CodedOutputStream.newInstance(newBytes, bytes.length, extraFieldSize).writeString(1001,
+ "This is an unknown field");
+
+ // Deserialize with an unknown field.
+ AnotherMessage deserialized = AnotherMessage.parseFrom(newBytes);
+ byte[] serialized = MessageNano.toByteArray(deserialized);
+
+ assertEquals(newBytes.length, serialized.length);
+
+ // Clear, and make sure it clears everything.
+ deserialized.clear();
+ assertEquals(0, MessageNano.toByteArray(deserialized).length);
+ }
+
+ private <T> List<T> list(T first, T... remaining) {
+ List<T> list = new ArrayList<T>();
+ list.add(first);
+ for (T item : remaining) {
+ list.add(item);
+ }
+ return list;
+ }
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc
new file mode 100644
index 0000000..ea74af9
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -0,0 +1,96 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// http://code.google.com/p/protobuf/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Author: bduff@google.com (Brian Duff)
+
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
+#include <google/protobuf/compiler/javanano/javanano_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+#include <google/protobuf/wire_format.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+using internal::WireFormat;
+
+void SetVariables(const FieldDescriptor* descriptor, const Params params,
+ map<string, string>* variables) {
+ (*variables)["name"] = UnderscoresToCamelCase(descriptor);
+ (*variables)["number"] = SimpleItoa(descriptor->number());
+ (*variables)["extends"] = ClassName(params, descriptor->containing_type());
+
+ string type;
+ JavaType java_type = GetJavaType(descriptor->type());
+ switch (java_type) {
+ case JAVATYPE_ENUM:
+ type = "java.lang.Integer";
+ break;
+ case JAVATYPE_MESSAGE:
+ type = ClassName(params, descriptor->message_type());
+ break;
+ default:
+ type = BoxedPrimitiveTypeName(java_type);
+ break;
+ }
+ (*variables)["type"] = type;
+}
+
+ExtensionGenerator::
+ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params)
+ : params_(params), descriptor_(descriptor) {
+ SetVariables(descriptor, params, &variables_);
+}
+
+ExtensionGenerator::~ExtensionGenerator() {}
+
+void ExtensionGenerator::Generate(io::Printer* printer) const {
+ if (descriptor_->is_repeated()) {
+ printer->Print(variables_,
+ "// Extends $extends$\n"
+ "public static final com.google.protobuf.nano.Extension<java.util.List<$type$>> $name$ = \n"
+ " com.google.protobuf.nano.Extension.createRepeated($number$,\n"
+ " new com.google.protobuf.nano.Extension.TypeLiteral<java.util.List<$type$>>(){});\n");
+ } else {
+ printer->Print(variables_,
+ "// Extends $extends$\n"
+ "public static final com.google.protobuf.nano.Extension<$type$> $name$ =\n"
+ " com.google.protobuf.nano.Extension.create($number$,\n"
+ " new com.google.protobuf.nano.Extension.TypeLiteral<$type$>(){});\n");
+ }
+}
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.h b/src/google/protobuf/compiler/javanano/javanano_extension.h
new file mode 100644
index 0000000..c6543eb
--- /dev/null
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.h
@@ -0,0 +1,74 @@
+// 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: bduff@google.com (Brian Duff)
+// Based on original Protocol Buffers design by
+// Sanjay Ghemawat, Jeff Dean, and others.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
+#define GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
+
+#include <google/protobuf/stubs/common.h>
+#include <google/protobuf/compiler/javanano/javanano_params.h>
+#include <google/protobuf/descriptor.pb.h>
+
+
+namespace google {
+namespace protobuf {
+ namespace io {
+ class Printer; // printer.h
+ }
+}
+
+namespace protobuf {
+namespace compiler {
+namespace javanano {
+
+class ExtensionGenerator {
+ public:
+ explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params);
+ ~ExtensionGenerator();
+
+ void Generate(io::Printer* printer) const;
+
+ private:
+ const Params& params_;
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator);
+};
+
+} // namespace javanano
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
+
+#endif // GOOGLE_PROTOBUF_COMPILER_JAVA_EXTENSION_H_
diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc
index 2f42fa0..6efa2bf 100644
--- a/src/google/protobuf/compiler/javanano/javanano_file.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_file.cc
@@ -34,6 +34,7 @@
#include <google/protobuf/compiler/javanano/javanano_file.h>
#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
#include <google/protobuf/compiler/javanano/javanano_helpers.h>
#include <google/protobuf/compiler/javanano/javanano_message.h>
#include <google/protobuf/compiler/code_generator.h>
@@ -94,10 +95,11 @@ bool FileGenerator::Validate(string* error) {
// Check for extensions
FileDescriptorProto file_proto;
file_->CopyTo(&file_proto);
- if (UsesExtensions(file_proto)) {
+ if (UsesExtensions(file_proto) && !params_.store_unknown_fields()) {
error->assign(file_->name());
error->append(
- ": Java NANO_RUNTIME does not support extensions\"");
+ ": Java NANO_RUNTIME only supports extensions when the "
+ "'store_unknown_fields' generator option is 'true'.");
return false;
}
@@ -179,6 +181,11 @@ void FileGenerator::Generate(io::Printer* printer) {
// -----------------------------------------------------------------
+ // Extensions.
+ for (int i = 0; i < file_->extension_count(); i++) {
+ ExtensionGenerator(file_->extension(i), params_).Generate(printer);
+ }
+
if (!params_.java_multiple_files()) {
for (int i = 0; i < file_->enum_type_count(); i++) {
EnumGenerator(file_->enum_type(i), params_).Generate(printer);
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index 554f6d4..19a3dcc 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -115,6 +115,8 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
return false;
}
params.set_java_outer_classname(parts[0], parts[1]);
+ } else if (options[i].first == "store_unknown_fields") {
+ params.set_store_unknown_fields(options[i].second == "true");
} else if (options[i].first == "java_multiple_files") {
params.set_java_multiple_files(options[i].second == "true");
} else {
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index f8a4fe7..2740779 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -36,6 +36,7 @@
#include <google/protobuf/stubs/hash.h>
#include <google/protobuf/compiler/javanano/javanano_message.h>
#include <google/protobuf/compiler/javanano/javanano_enum.h>
+#include <google/protobuf/compiler/javanano/javanano_extension.h>
#include <google/protobuf/compiler/javanano/javanano_helpers.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
@@ -117,10 +118,6 @@ void MessageGenerator::GenerateStaticVariableInitializers(
MessageGenerator(descriptor_->nested_type(i), params_)
.GenerateStaticVariableInitializers(printer);
}
-
- if (descriptor_->extension_count() != 0) {
- GOOGLE_LOG(FATAL) << "Extensions not supported in NANO_RUNTIME\n";
- }
}
void MessageGenerator::Generate(io::Printer* printer) {
@@ -135,9 +132,10 @@ void MessageGenerator::Generate(io::Printer* printer) {
GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
#endif
- if ((descriptor_->extension_count() != 0)
- || (descriptor_->extension_range_count() != 0)) {
- GOOGLE_LOG(FATAL) << "Extensions not supported in NANO_RUNTIME\n";
+ if (!params_.store_unknown_fields() &&
+ (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
+ GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
+ "'store_unknown_fields' generator option is 'true'\n";
}
// Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
@@ -156,7 +154,17 @@ void MessageGenerator::Generate(io::Printer* printer) {
"\n",
"classname", descriptor_->name());
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "private java.util.List<com.google.protobuf.nano.UnknownFieldData>\n"
+ " unknownFieldData;\n");
+ }
+
// Nested types and extensions
+ for (int i = 0; i < descriptor_->extension_count(); i++) {
+ ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
+ }
+
for (int i = 0; i < descriptor_->enum_type_count(); i++) {
EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
}
@@ -173,6 +181,24 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
GenerateClear(printer);
+
+ // If we have an extension range, generate accessors for extensions.
+ if (params_.store_unknown_fields()
+ && descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ "public <T> T getExtension(com.google.protobuf.nano.Extension<T> extension) {\n"
+ " return com.google.protobuf.nano.WireFormatNano.getExtension(\n"
+ " extension, unknownFieldData);\n"
+ "}\n\n"
+ "public <T> void setExtension(com.google.protobuf.nano.Extension<T> extension, T value) {\n"
+ " if (unknownFieldData == null) {\n"
+ " unknownFieldData = \n"
+ " new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
+ " }\n"
+ " com.google.protobuf.nano.WireFormatNano.setExtension(\n"
+ " extension, value, unknownFieldData);\n"
+ "}\n\n");
+ }
GenerateMessageSerializationMethods(printer);
GenerateMergeFromMethods(printer);
GenerateParseFromMethods(printer);
@@ -188,12 +214,8 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
scoped_array<const FieldDescriptor*> sorted_fields(
SortFieldsByNumber(descriptor_));
- if (descriptor_->extension_range_count() != 0) {
- GOOGLE_LOG(FATAL) << "Extensions not supported in NANO_RUNTIME\n";
- }
-
// writeTo only throws an exception if it contains one or more fields to write
- if (descriptor_->field_count() > 0) {
+ if (descriptor_->field_count() > 0 || params_.store_unknown_fields()) {
printer->Print(
"@Override\n"
"public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
@@ -207,7 +229,14 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
// Output the fields in sorted order
for (int i = 0; i < descriptor_->field_count(); i++) {
- GenerateSerializeOneField(printer, sorted_fields[i]);
+ GenerateSerializeOneField(printer, sorted_fields[i]);
+ }
+
+ // Write unknown fields.
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "com.google.protobuf.nano.WireFormatNano.writeUnknownFields(\n"
+ " unknownFieldData, output);\n");
}
printer->Outdent();
@@ -233,6 +262,11 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
}
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "size += com.google.protobuf.nano.WireFormatNano.computeWireSize(unknownFieldData);\n");
+ }
+
printer->Outdent();
printer->Print(
" cachedSize = size;\n"
@@ -266,12 +300,28 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
printer->Print(
"case 0:\n" // zero signals EOF / limit reached
" return this;\n"
- "default: {\n"
- " if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
- " return this;\n" // it's an endgroup tag
- " }\n"
- " break;\n"
- "}\n");
+ "default: {\n");
+
+ printer->Indent();
+ if (params_.store_unknown_fields()) {
+ printer->Print(
+ "if (unknownFieldData == null) {\n"
+ " unknownFieldData = \n"
+ " new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
+ "}\n"
+ "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(unknownFieldData, \n"
+ " input, tag)) {\n"
+ " return this;\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
+ " return this;\n" // it's an endgroup tag
+ "}\n");
+ }
+ printer->Print("break;\n");
+ printer->Outdent();
+ printer->Print("}\n");
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = sorted_fields[i];
@@ -356,6 +406,11 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
}
}
+ // Clear unknown fields.
+ if (params_.store_unknown_fields()) {
+ printer->Print("unknownFieldData = null;\n");
+ }
+
printer->Outdent();
printer->Print(
" cachedSize = -1;\n"
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index f6192ea..30eedff 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -49,6 +49,7 @@ class Params {
string empty_;
string base_name_;
bool java_multiple_files_;
+ bool store_unknown_fields_;
NameMap java_packages_;
NameMap java_outer_classnames_;
@@ -56,6 +57,7 @@ class Params {
Params(const string & base_name) :
empty_(""),
base_name_(base_name),
+ store_unknown_fields_(false),
java_multiple_files_(false) {
}
@@ -107,6 +109,13 @@ class Params {
return java_outer_classnames_;
}
+ void set_store_unknown_fields(bool value) {
+ store_unknown_fields_ = value;
+ }
+ bool store_unknown_fields() const {
+ return store_unknown_fields_;
+ }
+
void set_java_multiple_files(bool value) {
java_multiple_files_ = value;
}
diff --git a/src/google/protobuf/unittest_extension_nano.proto b/src/google/protobuf/unittest_extension_nano.proto
new file mode 100644
index 0000000..f2906f0
--- /dev/null
+++ b/src/google/protobuf/unittest_extension_nano.proto
@@ -0,0 +1,44 @@
+syntax = "proto2";
+
+option java_outer_classname = "Extensions";
+option java_package = "com.google.protobuf.nano";
+
+message ExtendableMessage {
+ optional int32 field = 1;
+ extensions 10 to max;
+}
+
+enum AnEnum {
+ FIRST_VALUE = 1;
+ SECOND_VALUE = 2;
+}
+
+message AnotherMessage {
+ optional string string = 1;
+ optional bool value = 2;
+}
+
+extend ExtendableMessage {
+ optional string some_string = 10;
+ optional int32 some_int = 11;
+ optional int64 some_long = 12;
+ optional float some_float = 13;
+ optional double some_double = 14;
+ optional bool some_bool = 15;
+ optional AnEnum some_enum = 16;
+ optional AnotherMessage some_message = 17;
+ repeated string some_repeated_string = 18;
+ repeated int32 some_repeated_int = 19;
+ repeated int64 some_repeated_long = 20;
+ repeated float some_repeated_float = 21;
+ repeated double some_repeated_double = 22;
+ repeated bool some_repeated_bool = 23;
+ repeated AnEnum some_repeated_enum = 24;
+ repeated AnotherMessage some_repeated_message = 25;
+}
+
+message ContainerMessage {
+ extend ExtendableMessage {
+ optional bool another_thing = 100;
+ }
+}