aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--java/pom.xml18
-rw-r--r--java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java31
-rw-r--r--java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java64
-rw-r--r--java/src/main/java/com/google/protobuf/nano/Extension.java700
-rw-r--r--java/src/main/java/com/google/protobuf/nano/MessageNano.java15
-rw-r--r--java/src/main/java/com/google/protobuf/nano/WireFormatNano.java236
-rw-r--r--java/src/test/java/com/google/protobuf/NanoTest.java227
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_extension.cc113
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc38
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.h8
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc92
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc20
-rw-r--r--src/google/protobuf/unittest_extension_nano.proto21
-rw-r--r--src/google/protobuf/unittest_extension_packed_nano.proto29
-rw-r--r--src/google/protobuf/unittest_extension_repeated_nano.proto34
-rw-r--r--src/google/protobuf/unittest_extension_singular_nano.proto34
16 files changed, 1142 insertions, 538 deletions
diff --git a/java/pom.xml b/java/pom.xml
index ba281ff..5b49a72 100644
--- a/java/pom.xml
+++ b/java/pom.xml
@@ -158,6 +158,24 @@
<arg value="../src/google/protobuf/unittest_extension_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_singular_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_repeated_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_packed_nano.proto" />
+ </exec>
+ <exec executable="../src/protoc">
<arg value="--javanano_out=java_nano_generate_has=true,generate_equals=true:target/generated-test-sources" />
<arg value="--proto_path=../src" />
<arg value="--proto_path=src/test/java" />
diff --git a/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java b/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
index 769bb19..88df38d 100644
--- a/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/CodedOutputByteBufferNano.java
@@ -168,14 +168,6 @@ public final class CodedOutputByteBufferNano {
writeBytesNoTag(value);
}
- /** Write a {@code byte} field, including tag, to the stream. */
- public void writeByteArray(final int fieldNumber, final byte[] value)
- throws IOException {
- writeTag(fieldNumber, WireFormatNano.WIRETYPE_LENGTH_DELIMITED);
- writeByteArrayNoTag(value);
- }
-
-
/** Write a {@code uint32} field, including tag, to the stream. */
public void writeUInt32(final int fieldNumber, final int value)
throws IOException {
@@ -321,12 +313,6 @@ public final class CodedOutputByteBufferNano {
writeRawBytes(value);
}
- /** Write a {@code byte[]} field to the stream. */
- public void writeByteArrayNoTag(final byte [] value) throws IOException {
- writeRawVarint32(value.length);
- writeRawBytes(value);
- }
-
/** Write a {@code uint32} field to the stream. */
public void writeUInt32NoTag(final int value) throws IOException {
writeRawVarint32(value);
@@ -468,15 +454,6 @@ public final class CodedOutputByteBufferNano {
/**
* Compute the number of bytes that would be needed to encode a
- * {@code byte[]} field, including tag.
- */
- public static int computeByteArraySize(final int fieldNumber,
- final byte[] value) {
- return computeTagSize(fieldNumber) + computeByteArraySizeNoTag(value);
- }
-
- /**
- * Compute the number of bytes that would be needed to encode a
* {@code uint32} field, including tag.
*/
public static int computeUInt32Size(final int fieldNumber, final int value) {
@@ -662,14 +639,6 @@ public final class CodedOutputByteBufferNano {
/**
* Compute the number of bytes that would be needed to encode a
- * {@code byte[]} field.
- */
- public static int computeByteArraySizeNoTag(final byte[] value) {
- return computeRawVarint32Size(value.length) + value.length;
- }
-
- /**
- * Compute the number of bytes that would be needed to encode a
* {@code uint32} field.
*/
public static int computeUInt32SizeNoTag(final int value) {
diff --git a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java b/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
index 066774d..839f21c 100644
--- a/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/ExtendableMessageNano.java
@@ -30,6 +30,7 @@
package com.google.protobuf.nano;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@@ -37,34 +38,81 @@ import java.util.List;
* Base class of those Protocol Buffer messages that need to store unknown fields,
* such as extensions.
*/
-public abstract class ExtendableMessageNano extends MessageNano {
+public abstract class ExtendableMessageNano<M extends ExtendableMessageNano<M>>
+ extends MessageNano {
/**
* A container for fields unknown to the message, including extensions. Extension fields can
- * can be accessed through the {@link getExtension()} and {@link setExtension()} methods.
+ * can be accessed through the {@link #getExtension} and {@link #setExtension} methods.
*/
protected List<UnknownFieldData> unknownFieldData;
@Override
public int getSerializedSize() {
- int size = WireFormatNano.computeWireSize(unknownFieldData);
+ int size = 0;
+ int unknownFieldCount = unknownFieldData == null ? 0 : unknownFieldData.size();
+ for (int i = 0; i < unknownFieldCount; i++) {
+ UnknownFieldData unknownField = unknownFieldData.get(i);
+ size += CodedOutputByteBufferNano.computeRawVarint32Size(unknownField.tag);
+ size += unknownField.bytes.length;
+ }
cachedSize = size;
return size;
}
+ @Override
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ int unknownFieldCount = unknownFieldData == null ? 0 : unknownFieldData.size();
+ for (int i = 0; i < unknownFieldCount; i++) {
+ UnknownFieldData unknownField = unknownFieldData.get(i);
+ output.writeRawVarint32(unknownField.tag);
+ output.writeRawBytes(unknownField.bytes);
+ }
+ }
+
/**
* Gets the value stored in the specified extension of this message.
*/
- public <T> T getExtension(Extension<T> extension) {
- return WireFormatNano.getExtension(extension, unknownFieldData);
+ public final <T> T getExtension(Extension<M, T> extension) {
+ return extension.getValueFrom(unknownFieldData);
}
/**
* Sets the value of the specified extension of this message.
*/
- public <T> void setExtension(Extension<T> extension, T value) {
+ public final <T> M setExtension(Extension<M, T> extension, T value) {
+ unknownFieldData = extension.setValueTo(value, unknownFieldData);
+
+ @SuppressWarnings("unchecked") // Generated code should guarantee type safety
+ M typedThis = (M) this;
+ return typedThis;
+ }
+
+ /**
+ * 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.
+ *
+ * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
+ * which case we do not want to add an unknown field entry.
+ *
+ * @param input the input buffer.
+ * @param tag the tag of the field.
+
+ * @return {@literal true} unless the tag is an end-group tag.
+ */
+ protected final boolean storeUnknownField(CodedInputByteBufferNano input, int tag)
+ throws IOException {
+ int startPos = input.getPosition();
+ if (!input.skipField(tag)) {
+ return false; // This wasn't an unknown field, it's an end-group tag.
+ }
if (unknownFieldData == null) {
unknownFieldData = new ArrayList<UnknownFieldData>();
}
- WireFormatNano.setExtension(extension, value, unknownFieldData);
+ int endPos = input.getPosition();
+ byte[] bytes = input.getData(startPos, endPos - startPos);
+ unknownFieldData.add(new UnknownFieldData(tag, bytes));
+ return true;
}
-} \ No newline at end of file
+}
diff --git a/java/src/main/java/com/google/protobuf/nano/Extension.java b/java/src/main/java/com/google/protobuf/nano/Extension.java
index 4512b01..177a9cc 100644
--- a/java/src/main/java/com/google/protobuf/nano/Extension.java
+++ b/java/src/main/java/com/google/protobuf/nano/Extension.java
@@ -30,85 +30,659 @@
package com.google.protobuf.nano;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
+import java.io.IOException;
+import java.lang.reflect.Array;
+import java.util.ArrayList;
import java.util.List;
/**
* Represents an extension.
*
* @author bduff@google.com (Brian Duff)
- * @param <T> the type of the extension.
+ * @author maxtroy@google.com (Max Cai)
+ * @param <M> the type of the extendable message this extension is for.
+ * @param <T> the Java type of the extension; see {@link #clazz}.
*/
-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];
+public class Extension<M extends ExtendableMessageNano<M>, T> {
+
+ /*
+ * Because we typically only define message-typed extensions, the Extension class hierarchy is
+ * designed as follows, to allow a big amount of code in this file to be removed by ProGuard:
+ *
+ * Extension // ready to use for message/group typed extensions
+ * Δ
+ * |
+ * 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;
+
+ /**
+ * Creates an {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T> createMessageTyped(int type, Class<T> clazz, int tag) {
+ return new Extension<M, T>(type, clazz, tag, false);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given message type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type {@link #TYPE_MESSAGE} or {@link #TYPE_GROUP}
+ */
+ public static <M extends ExtendableMessageNano<M>, T extends MessageNano>
+ Extension<M, T[]> createRepeatedMessageTyped(int type, Class<T[]> clazz, int tag) {
+ return new Extension<M, T[]>(type, clazz, tag, true);
+ }
+
+ /**
+ * Creates an {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the boxed Java type of this extension
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createPrimitiveTyped(int type, Class<T> clazz, int tag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, false, 0, 0);
+ }
+
+ /**
+ * Creates a repeated {@code Extension} of the given primitive type and tag number.
+ * Should be used by the generated code only.
+ *
+ * @param type one of {@code TYPE_*}, except {@link #TYPE_MESSAGE} and {@link #TYPE_GROUP}
+ * @param clazz the Java array type of this extension, with an unboxed component type
+ */
+ public static <M extends ExtendableMessageNano<M>, T>
+ Extension<M, T> createRepeatedPrimitiveTyped(
+ int type, Class<T> clazz, int tag, int nonPackedTag, int packedTag) {
+ return new PrimitiveExtension<M, T>(type, clazz, tag, true, nonPackedTag, packedTag);
+ }
+
+ /**
+ * Protocol Buffer type of this extension; one of the {@code TYPE_} constants.
+ */
+ protected final int type;
+
+ /**
+ * Java type of this extension. For a singular extension, this is the boxed Java type for the
+ * Protocol Buffer {@link #type}; for a repeated extension, this is an array type whose
+ * component type is the unboxed Java type for {@link #type}. For example, for a singular
+ * {@code int32}/{@link #TYPE_INT32} extension, this equals {@code Integer.class}; for a
+ * repeated {@code int32} extension, this equals {@code int[].class}.
+ */
+ protected final Class<T> clazz;
+
+ /**
+ * Tag number of this extension.
+ */
+ protected final int tag;
+
+ /**
+ * Whether this extension is repeated.
+ */
+ protected final boolean repeated;
+
+ private Extension(int type, Class<T> clazz, int tag, boolean repeated) {
+ this.type = type;
+ this.clazz = clazz;
+ this.tag = tag;
+ this.repeated = repeated;
+ }
+
+ protected boolean isMatch(int unknownDataTag) {
+ // This implementation is for message/group extensions.
+ return unknownDataTag == tag;
+ }
+
+ /**
+ * Returns the value of this extension stored in the given list of unknown fields, or
+ * {@code null} if no unknown fields matches this extension.
+ */
+ final T getValueFrom(List<UnknownFieldData> unknownFields) {
+ if (unknownFields == null) {
+ return null;
+ }
+
+ if (repeated) {
+ // For repeated extensions, read all matching unknown fields in their original order.
+ List<Object> resultList = new ArrayList<Object>();
+ for (int i = 0; i < unknownFields.size(); i++) {
+ UnknownFieldData data = unknownFields.get(i);
+ if (isMatch(data.tag) && data.bytes.length != 0) {
+ readDataInto(data, resultList);
+ }
+ }
+
+ int resultSize = resultList.size();
+ if (resultSize == 0) {
+ return null;
+ }
+
+ T result = clazz.cast(Array.newInstance(clazz.getComponentType(), resultSize));
+ for (int i = 0; i < resultSize; i++) {
+ Array.set(result, i, resultList.get(i));
+ }
+ return result;
+ } else {
+ // For singular extensions, get the last piece of data stored under this extension.
+ UnknownFieldData lastData = null;
+ for (int i = unknownFields.size() - 1; lastData == null && i >= 0; i--) {
+ UnknownFieldData data = unknownFields.get(i);
+ if (isMatch(data.tag) && data.bytes.length != 0) {
+ lastData = data;
+ }
+ }
+
+ if (lastData == null) {
+ return null;
+ }
+
+ return clazz.cast(readData(CodedInputByteBufferNano.newInstance(lastData.bytes)));
+ }
+ }
+
+ protected Object readData(CodedInputByteBufferNano input) {
+ // This implementation is for message/group extensions.
+ Class<?> messageType = repeated ? clazz.getComponentType() : clazz;
+ try {
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano group = (MessageNano) messageType.newInstance();
+ input.readGroup(group, WireFormatNano.getTagFieldNumber(tag));
+ return group;
+ case TYPE_MESSAGE:
+ MessageNano message = (MessageNano) messageType.newInstance();
+ input.readMessage(message);
+ return message;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (InstantiationException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalArgumentException(
+ "Error creating instance of class " + messageType, e);
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for message/group extensions.
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
}
/**
- * If the generic type is a list, returns {@code true}.
+ * Sets the value of this extension to the given list of unknown fields. This removes any
+ * previously stored data matching this extension.
+ *
+ * @param value The value of this extension, or {@code null} to clear this extension from the
+ * unknown fields.
+ * @return The same {@code unknownFields} list, or a new list storing the extension value if
+ * the argument was null.
*/
- private boolean isList() {
- return type instanceof ParameterizedType;
+ final List<UnknownFieldData> setValueTo(T value, List<UnknownFieldData> unknownFields) {
+ if (unknownFields != null) {
+ // Delete all data matching this extension
+ for (int i = unknownFields.size() - 1; i >= 0; i--) {
+ if (isMatch(unknownFields.get(i).tag)) {
+ unknownFields.remove(i);
+ }
+ }
+ }
+
+ if (value != null) {
+ if (unknownFields == null) {
+ unknownFields = new ArrayList<UnknownFieldData>();
+ }
+ if (repeated) {
+ writeDataInto(value, unknownFields);
+ } else {
+ unknownFields.add(writeData(value));
+ }
+ }
+
+ // After deletion or no-op addition (due to 'value' being an array of empty or
+ // null-only elements), unknownFields may be empty. Discard the ArrayList if so.
+ return (unknownFields.size() == 0) ? null : unknownFields;
}
- @SuppressWarnings("unchecked")
- private Class<T> getListType() {
- return (Class<T>) ((ParameterizedType) type).getRawType();
+ protected UnknownFieldData writeData(Object value) {
+ // This implementation is for message/group extensions.
+ byte[] data;
+ try {
+ switch (type) {
+ case TYPE_GROUP:
+ MessageNano groupValue = (MessageNano) value;
+ int fieldNumber = WireFormatNano.getTagFieldNumber(tag);
+ data = new byte[CodedOutputByteBufferNano.computeGroupSizeNoTag(groupValue)
+ + CodedOutputByteBufferNano.computeTagSize(fieldNumber)];
+ CodedOutputByteBufferNano out = CodedOutputByteBufferNano.newInstance(data);
+ out.writeGroupNoTag(groupValue);
+ // The endgroup tag must be included in the data payload.
+ out.writeTag(fieldNumber, WireFormatNano.WIRETYPE_END_GROUP);
+ break;
+ case TYPE_MESSAGE:
+ MessageNano messageValue = (MessageNano) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeMessageSizeNoTag(messageValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeMessageNoTag(messageValue);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ return new UnknownFieldData(tag, data);
+ }
+
+ protected void writeDataInto(T array, List<UnknownFieldData> unknownFields) {
+ // This implementation is for non-packed extensions.
+ int arrayLength = Array.getLength(array);
+ for (int i = 0; i < arrayLength; i++) {
+ Object element = Array.get(array, i);
+ if (element != null) {
+ unknownFields.add(writeData(element));
+ }
+ }
}
/**
- * If the generic type is a list, returns the type of element in the list. Otherwise,
- * returns the actual type.
+ * Represents an extension of a primitive (including enum) type. If there is no primitive
+ * extensions, this subclass will be removable by ProGuard.
*/
- @SuppressWarnings("unchecked")
- private Class<T> getTargetClass() {
- if (isList()) {
- return (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
- }
- return (Class<T>) type;
+ private static class PrimitiveExtension<M extends ExtendableMessageNano<M>, T>
+ extends Extension<M, T> {
+
+ /**
+ * Tag of a piece of non-packed data from the wire compatible with this extension.
+ */
+ private final int nonPackedTag;
+
+ /**
+ * Tag of a piece of packed data from the wire compatible with this extension.
+ * 0 if the type of this extension is not packable.
+ */
+ private final int packedTag;
+
+ public PrimitiveExtension(int type, Class<T> clazz, int tag, boolean repeated,
+ int nonPackedTag, int packedTag) {
+ super(type, clazz, tag, repeated);
+ this.nonPackedTag = nonPackedTag;
+ this.packedTag = packedTag;
+ }
+
+ @Override
+ protected boolean isMatch(int unknownDataTag) {
+ if (repeated) {
+ return unknownDataTag == nonPackedTag || unknownDataTag == packedTag;
+ } else {
+ return unknownDataTag == tag;
+ }
+ }
+
+ @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);
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ }
+
+ @Override
+ protected void readDataInto(UnknownFieldData data, List<Object> resultList) {
+ // This implementation is for primitive typed extensions,
+ // which can read both packed and non-packed data.
+ if (data.tag == nonPackedTag) {
+ resultList.add(readData(CodedInputByteBufferNano.newInstance(data.bytes)));
+ } else {
+ CodedInputByteBufferNano buffer = CodedInputByteBufferNano.newInstance(data.bytes);
+ try {
+ buffer.pushLimit(buffer.readRawVarint32()); // length limit
+ } catch (IOException e) {
+ throw new IllegalArgumentException("Error reading extension field", e);
+ }
+ while (!buffer.isAtEnd()) {
+ resultList.add(readData(buffer));
+ }
+ }
+ }
+
+ @Override
+ protected final UnknownFieldData writeData(Object value) {
+ byte[] data;
+ try {
+ switch (type) {
+ case TYPE_DOUBLE:
+ Double doubleValue = (Double) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeDoubleSizeNoTag(doubleValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeDoubleNoTag(doubleValue);
+ break;
+ case TYPE_FLOAT:
+ Float floatValue = (Float) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeFloatSizeNoTag(floatValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeFloatNoTag(floatValue);
+ break;
+ case TYPE_INT64:
+ Long int64Value = (Long) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeInt64SizeNoTag(int64Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeInt64NoTag(int64Value);
+ break;
+ case TYPE_UINT64:
+ Long uint64Value = (Long) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeUInt64SizeNoTag(uint64Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeUInt64NoTag(uint64Value);
+ break;
+ case TYPE_INT32:
+ Integer int32Value = (Integer) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeInt32SizeNoTag(int32Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeInt32NoTag(int32Value);
+ break;
+ case TYPE_FIXED64:
+ Long fixed64Value = (Long) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeFixed64SizeNoTag(fixed64Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeFixed64NoTag(fixed64Value);
+ break;
+ case TYPE_FIXED32:
+ Integer fixed32Value = (Integer) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeFixed32SizeNoTag(fixed32Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeFixed32NoTag(fixed32Value);
+ break;
+ case TYPE_BOOL:
+ Boolean boolValue = (Boolean) value;
+ data = new byte[CodedOutputByteBufferNano.computeBoolSizeNoTag(boolValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeBoolNoTag(boolValue);
+ break;
+ case TYPE_STRING:
+ String stringValue = (String) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeStringSizeNoTag(stringValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeStringNoTag(stringValue);
+ break;
+ case TYPE_BYTES:
+ byte[] bytesValue = (byte[]) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeBytesSizeNoTag(bytesValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeBytesNoTag(bytesValue);
+ break;
+ case TYPE_UINT32:
+ Integer uint32Value = (Integer) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeUInt32SizeNoTag(uint32Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeUInt32NoTag(uint32Value);
+ break;
+ case TYPE_ENUM:
+ Integer enumValue = (Integer) value;
+ data = new byte[CodedOutputByteBufferNano.computeEnumSizeNoTag(enumValue)];
+ CodedOutputByteBufferNano.newInstance(data).writeEnumNoTag(enumValue);
+ break;
+ case TYPE_SFIXED32:
+ Integer sfixed32Value = (Integer) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeSFixed32SizeNoTag(sfixed32Value)];
+ CodedOutputByteBufferNano.newInstance(data)
+ .writeSFixed32NoTag(sfixed32Value);
+ break;
+ case TYPE_SFIXED64:
+ Long sfixed64Value = (Long) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeSFixed64SizeNoTag(sfixed64Value)];
+ CodedOutputByteBufferNano.newInstance(data)
+ .writeSFixed64NoTag(sfixed64Value);
+ break;
+ case TYPE_SINT32:
+ Integer sint32Value = (Integer) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeSInt32SizeNoTag(sint32Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeSInt32NoTag(sint32Value);
+ break;
+ case TYPE_SINT64:
+ Long sint64Value = (Long) value;
+ data = new byte[
+ CodedOutputByteBufferNano.computeSInt64SizeNoTag(sint64Value)];
+ CodedOutputByteBufferNano.newInstance(data).writeSInt64NoTag(sint64Value);
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen
+ throw new IllegalStateException(e);
+ }
+ return new UnknownFieldData(tag, data);
+ }
+
+ @Override
+ protected void writeDataInto(T array, List<UnknownFieldData> unknownFields) {
+ if (tag == nonPackedTag) {
+ // Use base implementation for non-packed data
+ super.writeDataInto(array, unknownFields);
+ } else if (tag == packedTag) {
+ // Packed. Note that the array element type is guaranteed to be primitive, so there
+ // won't be any null elements, so no null check in this block. First get data size.
+ int arrayLength = Array.getLength(array);
+ int dataSize = 0;
+ switch (type) {
+ case TYPE_BOOL:
+ // Bools are stored as int32 but just as 0 or 1, so 1 byte each.
+ dataSize = arrayLength;
+ break;
+ case TYPE_FIXED32:
+ case TYPE_SFIXED32:
+ case TYPE_FLOAT:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_32_SIZE;
+ break;
+ case TYPE_FIXED64:
+ case TYPE_SFIXED64:
+ case TYPE_DOUBLE:
+ dataSize = arrayLength * CodedOutputByteBufferNano.LITTLE_ENDIAN_64_SIZE;
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt32SizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeSInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeUInt64SizeNoTag(
+ Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ dataSize += CodedOutputByteBufferNano.computeEnumSizeNoTag(
+ Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unexpected non-packable type " + type);
+ }
+
+ // Then construct payload.
+ int payloadSize =
+ dataSize + CodedOutputByteBufferNano.computeRawVarint32Size(dataSize);
+ byte[] data = new byte[payloadSize];
+ CodedOutputByteBufferNano output = CodedOutputByteBufferNano.newInstance(data);
+ try {
+ output.writeRawVarint32(dataSize);
+ switch (type) {
+ case TYPE_BOOL:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeBoolNoTag(Array.getBoolean(array, i));
+ }
+ break;
+ case TYPE_FIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SFIXED32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_FLOAT:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFloatNoTag(Array.getFloat(array, i));
+ }
+ break;
+ case TYPE_FIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SFIXED64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSFixed64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_DOUBLE:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeDoubleNoTag(Array.getDouble(array, i));
+ }
+ break;
+ case TYPE_INT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_SINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_UINT32:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt32NoTag(Array.getInt(array, i));
+ }
+ break;
+ case TYPE_INT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_SINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeSInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_UINT64:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeUInt64NoTag(Array.getLong(array, i));
+ }
+ break;
+ case TYPE_ENUM:
+ for (int i = 0; i < arrayLength; i++) {
+ output.writeEnumNoTag(Array.getInt(array, i));
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unpackable type " + type);
+ }
+ } catch (IOException e) {
+ // Should not happen.
+ throw new IllegalStateException(e);
+ }
+ unknownFields.add(new UnknownFieldData(tag, data));
+ } else {
+ throw new IllegalArgumentException("Unexpected repeated extension tag " + tag
+ + ", unequal to both non-packed variant " + nonPackedTag
+ + " and packed variant " + packedTag);
+ }
+ }
}
- }
}
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 e95c514..82dc6cc 100644
--- a/java/src/main/java/com/google/protobuf/nano/MessageNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/MessageNano.java
@@ -67,16 +67,20 @@ public abstract class MessageNano {
}
/**
- * Serializes the message and writes it to {@code output}. This does not
- * flush or close the stream.
+ * Serializes the message and writes it to {@code output}.
+ *
+ * @param output the output to receive the serialized form.
+ * @throws IOException if an error occurred writing to {@code output}.
*/
- abstract public void writeTo(CodedOutputByteBufferNano output) throws java.io.IOException;
+ public void writeTo(CodedOutputByteBufferNano output) throws IOException {
+ // Does nothing by default. Overridden by subclasses which have data to write.
+ }
/**
* Parse {@code input} as a message of this type and merge it with the
* message being built.
*/
- abstract public MessageNano mergeFrom(final CodedInputByteBufferNano input) throws IOException;
+ public abstract MessageNano mergeFrom(CodedInputByteBufferNano input) throws IOException;
/**
* Serialize to a byte array.
@@ -95,9 +99,8 @@ public abstract class MessageNano {
* write more than length bytes OutOfSpaceException will be thrown
* and if length bytes are not written then IllegalStateException
* is thrown.
- * @return byte array with the serialized data.
*/
- public static final void toByteArray(MessageNano msg, byte [] data, int offset, int length) {
+ public static final void toByteArray(MessageNano msg, byte[] data, int offset, int length) {
try {
final CodedOutputByteBufferNano output =
CodedOutputByteBufferNano.newInstance(data, offset, length);
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 301ff1d..1ff8f06 100644
--- a/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
+++ b/java/src/main/java/com/google/protobuf/nano/WireFormatNano.java
@@ -31,9 +31,6 @@
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
@@ -75,21 +72,6 @@ public final class WireFormatNano {
return (fieldNumber << TAG_TYPE_BITS) | wireType;
}
- // Field numbers for feilds in MessageSet wire format.
- static final int MESSAGE_SET_ITEM = 1;
- static final int MESSAGE_SET_TYPE_ID = 2;
- static final int MESSAGE_SET_MESSAGE = 3;
-
- // Tag numbers.
- static final int MESSAGE_SET_ITEM_TAG =
- makeTag(MESSAGE_SET_ITEM, WIRETYPE_START_GROUP);
- static final int MESSAGE_SET_ITEM_END_TAG =
- makeTag(MESSAGE_SET_ITEM, WIRETYPE_END_GROUP);
- static final int MESSAGE_SET_TYPE_ID_TAG =
- makeTag(MESSAGE_SET_TYPE_ID, WIRETYPE_VARINT);
- static final int MESSAGE_SET_MESSAGE_TAG =
- makeTag(MESSAGE_SET_MESSAGE, WIRETYPE_LENGTH_DELIMITED);
-
public static final int EMPTY_INT_ARRAY[] = {};
public static final long EMPTY_LONG_ARRAY[] = {};
public static final float EMPTY_FLOAT_ARRAY[] = {};
@@ -114,35 +96,6 @@ 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.
- *
- * <p>Note that the tag might be a end-group tag (rather than the start of an unknown field) in
- * which case we do not want to add an unknown field entry.
- *
- * @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();
- if (!input.skipField(tag)) {
- return false; // This wasn't an unknown field, it's an end-group tag.
- }
- int endPos = input.getPosition();
- byte[] bytes = input.getData(startPos, endPos - startPos);
- data.add(new UnknownFieldData(tag, bytes));
- return true;
- }
-
- /**
* 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).
@@ -172,193 +125,4 @@ public final class WireFormatNano {
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 32a331e..9987cac 100644
--- a/java/src/test/java/com/google/protobuf/NanoTest.java
+++ b/java/src/test/java/com/google/protobuf/NanoTest.java
@@ -52,6 +52,9 @@ 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.UnittestImportNano;
import com.google.protobuf.nano.UnittestMultipleNano;
@@ -61,10 +64,8 @@ import com.google.protobuf.nano.UnittestSingleNano.SingleMessageNano;
import junit.framework.TestCase;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
/**
* Test nano runtime.
@@ -520,12 +521,12 @@ public class NanoTest extends TestCase {
byte [] serialized = MessageNano.toByteArray(msg);
MessageWithGroup parsed = MessageWithGroup.parseFrom(serialized);
- assertTrue(msg.group != null);
- assertEquals(1, msg.group.a);
+ assertEquals(1, parsed.group.a);
byte [] serialized2 = MessageNano.toByteArray(parsed);
- assertEquals(serialized2.length, serialized.length);
+ assertEquals(serialized.length, serialized2.length);
MessageWithGroup parsed2 = MessageWithGroup.parseFrom(serialized2);
+ assertEquals(1, parsed2.group.a);
}
public void testNanoOptionalNestedMessage() throws Exception {
@@ -2222,6 +2223,7 @@ public class NanoTest extends TestCase {
*/
public void testNanoSingle() throws Exception {
SingleMessageNano msg = new SingleMessageNano();
+ assertNotNull(msg);
}
/**
@@ -2597,12 +2599,14 @@ public class NanoTest extends TestCase {
msg.defaultFloatNan = 0;
byte[] result = MessageNano.toByteArray(msg);
int msgSerializedSize = msg.getSerializedSize();
+ assertTrue(result.length == msgSerializedSize);
assertTrue(msgSerializedSize > 3);
msg.defaultDoubleNan = Double.NaN;
msg.defaultFloatNan = Float.NaN;
result = MessageNano.toByteArray(msg);
msgSerializedSize = msg.getSerializedSize();
+ assertEquals(3, result.length);
assertEquals(3, msgSerializedSize);
}
@@ -2735,57 +2739,163 @@ public class NanoTest extends TestCase {
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));
+ int[] int32s = {1, 2};
+ int[] uint32s = {3, 4};
+ int[] sint32s = {-5, -6};
+ long[] int64s = {7, 8};
+ long[] uint64s = {9, 10};
+ long[] sint64s = {-11, -12};
+ int[] fixed32s = {13, 14};
+ int[] sfixed32s = {-15, -16};
+ long[] fixed64s = {17, 18};
+ long[] sfixed64s = {-19, -20};
+ boolean[] bools = {true, false};
+ float[] floats = {2.1f, 2.2f};
+ double[] doubles = {2.3, 2.4};
+ int[] enums = {Extensions.SECOND_VALUE, Extensions.FIRST_VALUE};
+ String[] strings = {"vijfentwintig", "twenty-six"};
+ byte[][] bytess = {{2, 7}, {2, 8}};
+ AnotherMessage another1 = new AnotherMessage();
+ another1.string = "er shi jiu";
+ another1.value = false;
+ AnotherMessage another2 = new AnotherMessage();
+ another2.string = "trente";
+ another2.value = true;
+ AnotherMessage[] messages = {another1, another2};
+ RepeatedExtensions.RepeatedGroup group1 = new RepeatedExtensions.RepeatedGroup();
+ group1.a = 31;
+ RepeatedExtensions.RepeatedGroup group2 = new RepeatedExtensions.RepeatedGroup();
+ group2.a = 32;
+ RepeatedExtensions.RepeatedGroup[] groups = {group1, group2};
+ message.setExtension(RepeatedExtensions.repeatedInt32, int32s);
+ message.setExtension(RepeatedExtensions.repeatedUint32, uint32s);
+ message.setExtension(RepeatedExtensions.repeatedSint32, sint32s);
+ message.setExtension(RepeatedExtensions.repeatedInt64, int64s);
+ message.setExtension(RepeatedExtensions.repeatedUint64, uint64s);
+ message.setExtension(RepeatedExtensions.repeatedSint64, sint64s);
+ message.setExtension(RepeatedExtensions.repeatedFixed32, fixed32s);
+ message.setExtension(RepeatedExtensions.repeatedSfixed32, sfixed32s);
+ message.setExtension(RepeatedExtensions.repeatedFixed64, fixed64s);
+ message.setExtension(RepeatedExtensions.repeatedSfixed64, sfixed64s);
+ message.setExtension(RepeatedExtensions.repeatedBool, bools);
+ message.setExtension(RepeatedExtensions.repeatedFloat, floats);
+ message.setExtension(RepeatedExtensions.repeatedDouble, doubles);
+ message.setExtension(RepeatedExtensions.repeatedEnum, enums);
+ message.setExtension(RepeatedExtensions.repeatedString, strings);
+ message.setExtension(RepeatedExtensions.repeatedBytes, bytess);
+ message.setExtension(RepeatedExtensions.repeatedMessage, messages);
+ message.setExtension(RepeatedExtensions.repeatedGroup, groups);
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);
+ message = Extensions.ExtendableMessage.parseFrom(data);
+ assertEquals(5, message.field);
+
+ // Test reading back using SingularExtensions: the retrieved value should equal the last
+ // in each array.
+ assertEquals(int32s[1], (int) message.getExtension(SingularExtensions.someInt32));
+ assertEquals(uint32s[1], (int) message.getExtension(SingularExtensions.someUint32));
+ assertEquals(sint32s[1], (int) message.getExtension(SingularExtensions.someSint32));
+ assertEquals(int64s[1], (long) message.getExtension(SingularExtensions.someInt64));
+ assertEquals(uint64s[1], (long) message.getExtension(SingularExtensions.someUint64));
+ assertEquals(sint64s[1], (long) message.getExtension(SingularExtensions.someSint64));
+ assertEquals(fixed32s[1], (int) message.getExtension(SingularExtensions.someFixed32));
+ assertEquals(sfixed32s[1], (int) message.getExtension(SingularExtensions.someSfixed32));
+ assertEquals(fixed64s[1], (long) message.getExtension(SingularExtensions.someFixed64));
+ assertEquals(sfixed64s[1], (long) message.getExtension(SingularExtensions.someSfixed64));
+ assertEquals(bools[1], (boolean) message.getExtension(SingularExtensions.someBool));
+ assertEquals(floats[1], (float) message.getExtension(SingularExtensions.someFloat));
+ assertEquals(doubles[1], (double) message.getExtension(SingularExtensions.someDouble));
+ assertEquals(enums[1], (int) message.getExtension(SingularExtensions.someEnum));
+ assertEquals(strings[1], message.getExtension(SingularExtensions.someString));
+ assertTrue(Arrays.equals(bytess[1], message.getExtension(SingularExtensions.someBytes)));
+ AnotherMessage deserializedMessage = message.getExtension(SingularExtensions.someMessage);
+ assertEquals(another2.string, deserializedMessage.string);
+ assertEquals(another2.value, deserializedMessage.value);
+ assertEquals(group2.a, message.getExtension(SingularExtensions.someGroup).a);
+
+ // Test reading back using RepeatedExtensions: the arrays should be equal.
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
+ assertTrue(Arrays.equals(strings, message.getExtension(RepeatedExtensions.repeatedString)));
+ byte[][] deserializedRepeatedBytes = message.getExtension(RepeatedExtensions.repeatedBytes);
+ assertEquals(2, deserializedRepeatedBytes.length);
+ assertTrue(Arrays.equals(bytess[0], deserializedRepeatedBytes[0]));
+ assertTrue(Arrays.equals(bytess[1], deserializedRepeatedBytes[1]));
+ AnotherMessage[] deserializedRepeatedMessage =
+ message.getExtension(RepeatedExtensions.repeatedMessage);
+ assertEquals(2, deserializedRepeatedMessage.length);
+ assertEquals(another1.string, deserializedRepeatedMessage[0].string);
+ assertEquals(another1.value, deserializedRepeatedMessage[0].value);
+ assertEquals(another2.string, deserializedRepeatedMessage[1].string);
+ assertEquals(another2.value, deserializedRepeatedMessage[1].value);
+ RepeatedExtensions.RepeatedGroup[] deserializedRepeatedGroup =
+ message.getExtension(RepeatedExtensions.repeatedGroup);
+ assertEquals(2, deserializedRepeatedGroup.length);
+ assertEquals(group1.a, deserializedRepeatedGroup[0].a);
+ assertEquals(group2.a, deserializedRepeatedGroup[1].a);
+
+ // Test reading back using PackedExtensions: the arrays should be equal, even the fields
+ // are non-packed.
+ assertTrue(Arrays.equals(int32s, message.getExtension(PackedExtensions.packedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(PackedExtensions.packedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(PackedExtensions.packedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(PackedExtensions.packedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(PackedExtensions.packedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(PackedExtensions.packedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(PackedExtensions.packedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(PackedExtensions.packedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(PackedExtensions.packedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(PackedExtensions.packedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(PackedExtensions.packedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(PackedExtensions.packedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(PackedExtensions.packedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(PackedExtensions.packedEnum)));
+
+ // Now set the packable extension values using PackedExtensions so they're serialized packed.
+ message.setExtension(PackedExtensions.packedInt32, int32s);
+ message.setExtension(PackedExtensions.packedUint32, uint32s);
+ message.setExtension(PackedExtensions.packedSint32, sint32s);
+ message.setExtension(PackedExtensions.packedInt64, int64s);
+ message.setExtension(PackedExtensions.packedUint64, uint64s);
+ message.setExtension(PackedExtensions.packedSint64, sint64s);
+ message.setExtension(PackedExtensions.packedFixed32, fixed32s);
+ message.setExtension(PackedExtensions.packedSfixed32, sfixed32s);
+ message.setExtension(PackedExtensions.packedFixed64, fixed64s);
+ message.setExtension(PackedExtensions.packedSfixed64, sfixed64s);
+ message.setExtension(PackedExtensions.packedBool, bools);
+ message.setExtension(PackedExtensions.packedFloat, floats);
+ message.setExtension(PackedExtensions.packedDouble, doubles);
+ message.setExtension(PackedExtensions.packedEnum, enums);
+
+ // And read back using non-packed RepeatedExtensions.
+ byte[] data2 = MessageNano.toByteArray(message);
+ message = MessageNano.mergeFrom(new Extensions.ExtendableMessage(), data2);
+ assertTrue(Arrays.equals(int32s, message.getExtension(RepeatedExtensions.repeatedInt32)));
+ assertTrue(Arrays.equals(uint32s, message.getExtension(RepeatedExtensions.repeatedUint32)));
+ assertTrue(Arrays.equals(sint32s, message.getExtension(RepeatedExtensions.repeatedSint32)));
+ assertTrue(Arrays.equals(int64s, message.getExtension(RepeatedExtensions.repeatedInt64)));
+ assertTrue(Arrays.equals(uint64s, message.getExtension(RepeatedExtensions.repeatedUint64)));
+ assertTrue(Arrays.equals(sint64s, message.getExtension(RepeatedExtensions.repeatedSint64)));
+ assertTrue(Arrays.equals(fixed32s, message.getExtension(RepeatedExtensions.repeatedFixed32)));
+ assertTrue(Arrays.equals(sfixed32s, message.getExtension(RepeatedExtensions.repeatedSfixed32)));
+ assertTrue(Arrays.equals(fixed64s, message.getExtension(RepeatedExtensions.repeatedFixed64)));
+ assertTrue(Arrays.equals(sfixed64s, message.getExtension(RepeatedExtensions.repeatedSfixed64)));
+ assertTrue(Arrays.equals(bools, message.getExtension(RepeatedExtensions.repeatedBool)));
+ assertTrue(Arrays.equals(floats, message.getExtension(RepeatedExtensions.repeatedFloat)));
+ assertTrue(Arrays.equals(doubles, message.getExtension(RepeatedExtensions.repeatedDouble)));
+ assertTrue(Arrays.equals(enums, message.getExtension(RepeatedExtensions.repeatedEnum)));
}
public void testUnknownFields() throws Exception {
@@ -3462,13 +3572,4 @@ public class NanoTest extends TestCase {
}
return sb.toString();
}
-
- 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
index 0bc9c9d..754ed55 100644
--- a/src/google/protobuf/compiler/javanano/javanano_extension.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc
@@ -42,28 +42,84 @@ namespace compiler {
namespace javanano {
using internal::WireFormat;
+using internal::WireFormatLite;
+
+namespace {
+
+const char* GetTypeConstantName(const FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return "TYPE_INT32" ;
+ case FieldDescriptor::TYPE_UINT32 : return "TYPE_UINT32" ;
+ case FieldDescriptor::TYPE_SINT32 : return "TYPE_SINT32" ;
+ case FieldDescriptor::TYPE_FIXED32 : return "TYPE_FIXED32" ;
+ case FieldDescriptor::TYPE_SFIXED32: return "TYPE_SFIXED32";
+ case FieldDescriptor::TYPE_INT64 : return "TYPE_INT64" ;
+ case FieldDescriptor::TYPE_UINT64 : return "TYPE_UINT64" ;
+ case FieldDescriptor::TYPE_SINT64 : return "TYPE_SINT64" ;
+ case FieldDescriptor::TYPE_FIXED64 : return "TYPE_FIXED64" ;
+ case FieldDescriptor::TYPE_SFIXED64: return "TYPE_SFIXED64";
+ case FieldDescriptor::TYPE_FLOAT : return "TYPE_FLOAT" ;
+ case FieldDescriptor::TYPE_DOUBLE : return "TYPE_DOUBLE" ;
+ case FieldDescriptor::TYPE_BOOL : return "TYPE_BOOL" ;
+ case FieldDescriptor::TYPE_STRING : return "TYPE_STRING" ;
+ case FieldDescriptor::TYPE_BYTES : return "TYPE_BYTES" ;
+ case FieldDescriptor::TYPE_ENUM : return "TYPE_ENUM" ;
+ case FieldDescriptor::TYPE_GROUP : return "TYPE_GROUP" ;
+ case FieldDescriptor::TYPE_MESSAGE : return "TYPE_MESSAGE" ;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+} // namespace
void SetVariables(const FieldDescriptor* descriptor, const Params params,
map<string, string>* variables) {
- (*variables)["name"] =
- RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
- (*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["extends"] = ClassName(params, descriptor->containing_type());
-
- string type;
+ (*variables)["name"] = RenameJavaKeywords(UnderscoresToCamelCase(descriptor));
+ bool repeated = descriptor->is_repeated();
+ (*variables)["repeated"] = repeated ? "Repeated" : "";
+ (*variables)["type"] = GetTypeConstantName(descriptor->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;
+ string tag = SimpleItoa(WireFormat::MakeTag(descriptor));
+ if (java_type == JAVATYPE_MESSAGE) {
+ (*variables)["ext_type"] = "MessageTyped";
+ string message_type = ClassName(params, descriptor->message_type());
+ if (repeated) {
+ message_type += "[]";
+ }
+ (*variables)["class"] = message_type;
+ // For message typed extensions, tags_params contains a single tag
+ // for both singular and repeated cases.
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["ext_type"] = "PrimitiveTyped";
+ if (!repeated) {
+ (*variables)["class"] = BoxedPrimitiveTypeName(java_type);
+ (*variables)["tag_params"] = tag;
+ } else {
+ (*variables)["class"] = PrimitiveTypeName(java_type) + "[]";
+ if (!descriptor->is_packable()) {
+ // Non-packable: nonPackedTag == tag, packedTag == 0
+ (*variables)["tag_params"] = tag + ", " + tag + ", 0";
+ } else if (descriptor->options().packed()) {
+ // Packable and packed: tag == packedTag
+ string non_packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(),
+ WireFormat::WireTypeForFieldType(descriptor->type())));
+ (*variables)["tag_params"] = tag + ", " + non_packed_tag + ", " + tag;
+ } else {
+ // Packable and not packed: tag == nonPackedTag
+ string packed_tag = SimpleItoa(WireFormatLite::MakeTag(
+ descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED));
+ (*variables)["tag_params"] = tag + ", " + tag + ", " + packed_tag;
+ }
+ }
}
- (*variables)["type"] = type;
}
ExtensionGenerator::
@@ -75,21 +131,16 @@ ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params)
ExtensionGenerator::~ExtensionGenerator() {}
void ExtensionGenerator::Generate(io::Printer* printer) const {
- if (descriptor_->is_repeated()) {
- printer->Print(variables_,
- "\n"
- "// 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_,
- "\n"
- "// 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");
- }
+ printer->Print("\n");
+ PrintFieldComment(printer, descriptor_);
+ printer->Print(variables_,
+ "public static final com.google.protobuf.nano.Extension<\n"
+ " $extends$,\n"
+ " $class$> $name$ =\n"
+ " com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n"
+ " com.google.protobuf.nano.Extension.$type$,\n"
+ " $class$.class,\n"
+ " $tag_params$);\n");
}
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index ede4c6f..e8326a4 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -264,6 +264,22 @@ string FieldDefaultConstantName(const FieldDescriptor *field) {
return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default";
}
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
+ // We don't want to print group bodies so we cut off after the first line
+ // (the second line for extensions).
+ string def = field->DebugString();
+ string::size_type first_line_end = def.find_first_of('\n');
+ printer->Print("// $def$\n",
+ "def", def.substr(0, first_line_end));
+ if (field->is_extension()) {
+ string::size_type second_line_start = first_line_end + 1;
+ string::size_type second_line_length =
+ def.find('\n', second_line_start) - second_line_start;
+ printer->Print("// $def$\n",
+ "def", def.substr(second_line_start, second_line_length));
+ }
+}
+
JavaType GetJavaType(FieldDescriptor::Type field_type) {
switch (field_type) {
case FieldDescriptor::TYPE_INT32:
@@ -310,7 +326,27 @@ JavaType GetJavaType(FieldDescriptor::Type field_type) {
return JAVATYPE_INT;
}
-const char* BoxedPrimitiveTypeName(JavaType type) {
+string PrimitiveTypeName(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return "int";
+ case JAVATYPE_LONG : return "long";
+ case JAVATYPE_FLOAT : return "float";
+ case JAVATYPE_DOUBLE : return "double";
+ case JAVATYPE_BOOLEAN: return "boolean";
+ case JAVATYPE_STRING : return "java.lang.String";
+ case JAVATYPE_BYTES : return "byte[]";
+ case JAVATYPE_ENUM : return "int";
+ case JAVATYPE_MESSAGE: return NULL;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return NULL;
+}
+
+string BoxedPrimitiveTypeName(JavaType type) {
switch (type) {
case JAVATYPE_INT : return "java.lang.Integer";
case JAVATYPE_LONG : return "java.lang.Long";
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h
index 753a4bd..886bff8 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.h
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -39,6 +39,7 @@
#include <google/protobuf/compiler/javanano/javanano_params.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/descriptor.h>
+#include <google/protobuf/io/printer.h>
namespace google {
namespace protobuf {
@@ -111,6 +112,9 @@ string FieldConstantName(const FieldDescriptor *field);
string FieldDefaultConstantName(const FieldDescriptor *field);
+// Print the field's proto-syntax definition as a comment.
+void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field);
+
enum JavaType {
JAVATYPE_INT,
JAVATYPE_LONG,
@@ -129,10 +133,12 @@ inline JavaType GetJavaType(const FieldDescriptor* field) {
return GetJavaType(field->type());
}
+string PrimitiveTypeName(JavaType type);
+
// Get the fully-qualified class name for a boxed primitive type, e.g.
// "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message
// types.
-const char* BoxedPrimitiveTypeName(JavaType type);
+string BoxedPrimitiveTypeName(JavaType type);
string EmptyArrayName(const Params& params, const FieldDescriptor* field);
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index c09670a..008bec2 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -54,14 +54,6 @@ using internal::WireFormatLite;
namespace {
-void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
- // Print the field's proto-syntax definition as a comment. We don't want to
- // print group bodies so we cut off after the first line.
- string def = field->DebugString();
- printer->Print("// $def$\n",
- "def", def.substr(0, def.find_first_of('\n')));
-}
-
struct FieldOrderingByNumber {
inline bool operator()(const FieldDescriptor* a,
const FieldDescriptor* b) const {
@@ -82,13 +74,6 @@ const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
return fields;
}
-// Get an identifier that uniquely identifies this type within the file.
-// This is used to declare static variables related to this type at the
-// outermost file scope.
-string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
- return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
-}
-
} // namespace
// ===================================================================
@@ -149,7 +134,8 @@ void MessageGenerator::Generate(io::Printer* printer) {
}
if (params_.store_unknown_fields()) {
printer->Print(
- " com.google.protobuf.nano.ExtendableMessageNano {\n");
+ " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n",
+ "classname", descriptor_->name());
} else {
printer->Print(
" com.google.protobuf.nano.MessageNano {\n");
@@ -285,22 +271,20 @@ void MessageGenerator::Generate(io::Printer* printer) {
void MessageGenerator::
GenerateMessageSerializationMethods(io::Printer* printer) {
+ // Rely on the parent implementations of writeTo() and getSerializedSize()
+ // if there are no fields to serialize in this message.
+ if (descriptor_->field_count() == 0) {
+ return;
+ }
+
scoped_array<const FieldDescriptor*> sorted_fields(
SortFieldsByNumber(descriptor_));
- // writeTo only throws an exception if it contains one or more fields to write
- if (descriptor_->field_count() > 0 || params_.store_unknown_fields()) {
- printer->Print(
- "\n"
- "@Override\n"
- "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
- " throws java.io.IOException {\n");
- } else {
- printer->Print(
- "\n"
- "@Override\n"
- "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) {\n");
- }
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
+ " throws java.io.IOException {\n");
printer->Indent();
// Output the fields in sorted order
@@ -308,36 +292,31 @@ GenerateMessageSerializationMethods(io::Printer* printer) {
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");
- }
+ // The parent implementation will write any unknown fields if necessary.
+ printer->Print(
+ "super.writeTo(output);\n");
printer->Outdent();
printer->Print("}\n");
- // Rely on the parent implementation of getSerializedSize if there are no fields to
- // serialize in this MessageNano.
- if (descriptor_->field_count() != 0) {
- printer->Print(
- "\n"
- "@Override\n"
- "public int getSerializedSize() {\n"
- " int size = super.getSerializedSize();\n");
- printer->Indent();
-
- for (int i = 0; i < descriptor_->field_count(); i++) {
- field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
- }
+ // The parent implementation will get the serialized size for unknown
+ // fields if necessary.
+ printer->Print(
+ "\n"
+ "@Override\n"
+ "public int getSerializedSize() {\n"
+ " int size = super.getSerializedSize();\n");
+ printer->Indent();
- printer->Outdent();
- printer->Print(
- " cachedSize = size;\n"
- " return size;\n"
- "}\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
}
+
+ printer->Outdent();
+ printer->Print(
+ " cachedSize = size;\n"
+ " return size;\n"
+ "}\n");
}
void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
@@ -371,12 +350,7 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
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(\n"
- " unknownFieldData, input, tag)) {\n"
+ "if (!storeUnknownField(input, tag)) {\n"
" return this;\n"
"}\n");
} else {
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index e044e89..a3bc3a8 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -54,26 +54,6 @@ using internal::WireFormatLite;
namespace {
-const char* PrimitiveTypeName(JavaType type) {
- switch (type) {
- case JAVATYPE_INT : return "int";
- case JAVATYPE_LONG : return "long";
- case JAVATYPE_FLOAT : return "float";
- case JAVATYPE_DOUBLE : return "double";
- case JAVATYPE_BOOLEAN: return "boolean";
- case JAVATYPE_STRING : return "java.lang.String";
- case JAVATYPE_BYTES : return "byte[]";
- case JAVATYPE_ENUM : return NULL;
- case JAVATYPE_MESSAGE: return NULL;
-
- // No default because we want the compiler to complain if any new
- // JavaTypes are added.
- }
-
- GOOGLE_LOG(FATAL) << "Can't get here.";
- return NULL;
-}
-
bool IsReferenceType(JavaType type) {
switch (type) {
case JAVATYPE_INT : return false;
diff --git a/src/google/protobuf/unittest_extension_nano.proto b/src/google/protobuf/unittest_extension_nano.proto
index 104cfa7..0a775f4 100644
--- a/src/google/protobuf/unittest_extension_nano.proto
+++ b/src/google/protobuf/unittest_extension_nano.proto
@@ -18,31 +18,14 @@ message AnotherMessage {
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;
}
}
+// For testNanoOptionalGroupWithUnknownFieldsEnabled;
+// not part of the extensions tests.
message MessageWithGroup {
optional group Group = 1 {
optional int32 a = 2;
diff --git a/src/google/protobuf/unittest_extension_packed_nano.proto b/src/google/protobuf/unittest_extension_packed_nano.proto
new file mode 100644
index 0000000..3586de7
--- /dev/null
+++ b/src/google/protobuf/unittest_extension_packed_nano.proto
@@ -0,0 +1,29 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message PackedExtensions {
+ extend ExtendableMessage {
+ repeated int32 packed_int32 = 10 [ packed = true ];
+ repeated uint32 packed_uint32 = 11 [ packed = true ];
+ repeated sint32 packed_sint32 = 12 [ packed = true ];
+ repeated int64 packed_int64 = 13 [ packed = true ];
+ repeated uint64 packed_uint64 = 14 [ packed = true ];
+ repeated sint64 packed_sint64 = 15 [ packed = true ];
+ repeated fixed32 packed_fixed32 = 16 [ packed = true ];
+ repeated sfixed32 packed_sfixed32 = 17 [ packed = true ];
+ repeated fixed64 packed_fixed64 = 18 [ packed = true ];
+ repeated sfixed64 packed_sfixed64 = 19 [ packed = true ];
+ repeated bool packed_bool = 20 [ packed = true ];
+ repeated float packed_float = 21 [ packed = true ];
+ repeated double packed_double = 22 [ packed = true ];
+ repeated AnEnum packed_enum = 23 [ packed = true ];
+ // Non-packable types omitted.
+ }
+}
diff --git a/src/google/protobuf/unittest_extension_repeated_nano.proto b/src/google/protobuf/unittest_extension_repeated_nano.proto
new file mode 100644
index 0000000..546c2df
--- /dev/null
+++ b/src/google/protobuf/unittest_extension_repeated_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message RepeatedExtensions {
+ extend ExtendableMessage {
+ repeated int32 repeated_int32 = 10;
+ repeated uint32 repeated_uint32 = 11;
+ repeated sint32 repeated_sint32 = 12;
+ repeated int64 repeated_int64 = 13;
+ repeated uint64 repeated_uint64 = 14;
+ repeated sint64 repeated_sint64 = 15;
+ repeated fixed32 repeated_fixed32 = 16;
+ repeated sfixed32 repeated_sfixed32 = 17;
+ repeated fixed64 repeated_fixed64 = 18;
+ repeated sfixed64 repeated_sfixed64 = 19;
+ repeated bool repeated_bool = 20;
+ repeated float repeated_float = 21;
+ repeated double repeated_double = 22;
+ repeated AnEnum repeated_enum = 23;
+ repeated string repeated_string = 24;
+ repeated bytes repeated_bytes = 25;
+ repeated AnotherMessage repeated_message = 26;
+ repeated group RepeatedGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}
diff --git a/src/google/protobuf/unittest_extension_singular_nano.proto b/src/google/protobuf/unittest_extension_singular_nano.proto
new file mode 100644
index 0000000..35d9e6e
--- /dev/null
+++ b/src/google/protobuf/unittest_extension_singular_nano.proto
@@ -0,0 +1,34 @@
+syntax = "proto2";
+
+option java_multiple_files = true;
+option java_package = "com.google.protobuf.nano";
+
+import "google/protobuf/unittest_extension_nano.proto";
+
+// Must be compiled separately due to extension number reuse.
+// The reuse is deliberate, for testing wire compatibility.
+
+message SingularExtensions {
+ extend ExtendableMessage {
+ optional int32 some_int32 = 10;
+ optional uint32 some_uint32 = 11;
+ optional sint32 some_sint32 = 12;
+ optional int64 some_int64 = 13;
+ optional uint64 some_uint64 = 14;
+ optional sint64 some_sint64 = 15;
+ optional fixed32 some_fixed32 = 16;
+ optional sfixed32 some_sfixed32 = 17;
+ optional fixed64 some_fixed64 = 18;
+ optional sfixed64 some_sfixed64 = 19;
+ optional bool some_bool = 20;
+ optional float some_float = 21;
+ optional double some_double = 22;
+ optional AnEnum some_enum = 23;
+ optional string some_string = 24;
+ optional bytes some_bytes = 25;
+ optional AnotherMessage some_message = 26;
+ optional group SomeGroup = 27 {
+ optional int32 a = 1;
+ }
+ }
+}