|
@@ -0,0 +1,2716 @@
|
|
|
|
+// Protocol Buffers - Google's data interchange format
|
|
|
|
+// Copyright 2008 Google Inc. All rights reserved.
|
|
|
|
+// https://developers.google.com/protocol-buffers/
|
|
|
|
+//
|
|
|
|
+// Redistribution and use in source and binary forms, with or without
|
|
|
|
+// modification, are permitted provided that the following conditions are
|
|
|
|
+// met:
|
|
|
|
+//
|
|
|
|
+// * Redistributions of source code must retain the above copyright
|
|
|
|
+// notice, this list of conditions and the following disclaimer.
|
|
|
|
+// * Redistributions in binary form must reproduce the above
|
|
|
|
+// copyright notice, this list of conditions and the following disclaimer
|
|
|
|
+// in the documentation and/or other materials provided with the
|
|
|
|
+// distribution.
|
|
|
|
+// * Neither the name of Google Inc. nor the names of its
|
|
|
|
+// contributors may be used to endorse or promote products derived from
|
|
|
|
+// this software without specific prior written permission.
|
|
|
|
+//
|
|
|
|
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
|
|
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
|
|
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
|
|
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
|
|
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
|
|
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
|
|
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
|
|
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
+
|
|
|
|
+package com.google.protobuf;
|
|
|
|
+
|
|
|
|
+import com.google.protobuf.Descriptors.Descriptor;
|
|
|
|
+import com.google.protobuf.Descriptors.EnumDescriptor;
|
|
|
|
+import com.google.protobuf.Descriptors.EnumValueDescriptor;
|
|
|
|
+import com.google.protobuf.Descriptors.FieldDescriptor;
|
|
|
|
+import com.google.protobuf.Descriptors.FileDescriptor;
|
|
|
|
+import com.google.protobuf.Descriptors.OneofDescriptor;
|
|
|
|
+import com.google.protobuf.GeneratedMessage.GeneratedExtension;
|
|
|
|
+
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.io.InputStream;
|
|
|
|
+import java.io.ObjectStreamException;
|
|
|
|
+import java.io.Serializable;
|
|
|
|
+import java.lang.reflect.InvocationTargetException;
|
|
|
|
+import java.lang.reflect.Method;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Collections;
|
|
|
|
+import java.util.Iterator;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.TreeMap;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * All generated protocol message classes extend this class. This class
|
|
|
|
+ * implements most of the Message and Builder interfaces using Java reflection.
|
|
|
|
+ * Users can ignore this class and pretend that generated messages implement
|
|
|
|
+ * the Message interface directly.
|
|
|
|
+ *
|
|
|
|
+ * @author kenton@google.com Kenton Varda
|
|
|
|
+ */
|
|
|
|
+public abstract class GeneratedMessageV3 extends AbstractMessage
|
|
|
|
+ implements Serializable {
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * For testing. Allows a test to disable the optimization that avoids using
|
|
|
|
+ * field builders for nested messages until they are requested. By disabling
|
|
|
|
+ * this optimization, existing tests can be reused to test the field builders.
|
|
|
|
+ */
|
|
|
|
+ protected static boolean alwaysUseFieldBuilders = false;
|
|
|
|
+
|
|
|
|
+ /** For use by generated code only. */
|
|
|
|
+ protected UnknownFieldSet unknownFields;
|
|
|
|
+
|
|
|
|
+ protected GeneratedMessageV3() {
|
|
|
|
+ unknownFields = UnknownFieldSet.getDefaultInstance();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected GeneratedMessageV3(Builder<?> builder) {
|
|
|
|
+ unknownFields = builder.getUnknownFields();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Parser<? extends GeneratedMessageV3> getParserForType() {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "This is supposed to be overridden by subclasses.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * For testing. Allows a test to disable the optimization that avoids using
|
|
|
|
+ * field builders for nested messages until they are requested. By disabling
|
|
|
|
+ * this optimization, existing tests can be reused to test the field builders.
|
|
|
|
+ * See {@link RepeatedFieldBuilder} and {@link SingleFieldBuilder}.
|
|
|
|
+ */
|
|
|
|
+ static void enableAlwaysUseFieldBuildersForTesting() {
|
|
|
|
+ alwaysUseFieldBuilders = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Get the FieldAccessorTable for this type. We can't have the message
|
|
|
|
+ * class pass this in to the constructor because of bootstrapping trouble
|
|
|
|
+ * with DescriptorProtos.
|
|
|
|
+ */
|
|
|
|
+ protected abstract FieldAccessorTable internalGetFieldAccessorTable();
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Descriptor getDescriptorForType() {
|
|
|
|
+ return internalGetFieldAccessorTable().descriptor;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Internal helper to return a modifiable map containing all the fields.
|
|
|
|
+ * The returned Map is modifialbe so that the caller can add additional
|
|
|
|
+ * extension fields to implement {@link #getAllFields()}.
|
|
|
|
+ *
|
|
|
|
+ * @param getBytesForString whether to generate ByteString for string fields
|
|
|
|
+ */
|
|
|
|
+ private Map<FieldDescriptor, Object> getAllFieldsMutable(
|
|
|
|
+ boolean getBytesForString) {
|
|
|
|
+ final TreeMap<FieldDescriptor, Object> result =
|
|
|
|
+ new TreeMap<FieldDescriptor, Object>();
|
|
|
|
+ final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
|
|
|
|
+ final List<FieldDescriptor> fields = descriptor.getFields();
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < fields.size(); i++) {
|
|
|
|
+ FieldDescriptor field = fields.get(i);
|
|
|
|
+ final OneofDescriptor oneofDescriptor = field.getContainingOneof();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the field is part of a Oneof, then at maximum one field in the Oneof is set
|
|
|
|
+ * and it is not repeated. There is no need to iterate through the others.
|
|
|
|
+ */
|
|
|
|
+ if (oneofDescriptor != null) {
|
|
|
|
+ // Skip other fields in the Oneof we know are not set
|
|
|
|
+ i += oneofDescriptor.getFieldCount() - 1;
|
|
|
|
+ if (!hasOneof(oneofDescriptor)) {
|
|
|
|
+ // If no field is set in the Oneof, skip all the fields in the Oneof
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ // Get the pointer to the only field which is set in the Oneof
|
|
|
|
+ field = getOneofFieldDescriptor(oneofDescriptor);
|
|
|
|
+ } else {
|
|
|
|
+ // If we are not in a Oneof, we need to check if the field is set and if it is repeated
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ final List<?> value = (List<?>) getField(field);
|
|
|
|
+ if (!value.isEmpty()) {
|
|
|
|
+ result.put(field, value);
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (!hasField(field)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Add the field to the map
|
|
|
|
+ if (getBytesForString && field.getJavaType() == FieldDescriptor.JavaType.STRING) {
|
|
|
|
+ result.put(field, getFieldRaw(field));
|
|
|
|
+ } else {
|
|
|
|
+ result.put(field, getField(field));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isInitialized() {
|
|
|
|
+ for (final FieldDescriptor field : getDescriptorForType().getFields()) {
|
|
|
|
+ // Check that all required fields are present.
|
|
|
|
+ if (field.isRequired()) {
|
|
|
|
+ if (!hasField(field)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Check that embedded messages are initialized.
|
|
|
|
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ @SuppressWarnings("unchecked") final
|
|
|
|
+ List<Message> messageList = (List<Message>) getField(field);
|
|
|
|
+ for (final Message element : messageList) {
|
|
|
|
+ if (!element.isInitialized()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (hasField(field) && !((Message) getField(field)).isInitialized()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Map<FieldDescriptor, Object> getAllFields() {
|
|
|
|
+ return Collections.unmodifiableMap(
|
|
|
|
+ getAllFieldsMutable(/* getBytesForString = */ false));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Returns a collection of all the fields in this message which are set
|
|
|
|
+ * and their corresponding values. A singular ("required" or "optional")
|
|
|
|
+ * field is set iff hasField() returns true for that field. A "repeated"
|
|
|
|
+ * field is set iff getRepeatedFieldCount() is greater than zero. The
|
|
|
|
+ * values are exactly what would be returned by calling
|
|
|
|
+ * {@link #getFieldRaw(Descriptors.FieldDescriptor)} for each field. The map
|
|
|
|
+ * is guaranteed to be a sorted map, so iterating over it will return fields
|
|
|
|
+ * in order by field number.
|
|
|
|
+ */
|
|
|
|
+ Map<FieldDescriptor, Object> getAllFieldsRaw() {
|
|
|
|
+ return Collections.unmodifiableMap(
|
|
|
|
+ getAllFieldsMutable(/* getBytesForString = */ true));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasOneof(final OneofDescriptor oneof) {
|
|
|
|
+ return internalGetFieldAccessorTable().getOneof(oneof).has(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
|
|
|
|
+ return internalGetFieldAccessorTable().getOneof(oneof).get(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasField(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).has(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getField(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).get(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Obtains the value of the given field, or the default value if it is
|
|
|
|
+ * not set. For primitive fields, the boxed primitive value is returned.
|
|
|
|
+ * For enum fields, the EnumValueDescriptor for the value is returned. For
|
|
|
|
+ * embedded message fields, the sub-message is returned. For repeated
|
|
|
|
+ * fields, a java.util.List is returned. For present string fields, a
|
|
|
|
+ * ByteString is returned representing the bytes that the field contains.
|
|
|
|
+ */
|
|
|
|
+ Object getFieldRaw(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).getRaw(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field)
|
|
|
|
+ .getRepeatedCount(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedField(final FieldDescriptor field, final int index) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field)
|
|
|
|
+ .getRepeated(this, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public UnknownFieldSet getUnknownFields() {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "This is supposed to be overridden by subclasses.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by subclasses to parse an unknown field.
|
|
|
|
+ * @return {@code true} unless the tag is an end-group tag.
|
|
|
|
+ */
|
|
|
|
+ protected boolean parseUnknownField(
|
|
|
|
+ CodedInputStream input,
|
|
|
|
+ UnknownFieldSet.Builder unknownFields,
|
|
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
|
|
+ int tag) throws IOException {
|
|
|
|
+ return unknownFields.mergeFieldFrom(tag, input);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input)
|
|
|
|
+ throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseFrom(input);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseWithIOException(Parser<M> parser, InputStream input,
|
|
|
|
+ ExtensionRegistryLite extensions) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseFrom(input, extensions);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseWithIOException(Parser<M> parser,
|
|
|
|
+ CodedInputStream input) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseFrom(input);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseWithIOException(Parser<M> parser,
|
|
|
|
+ CodedInputStream input, ExtensionRegistryLite extensions) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseFrom(input, extensions);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
|
|
|
|
+ InputStream input) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseDelimitedFrom(input);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static <M extends Message> M parseDelimitedWithIOException(Parser<M> parser,
|
|
|
|
+ InputStream input, ExtensionRegistryLite extensions) throws IOException {
|
|
|
|
+ try {
|
|
|
|
+ return parser.parseDelimitedFrom(input, extensions);
|
|
|
|
+ } catch (InvalidProtocolBufferException e) {
|
|
|
|
+ throw e.unwrapIOException();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void writeTo(final CodedOutputStream output) throws IOException {
|
|
|
|
+ MessageReflection.writeMessageTo(this, getAllFieldsRaw(), output, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getSerializedSize() {
|
|
|
|
+ int size = memoizedSize;
|
|
|
|
+ if (size != -1) {
|
|
|
|
+ return size;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ memoizedSize = MessageReflection.getSerializedSize(
|
|
|
|
+ this, getAllFieldsRaw());
|
|
|
|
+ return memoizedSize;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used by parsing constructors in generated classes.
|
|
|
|
+ */
|
|
|
|
+ protected void makeExtensionsImmutable() {
|
|
|
|
+ // Noop for messages without extensions.
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * TODO(xiaofeng): remove this after b/29368482 is fixed. We need to move this
|
|
|
|
+ * interface to AbstractMessage in order to versioning GeneratedMessageV3 but
|
|
|
|
+ * this move breaks binary compatibility for AppEngine. After AppEngine is
|
|
|
|
+ * fixed we can exlude this from google3.
|
|
|
|
+ */
|
|
|
|
+ protected interface BuilderParent extends AbstractMessage.BuilderParent {}
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * TODO(xiaofeng): remove this together with GeneratedMessageV3.BuilderParent.
|
|
|
|
+ */
|
|
|
|
+ protected abstract Message.Builder newBuilderForType(BuilderParent parent);
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected Message.Builder newBuilderForType(final AbstractMessage.BuilderParent parent) {
|
|
|
|
+ return newBuilderForType(new BuilderParent() {
|
|
|
|
+ @Override
|
|
|
|
+ public void markDirty() {
|
|
|
|
+ parent.markDirty();
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public abstract static class Builder <BuilderType extends Builder<BuilderType>>
|
|
|
|
+ extends AbstractMessage.Builder<BuilderType> {
|
|
|
|
+
|
|
|
|
+ private BuilderParent builderParent;
|
|
|
|
+
|
|
|
|
+ private BuilderParentImpl meAsParent;
|
|
|
|
+
|
|
|
|
+ // Indicates that we've built a message and so we are now obligated
|
|
|
|
+ // to dispatch dirty invalidations. See GeneratedMessageV3.BuilderListener.
|
|
|
|
+ private boolean isClean;
|
|
|
|
+
|
|
|
|
+ private UnknownFieldSet unknownFields =
|
|
|
|
+ UnknownFieldSet.getDefaultInstance();
|
|
|
|
+
|
|
|
|
+ protected Builder() {
|
|
|
|
+ this(null);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected Builder(BuilderParent builderParent) {
|
|
|
|
+ this.builderParent = builderParent;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ void dispose() {
|
|
|
|
+ builderParent = null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by the subclass when a message is built.
|
|
|
|
+ */
|
|
|
|
+ protected void onBuilt() {
|
|
|
|
+ if (builderParent != null) {
|
|
|
|
+ markClean();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by the subclass or a builder to notify us that a message was
|
|
|
|
+ * built and may be cached and therefore invalidations are needed.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ protected void markClean() {
|
|
|
|
+ this.isClean = true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets whether invalidations are needed
|
|
|
|
+ *
|
|
|
|
+ * @return whether invalidations are needed
|
|
|
|
+ */
|
|
|
|
+ protected boolean isClean() {
|
|
|
|
+ return isClean;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clone() {
|
|
|
|
+ BuilderType builder =
|
|
|
|
+ (BuilderType) getDefaultInstanceForType().newBuilderForType();
|
|
|
|
+ builder.mergeFrom(buildPartial());
|
|
|
|
+ return builder;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by the initialization and clear code paths to allow subclasses to
|
|
|
|
+ * reset any of their builtin fields back to the initial values.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clear() {
|
|
|
|
+ unknownFields = UnknownFieldSet.getDefaultInstance();
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Get the FieldAccessorTable for this type. We can't have the message
|
|
|
|
+ * class pass this in to the constructor because of bootstrapping trouble
|
|
|
|
+ * with DescriptorProtos.
|
|
|
|
+ */
|
|
|
|
+ protected abstract FieldAccessorTable internalGetFieldAccessorTable();
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Descriptor getDescriptorForType() {
|
|
|
|
+ return internalGetFieldAccessorTable().descriptor;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Map<FieldDescriptor, Object> getAllFields() {
|
|
|
|
+ return Collections.unmodifiableMap(getAllFieldsMutable());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Internal helper which returns a mutable map. */
|
|
|
|
+ private Map<FieldDescriptor, Object> getAllFieldsMutable() {
|
|
|
|
+ final TreeMap<FieldDescriptor, Object> result =
|
|
|
|
+ new TreeMap<FieldDescriptor, Object>();
|
|
|
|
+ final Descriptor descriptor = internalGetFieldAccessorTable().descriptor;
|
|
|
|
+ final List<FieldDescriptor> fields = descriptor.getFields();
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < fields.size(); i++) {
|
|
|
|
+ FieldDescriptor field = fields.get(i);
|
|
|
|
+ final OneofDescriptor oneofDescriptor = field.getContainingOneof();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * If the field is part of a Oneof, then at maximum one field in the Oneof is set
|
|
|
|
+ * and it is not repeated. There is no need to iterate through the others.
|
|
|
|
+ */
|
|
|
|
+ if (oneofDescriptor != null) {
|
|
|
|
+ // Skip other fields in the Oneof we know are not set
|
|
|
|
+ i += oneofDescriptor.getFieldCount() - 1;
|
|
|
|
+ if (!hasOneof(oneofDescriptor)) {
|
|
|
|
+ // If no field is set in the Oneof, skip all the fields in the Oneof
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ // Get the pointer to the only field which is set in the Oneof
|
|
|
|
+ field = getOneofFieldDescriptor(oneofDescriptor);
|
|
|
|
+ } else {
|
|
|
|
+ // If we are not in a Oneof, we need to check if the field is set and if it is repeated
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ final List<?> value = (List<?>) getField(field);
|
|
|
|
+ if (!value.isEmpty()) {
|
|
|
|
+ result.put(field, value);
|
|
|
|
+ }
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ if (!hasField(field)) {
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Add the field to the map
|
|
|
|
+ result.put(field, getField(field));
|
|
|
|
+ }
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder newBuilderForField(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).newBuilder();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getFieldBuilder(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).getBuilder(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getRepeatedFieldBuilder(final FieldDescriptor field, int index) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).getRepeatedBuilder(
|
|
|
|
+ this, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasOneof(final OneofDescriptor oneof) {
|
|
|
|
+ return internalGetFieldAccessorTable().getOneof(oneof).has(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public FieldDescriptor getOneofFieldDescriptor(final OneofDescriptor oneof) {
|
|
|
|
+ return internalGetFieldAccessorTable().getOneof(oneof).get(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasField(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field).has(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getField(final FieldDescriptor field) {
|
|
|
|
+ Object object = internalGetFieldAccessorTable().getField(field).get(this);
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ // The underlying list object is still modifiable at this point.
|
|
|
|
+ // Make sure not to expose the modifiable list to the caller.
|
|
|
|
+ return Collections.unmodifiableList((List) object);
|
|
|
|
+ } else {
|
|
|
|
+ return object;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType setField(final FieldDescriptor field, final Object value) {
|
|
|
|
+ internalGetFieldAccessorTable().getField(field).set(this, value);
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clearField(final FieldDescriptor field) {
|
|
|
|
+ internalGetFieldAccessorTable().getField(field).clear(this);
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clearOneof(final OneofDescriptor oneof) {
|
|
|
|
+ internalGetFieldAccessorTable().getOneof(oneof).clear(this);
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field)
|
|
|
|
+ .getRepeatedCount(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedField(final FieldDescriptor field, final int index) {
|
|
|
|
+ return internalGetFieldAccessorTable().getField(field)
|
|
|
|
+ .getRepeated(this, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType setRepeatedField(
|
|
|
|
+ final FieldDescriptor field, final int index, final Object value) {
|
|
|
|
+ internalGetFieldAccessorTable().getField(field)
|
|
|
|
+ .setRepeated(this, index, value);
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType addRepeatedField(final FieldDescriptor field, final Object value) {
|
|
|
|
+ internalGetFieldAccessorTable().getField(field).addRepeated(this, value);
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType setUnknownFields(final UnknownFieldSet unknownFields) {
|
|
|
|
+ this.unknownFields = unknownFields;
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType mergeUnknownFields(
|
|
|
|
+ final UnknownFieldSet unknownFields) {
|
|
|
|
+ this.unknownFields =
|
|
|
|
+ UnknownFieldSet.newBuilder(this.unknownFields)
|
|
|
|
+ .mergeFrom(unknownFields)
|
|
|
|
+ .build();
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isInitialized() {
|
|
|
|
+ for (final FieldDescriptor field : getDescriptorForType().getFields()) {
|
|
|
|
+ // Check that all required fields are present.
|
|
|
|
+ if (field.isRequired()) {
|
|
|
|
+ if (!hasField(field)) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Check that embedded messages are initialized.
|
|
|
|
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ @SuppressWarnings("unchecked") final
|
|
|
|
+ List<Message> messageList = (List<Message>) getField(field);
|
|
|
|
+ for (final Message element : messageList) {
|
|
|
|
+ if (!element.isInitialized()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (hasField(field) &&
|
|
|
|
+ !((Message) getField(field)).isInitialized()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public final UnknownFieldSet getUnknownFields() {
|
|
|
|
+ return unknownFields;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by subclasses to parse an unknown field.
|
|
|
|
+ * @return {@code true} unless the tag is an end-group tag.
|
|
|
|
+ */
|
|
|
|
+ protected boolean parseUnknownField(
|
|
|
|
+ final CodedInputStream input,
|
|
|
|
+ final UnknownFieldSet.Builder unknownFields,
|
|
|
|
+ final ExtensionRegistryLite extensionRegistry,
|
|
|
|
+ final int tag) throws IOException {
|
|
|
|
+ return unknownFields.mergeFieldFrom(tag, input);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Implementation of {@link BuilderParent} for giving to our children. This
|
|
|
|
+ * small inner class makes it so we don't publicly expose the BuilderParent
|
|
|
|
+ * methods.
|
|
|
|
+ */
|
|
|
|
+ private class BuilderParentImpl implements BuilderParent {
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void markDirty() {
|
|
|
|
+ onChanged();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the {@link BuilderParent} for giving to our children.
|
|
|
|
+ * @return The builder parent for our children.
|
|
|
|
+ */
|
|
|
|
+ protected BuilderParent getParentForChildren() {
|
|
|
|
+ if (meAsParent == null) {
|
|
|
|
+ meAsParent = new BuilderParentImpl();
|
|
|
|
+ }
|
|
|
|
+ return meAsParent;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called when a the builder or one of its nested children has changed
|
|
|
|
+ * and any parent should be notified of its invalidation.
|
|
|
|
+ */
|
|
|
|
+ protected final void onChanged() {
|
|
|
|
+ if (isClean && builderParent != null) {
|
|
|
|
+ builderParent.markDirty();
|
|
|
|
+
|
|
|
|
+ // Don't keep dispatching invalidations until build is called again.
|
|
|
|
+ isClean = false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the map field with the given field number. This method should be
|
|
|
|
+ * overridden in the generated message class if the message contains map
|
|
|
|
+ * fields.
|
|
|
|
+ *
|
|
|
|
+ * Unlike other field types, reflection support for map fields can't be
|
|
|
|
+ * implemented based on generated public API because we need to access a
|
|
|
|
+ * map field as a list in reflection API but the generated API only allows
|
|
|
|
+ * us to access it as a map. This method returns the underlying map field
|
|
|
|
+ * directly and thus enables us to access the map field as a list.
|
|
|
|
+ */
|
|
|
|
+ @SuppressWarnings({"unused", "rawtypes"})
|
|
|
|
+ protected MapField internalGetMapField(int fieldNumber) {
|
|
|
|
+ // Note that we can't use descriptor names here because this method will
|
|
|
|
+ // be called when descriptor is being initialized.
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "No map fields found in " + getClass().getName());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Like {@link #internalGetMapField} but return a mutable version. */
|
|
|
|
+ @SuppressWarnings({"unused", "rawtypes"})
|
|
|
|
+ protected MapField internalGetMutableMapField(int fieldNumber) {
|
|
|
|
+ // Note that we can't use descriptor names here because this method will
|
|
|
|
+ // be called when descriptor is being initialized.
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "No map fields found in " + getClass().getName());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // =================================================================
|
|
|
|
+ // Extensions-related stuff
|
|
|
|
+
|
|
|
|
+ public interface ExtendableMessageOrBuilder<
|
|
|
|
+ MessageType extends ExtendableMessage> extends MessageOrBuilder {
|
|
|
|
+ // Re-define for return type covariance.
|
|
|
|
+ @Override
|
|
|
|
+ Message getDefaultInstanceForType();
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ <Type> boolean hasExtension(
|
|
|
|
+ ExtensionLite<MessageType, Type> extension);
|
|
|
|
+
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ <Type> int getExtensionCount(
|
|
|
|
+ ExtensionLite<MessageType, List<Type>> extension);
|
|
|
|
+
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ ExtensionLite<MessageType, Type> extension);
|
|
|
|
+
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ ExtensionLite<MessageType, List<Type>> extension,
|
|
|
|
+ int index);
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ <Type> boolean hasExtension(
|
|
|
|
+ Extension<MessageType, Type> extension);
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ <Type> boolean hasExtension(
|
|
|
|
+ GeneratedExtension<MessageType, Type> extension);
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ <Type> int getExtensionCount(
|
|
|
|
+ Extension<MessageType, List<Type>> extension);
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ <Type> int getExtensionCount(
|
|
|
|
+ GeneratedExtension<MessageType, List<Type>> extension);
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ Extension<MessageType, Type> extension);
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ GeneratedExtension<MessageType, Type> extension);
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ Extension<MessageType, List<Type>> extension,
|
|
|
|
+ int index);
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ <Type> Type getExtension(
|
|
|
|
+ GeneratedExtension<MessageType, List<Type>> extension,
|
|
|
|
+ int index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Generated message classes for message types that contain extension ranges
|
|
|
|
+ * subclass this.
|
|
|
|
+ *
|
|
|
|
+ * <p>This class implements type-safe accessors for extensions. They
|
|
|
|
+ * implement all the same operations that you can do with normal fields --
|
|
|
|
+ * e.g. "has", "get", and "getCount" -- but for extensions. The extensions
|
|
|
|
+ * are identified using instances of the class {@link GeneratedExtension};
|
|
|
|
+ * the protocol compiler generates a static instance of this class for every
|
|
|
|
+ * extension in its input. Through the magic of generics, all is made
|
|
|
|
+ * type-safe.
|
|
|
|
+ *
|
|
|
|
+ * <p>For example, imagine you have the {@code .proto} file:
|
|
|
|
+ *
|
|
|
|
+ * <pre>
|
|
|
|
+ * option java_class = "MyProto";
|
|
|
|
+ *
|
|
|
|
+ * message Foo {
|
|
|
|
+ * extensions 1000 to max;
|
|
|
|
+ * }
|
|
|
|
+ *
|
|
|
|
+ * extend Foo {
|
|
|
|
+ * optional int32 bar;
|
|
|
|
+ * }
|
|
|
|
+ * </pre>
|
|
|
|
+ *
|
|
|
|
+ * <p>Then you might write code like:
|
|
|
|
+ *
|
|
|
|
+ * <pre>
|
|
|
|
+ * MyProto.Foo foo = getFoo();
|
|
|
|
+ * int i = foo.getExtension(MyProto.bar);
|
|
|
|
+ * </pre>
|
|
|
|
+ *
|
|
|
|
+ * <p>See also {@link ExtendableBuilder}.
|
|
|
|
+ */
|
|
|
|
+ public abstract static class ExtendableMessage<
|
|
|
|
+ MessageType extends ExtendableMessage>
|
|
|
|
+ extends GeneratedMessageV3
|
|
|
|
+ implements ExtendableMessageOrBuilder<MessageType> {
|
|
|
|
+
|
|
|
|
+ private static final long serialVersionUID = 1L;
|
|
|
|
+
|
|
|
|
+ private final FieldSet<FieldDescriptor> extensions;
|
|
|
|
+
|
|
|
|
+ protected ExtendableMessage() {
|
|
|
|
+ this.extensions = FieldSet.newFieldSet();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected ExtendableMessage(
|
|
|
|
+ ExtendableBuilder<MessageType, ?> builder) {
|
|
|
|
+ super(builder);
|
|
|
|
+ this.extensions = builder.buildExtensions();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void verifyExtensionContainingType(
|
|
|
|
+ final Extension<MessageType, ?> extension) {
|
|
|
|
+ if (extension.getDescriptor().getContainingType() !=
|
|
|
|
+ getDescriptorForType()) {
|
|
|
|
+ // This can only happen if someone uses unchecked operations.
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "Extension is for type \"" +
|
|
|
|
+ extension.getDescriptor().getContainingType().getFullName() +
|
|
|
|
+ "\" which does not match message type \"" +
|
|
|
|
+ getDescriptorForType().getFullName() + "\".");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
|
|
|
|
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ return extensions.hasField(extension.getDescriptor());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ final FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ return extensions.getRepeatedFieldCount(descriptor);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
|
|
|
|
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ final Object value = extensions.getField(descriptor);
|
|
|
|
+ if (value == null) {
|
|
|
|
+ if (descriptor.isRepeated()) {
|
|
|
|
+ return (Type) Collections.emptyList();
|
|
|
|
+ } else if (descriptor.getJavaType() ==
|
|
|
|
+ FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ return (Type) extension.getMessageDefaultInstance();
|
|
|
|
+ } else {
|
|
|
|
+ return (Type) extension.fromReflectionType(
|
|
|
|
+ descriptor.getDefaultValue());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return (Type) extension.fromReflectionType(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ return (Type) extension.singularFromReflectionType(
|
|
|
|
+ extensions.getRepeatedField(descriptor, index));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
|
|
|
|
+ return hasExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, Type> extension) {
|
|
|
|
+ return hasExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension) {
|
|
|
|
+ return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension) {
|
|
|
|
+ return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, Type> extension) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension, final int index) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
|
|
|
|
+ }
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Called by subclasses to check if all extensions are initialized. */
|
|
|
|
+ protected boolean extensionsAreInitialized() {
|
|
|
|
+ return extensions.isInitialized();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isInitialized() {
|
|
|
|
+ return super.isInitialized() && extensionsAreInitialized();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ protected boolean parseUnknownField(
|
|
|
|
+ CodedInputStream input,
|
|
|
|
+ UnknownFieldSet.Builder unknownFields,
|
|
|
|
+ ExtensionRegistryLite extensionRegistry,
|
|
|
|
+ int tag) throws IOException {
|
|
|
|
+ return MessageReflection.mergeFieldFrom(
|
|
|
|
+ input, unknownFields, extensionRegistry, getDescriptorForType(),
|
|
|
|
+ new MessageReflection.ExtensionAdapter(extensions), tag);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used by parsing constructors in generated classes.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ protected void makeExtensionsImmutable() {
|
|
|
|
+ extensions.makeImmutable();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Used by subclasses to serialize extensions. Extension ranges may be
|
|
|
|
+ * interleaved with field numbers, but we must write them in canonical
|
|
|
|
+ * (sorted by field number) order. ExtensionWriter helps us write
|
|
|
|
+ * individual ranges of extensions at once.
|
|
|
|
+ */
|
|
|
|
+ protected class ExtensionWriter {
|
|
|
|
+ // Imagine how much simpler this code would be if Java iterators had
|
|
|
|
+ // a way to get the next element without advancing the iterator.
|
|
|
|
+
|
|
|
|
+ private final Iterator<Map.Entry<FieldDescriptor, Object>> iter =
|
|
|
|
+ extensions.iterator();
|
|
|
|
+ private Map.Entry<FieldDescriptor, Object> next;
|
|
|
|
+ private final boolean messageSetWireFormat;
|
|
|
|
+
|
|
|
|
+ private ExtensionWriter(final boolean messageSetWireFormat) {
|
|
|
|
+ if (iter.hasNext()) {
|
|
|
|
+ next = iter.next();
|
|
|
|
+ }
|
|
|
|
+ this.messageSetWireFormat = messageSetWireFormat;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void writeUntil(final int end, final CodedOutputStream output)
|
|
|
|
+ throws IOException {
|
|
|
|
+ while (next != null && next.getKey().getNumber() < end) {
|
|
|
|
+ FieldDescriptor descriptor = next.getKey();
|
|
|
|
+ if (messageSetWireFormat && descriptor.getLiteJavaType() ==
|
|
|
|
+ WireFormat.JavaType.MESSAGE &&
|
|
|
|
+ !descriptor.isRepeated()) {
|
|
|
|
+ if (next instanceof LazyField.LazyEntry<?>) {
|
|
|
|
+ output.writeRawMessageSetExtension(descriptor.getNumber(),
|
|
|
|
+ ((LazyField.LazyEntry<?>) next).getField().toByteString());
|
|
|
|
+ } else {
|
|
|
|
+ output.writeMessageSetExtension(descriptor.getNumber(),
|
|
|
|
+ (Message) next.getValue());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ // TODO(xiangl): Taken care of following code, it may cause
|
|
|
|
+ // problem when we use LazyField for normal fields/extensions.
|
|
|
|
+ // Due to the optional field can be duplicated at the end of
|
|
|
|
+ // serialized bytes, which will make the serialized size change
|
|
|
|
+ // after lazy field parsed. So when we use LazyField globally,
|
|
|
|
+ // we need to change the following write method to write cached
|
|
|
|
+ // bytes directly rather than write the parsed message.
|
|
|
|
+ FieldSet.writeField(descriptor, next.getValue(), output);
|
|
|
|
+ }
|
|
|
|
+ if (iter.hasNext()) {
|
|
|
|
+ next = iter.next();
|
|
|
|
+ } else {
|
|
|
|
+ next = null;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected ExtensionWriter newExtensionWriter() {
|
|
|
|
+ return new ExtensionWriter(false);
|
|
|
|
+ }
|
|
|
|
+ protected ExtensionWriter newMessageSetExtensionWriter() {
|
|
|
|
+ return new ExtensionWriter(true);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Called by subclasses to compute the size of extensions. */
|
|
|
|
+ protected int extensionsSerializedSize() {
|
|
|
|
+ return extensions.getSerializedSize();
|
|
|
|
+ }
|
|
|
|
+ protected int extensionsSerializedSizeAsMessageSet() {
|
|
|
|
+ return extensions.getMessageSetSerializedSize();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+ // Reflection
|
|
|
|
+
|
|
|
|
+ protected Map<FieldDescriptor, Object> getExtensionFields() {
|
|
|
|
+ return extensions.getAllFields();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Map<FieldDescriptor, Object> getAllFields() {
|
|
|
|
+ final Map<FieldDescriptor, Object> result =
|
|
|
|
+ super.getAllFieldsMutable(/* getBytesForString = */ false);
|
|
|
|
+ result.putAll(getExtensionFields());
|
|
|
|
+ return Collections.unmodifiableMap(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Map<FieldDescriptor, Object> getAllFieldsRaw() {
|
|
|
|
+ final Map<FieldDescriptor, Object> result =
|
|
|
|
+ super.getAllFieldsMutable(/* getBytesForString = */ false);
|
|
|
|
+ result.putAll(getExtensionFields());
|
|
|
|
+ return Collections.unmodifiableMap(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasField(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.hasField(field);
|
|
|
|
+ } else {
|
|
|
|
+ return super.hasField(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getField(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ final Object value = extensions.getField(field);
|
|
|
|
+ if (value == null) {
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ return Collections.emptyList();
|
|
|
|
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ // Lacking an ExtensionRegistry, we have no way to determine the
|
|
|
|
+ // extension's real type, so we return a DynamicMessage.
|
|
|
|
+ return DynamicMessage.getDefaultInstance(field.getMessageType());
|
|
|
|
+ } else {
|
|
|
|
+ return field.getDefaultValue();
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return super.getField(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.getRepeatedFieldCount(field);
|
|
|
|
+ } else {
|
|
|
|
+ return super.getRepeatedFieldCount(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedField(final FieldDescriptor field,
|
|
|
|
+ final int index) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.getRepeatedField(field, index);
|
|
|
|
+ } else {
|
|
|
|
+ return super.getRepeatedField(field, index);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void verifyContainingType(final FieldDescriptor field) {
|
|
|
|
+ if (field.getContainingType() != getDescriptorForType()) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "FieldDescriptor does not match message type.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Generated message builders for message types that contain extension ranges
|
|
|
|
+ * subclass this.
|
|
|
|
+ *
|
|
|
|
+ * <p>This class implements type-safe accessors for extensions. They
|
|
|
|
+ * implement all the same operations that you can do with normal fields --
|
|
|
|
+ * e.g. "get", "set", and "add" -- but for extensions. The extensions are
|
|
|
|
+ * identified using instances of the class {@link GeneratedExtension}; the
|
|
|
|
+ * protocol compiler generates a static instance of this class for every
|
|
|
|
+ * extension in its input. Through the magic of generics, all is made
|
|
|
|
+ * type-safe.
|
|
|
|
+ *
|
|
|
|
+ * <p>For example, imagine you have the {@code .proto} file:
|
|
|
|
+ *
|
|
|
|
+ * <pre>
|
|
|
|
+ * option java_class = "MyProto";
|
|
|
|
+ *
|
|
|
|
+ * message Foo {
|
|
|
|
+ * extensions 1000 to max;
|
|
|
|
+ * }
|
|
|
|
+ *
|
|
|
|
+ * extend Foo {
|
|
|
|
+ * optional int32 bar;
|
|
|
|
+ * }
|
|
|
|
+ * </pre>
|
|
|
|
+ *
|
|
|
|
+ * <p>Then you might write code like:
|
|
|
|
+ *
|
|
|
|
+ * <pre>
|
|
|
|
+ * MyProto.Foo foo =
|
|
|
|
+ * MyProto.Foo.newBuilder()
|
|
|
|
+ * .setExtension(MyProto.bar, 123)
|
|
|
|
+ * .build();
|
|
|
|
+ * </pre>
|
|
|
|
+ *
|
|
|
|
+ * <p>See also {@link ExtendableMessage}.
|
|
|
|
+ */
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public abstract static class ExtendableBuilder<
|
|
|
|
+ MessageType extends ExtendableMessage,
|
|
|
|
+ BuilderType extends ExtendableBuilder<MessageType, BuilderType>>
|
|
|
|
+ extends Builder<BuilderType>
|
|
|
|
+ implements ExtendableMessageOrBuilder<MessageType> {
|
|
|
|
+
|
|
|
|
+ private FieldSet<FieldDescriptor> extensions = FieldSet.emptySet();
|
|
|
|
+
|
|
|
|
+ protected ExtendableBuilder() {}
|
|
|
|
+
|
|
|
|
+ protected ExtendableBuilder(
|
|
|
|
+ BuilderParent parent) {
|
|
|
|
+ super(parent);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // For immutable message conversion.
|
|
|
|
+ void internalSetExtensionSet(FieldSet<FieldDescriptor> extensions) {
|
|
|
|
+ this.extensions = extensions;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clear() {
|
|
|
|
+ extensions = FieldSet.emptySet();
|
|
|
|
+ return super.clear();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // This is implemented here only to work around an apparent bug in the
|
|
|
|
+ // Java compiler and/or build system. See bug #1898463. The mere presence
|
|
|
|
+ // of this clone() implementation makes it go away.
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clone() {
|
|
|
|
+ return super.clone();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void ensureExtensionsIsMutable() {
|
|
|
|
+ if (extensions.isImmutable()) {
|
|
|
|
+ extensions = extensions.clone();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void verifyExtensionContainingType(
|
|
|
|
+ final Extension<MessageType, ?> extension) {
|
|
|
|
+ if (extension.getDescriptor().getContainingType() !=
|
|
|
|
+ getDescriptorForType()) {
|
|
|
|
+ // This can only happen if someone uses unchecked operations.
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "Extension is for type \"" +
|
|
|
|
+ extension.getDescriptor().getContainingType().getFullName() +
|
|
|
|
+ "\" which does not match message type \"" +
|
|
|
|
+ getDescriptorForType().getFullName() + "\".");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(final ExtensionLite<MessageType, Type> extensionLite) {
|
|
|
|
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ return extensions.hasField(extension.getDescriptor());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ final FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ return extensions.getRepeatedFieldCount(descriptor);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(final ExtensionLite<MessageType, Type> extensionLite) {
|
|
|
|
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ final Object value = extensions.getField(descriptor);
|
|
|
|
+ if (value == null) {
|
|
|
|
+ if (descriptor.isRepeated()) {
|
|
|
|
+ return (Type) Collections.emptyList();
|
|
|
|
+ } else if (descriptor.getJavaType() ==
|
|
|
|
+ FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ return (Type) extension.getMessageDefaultInstance();
|
|
|
|
+ } else {
|
|
|
|
+ return (Type) extension.fromReflectionType(
|
|
|
|
+ descriptor.getDefaultValue());
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return (Type) extension.fromReflectionType(value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get one element of a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite, final int index) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ return (Type) extension.singularFromReflectionType(
|
|
|
|
+ extensions.getRepeatedField(descriptor, index));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Set the value of an extension. */
|
|
|
|
+ public final <Type> BuilderType setExtension(
|
|
|
|
+ final ExtensionLite<MessageType, Type> extensionLite,
|
|
|
|
+ final Type value) {
|
|
|
|
+ Extension<MessageType, Type> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ final FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ extensions.setField(descriptor, extension.toReflectionType(value));
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Set the value of one element of a repeated extension. */
|
|
|
|
+ public final <Type> BuilderType setExtension(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
|
|
|
|
+ final int index, final Type value) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ final FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ extensions.setRepeatedField(
|
|
|
|
+ descriptor, index,
|
|
|
|
+ extension.singularToReflectionType(value));
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Append a value to a repeated extension. */
|
|
|
|
+ public final <Type> BuilderType addExtension(
|
|
|
|
+ final ExtensionLite<MessageType, List<Type>> extensionLite,
|
|
|
|
+ final Type value) {
|
|
|
|
+ Extension<MessageType, List<Type>> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ final FieldDescriptor descriptor = extension.getDescriptor();
|
|
|
|
+ extensions.addRepeatedField(
|
|
|
|
+ descriptor, extension.singularToReflectionType(value));
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Clear an extension. */
|
|
|
|
+ public final <Type> BuilderType clearExtension(
|
|
|
|
+ final ExtensionLite<MessageType, ?> extensionLite) {
|
|
|
|
+ Extension<MessageType, ?> extension = checkNotLite(extensionLite);
|
|
|
|
+
|
|
|
|
+ verifyExtensionContainingType(extension);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.clearField(extension.getDescriptor());
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(final Extension<MessageType, Type> extension) {
|
|
|
|
+ return hasExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Check if a singular extension is present. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> boolean hasExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, Type> extension) {
|
|
|
|
+ return hasExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension) {
|
|
|
|
+ return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the number of elements in a repeated extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> int getExtensionCount(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension) {
|
|
|
|
+ return getExtensionCount((ExtensionLite<MessageType, List<Type>>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(final Extension<MessageType, Type> extension) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, Type> extension) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, Type>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension, final int index) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
|
|
|
|
+ }
|
|
|
|
+ /** Get the value of an extension. */
|
|
|
|
+ @Override
|
|
|
|
+ public final <Type> Type getExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension, final int index) {
|
|
|
|
+ return getExtension((ExtensionLite<MessageType, List<Type>>) extension, index);
|
|
|
|
+ }
|
|
|
|
+ /** Set the value of an extension. */
|
|
|
|
+ public final <Type> BuilderType setExtension(
|
|
|
|
+ final Extension<MessageType, Type> extension, final Type value) {
|
|
|
|
+ return setExtension((ExtensionLite<MessageType, Type>) extension, value);
|
|
|
|
+ }
|
|
|
|
+ /** Set the value of an extension. */
|
|
|
|
+ public <Type> BuilderType setExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, Type> extension, final Type value) {
|
|
|
|
+ return setExtension((ExtensionLite<MessageType, Type>) extension, value);
|
|
|
|
+ }
|
|
|
|
+ /** Set the value of one element of a repeated extension. */
|
|
|
|
+ public final <Type> BuilderType setExtension(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension,
|
|
|
|
+ final int index, final Type value) {
|
|
|
|
+ return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
|
|
|
|
+ }
|
|
|
|
+ /** Set the value of one element of a repeated extension. */
|
|
|
|
+ public <Type> BuilderType setExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension,
|
|
|
|
+ final int index, final Type value) {
|
|
|
|
+ return setExtension((ExtensionLite<MessageType, List<Type>>) extension, index, value);
|
|
|
|
+ }
|
|
|
|
+ /** Append a value to a repeated extension. */
|
|
|
|
+ public final <Type> BuilderType addExtension(
|
|
|
|
+ final Extension<MessageType, List<Type>> extension, final Type value) {
|
|
|
|
+ return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
|
|
|
|
+ }
|
|
|
|
+ /** Append a value to a repeated extension. */
|
|
|
|
+ public <Type> BuilderType addExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, List<Type>> extension, final Type value) {
|
|
|
|
+ return addExtension((ExtensionLite<MessageType, List<Type>>) extension, value);
|
|
|
|
+ }
|
|
|
|
+ /** Clear an extension. */
|
|
|
|
+ public final <Type> BuilderType clearExtension(
|
|
|
|
+ final Extension<MessageType, ?> extension) {
|
|
|
|
+ return clearExtension((ExtensionLite<MessageType, ?>) extension);
|
|
|
|
+ }
|
|
|
|
+ /** Clear an extension. */
|
|
|
|
+ public <Type> BuilderType clearExtension(
|
|
|
|
+ final GeneratedExtension<MessageType, ?> extension) {
|
|
|
|
+ return clearExtension((ExtensionLite<MessageType, ?>) extension);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Called by subclasses to check if all extensions are initialized. */
|
|
|
|
+ protected boolean extensionsAreInitialized() {
|
|
|
|
+ return extensions.isInitialized();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by the build code path to create a copy of the extensions for
|
|
|
|
+ * building the message.
|
|
|
|
+ */
|
|
|
|
+ private FieldSet<FieldDescriptor> buildExtensions() {
|
|
|
|
+ extensions.makeImmutable();
|
|
|
|
+ return extensions;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean isInitialized() {
|
|
|
|
+ return super.isInitialized() && extensionsAreInitialized();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Called by subclasses to parse an unknown field or an extension.
|
|
|
|
+ * @return {@code true} unless the tag is an end-group tag.
|
|
|
|
+ */
|
|
|
|
+ @Override
|
|
|
|
+ protected boolean parseUnknownField(
|
|
|
|
+ final CodedInputStream input,
|
|
|
|
+ final UnknownFieldSet.Builder unknownFields,
|
|
|
|
+ final ExtensionRegistryLite extensionRegistry,
|
|
|
|
+ final int tag) throws IOException {
|
|
|
|
+ return MessageReflection.mergeFieldFrom(
|
|
|
|
+ input, unknownFields, extensionRegistry, getDescriptorForType(),
|
|
|
|
+ new MessageReflection.BuilderAdapter(this), tag);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+ // Reflection
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Map<FieldDescriptor, Object> getAllFields() {
|
|
|
|
+ final Map<FieldDescriptor, Object> result = super.getAllFieldsMutable();
|
|
|
|
+ result.putAll(extensions.getAllFields());
|
|
|
|
+ return Collections.unmodifiableMap(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getField(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ final Object value = extensions.getField(field);
|
|
|
|
+ if (value == null) {
|
|
|
|
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ // Lacking an ExtensionRegistry, we have no way to determine the
|
|
|
|
+ // extension's real type, so we return a DynamicMessage.
|
|
|
|
+ return DynamicMessage.getDefaultInstance(field.getMessageType());
|
|
|
|
+ } else {
|
|
|
|
+ return field.getDefaultValue();
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return value;
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ return super.getField(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedFieldCount(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.getRepeatedFieldCount(field);
|
|
|
|
+ } else {
|
|
|
|
+ return super.getRepeatedFieldCount(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedField(final FieldDescriptor field,
|
|
|
|
+ final int index) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.getRepeatedField(field, index);
|
|
|
|
+ } else {
|
|
|
|
+ return super.getRepeatedField(field, index);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean hasField(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ return extensions.hasField(field);
|
|
|
|
+ } else {
|
|
|
|
+ return super.hasField(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType setField(final FieldDescriptor field,
|
|
|
|
+ final Object value) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.setField(field, value);
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ } else {
|
|
|
|
+ return super.setField(field, value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType clearField(final FieldDescriptor field) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.clearField(field);
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ } else {
|
|
|
|
+ return super.clearField(field);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType setRepeatedField(final FieldDescriptor field,
|
|
|
|
+ final int index, final Object value) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.setRepeatedField(field, index, value);
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ } else {
|
|
|
|
+ return super.setRepeatedField(field, index, value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public BuilderType addRepeatedField(final FieldDescriptor field,
|
|
|
|
+ final Object value) {
|
|
|
|
+ if (field.isExtension()) {
|
|
|
|
+ verifyContainingType(field);
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.addRepeatedField(field, value);
|
|
|
|
+ onChanged();
|
|
|
|
+ return (BuilderType) this;
|
|
|
|
+ } else {
|
|
|
|
+ return super.addRepeatedField(field, value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected final void mergeExtensionFields(final ExtendableMessage other) {
|
|
|
|
+ ensureExtensionsIsMutable();
|
|
|
|
+ extensions.mergeFrom(other.extensions);
|
|
|
|
+ onChanged();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private void verifyContainingType(final FieldDescriptor field) {
|
|
|
|
+ if (field.getContainingType() != getDescriptorForType()) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "FieldDescriptor does not match message type.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // -----------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the descriptor for an extension. The implementation depends on whether
|
|
|
|
+ * the extension is scoped in the top level of a file or scoped in a Message.
|
|
|
|
+ */
|
|
|
|
+ static interface ExtensionDescriptorRetriever {
|
|
|
|
+ FieldDescriptor getDescriptor();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private abstract static class CachedDescriptorRetriever
|
|
|
|
+ implements ExtensionDescriptorRetriever {
|
|
|
|
+ private volatile FieldDescriptor descriptor;
|
|
|
|
+ protected abstract FieldDescriptor loadDescriptor();
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public FieldDescriptor getDescriptor() {
|
|
|
|
+ if (descriptor == null) {
|
|
|
|
+ synchronized (this) {
|
|
|
|
+ if (descriptor == null) {
|
|
|
|
+ descriptor = loadDescriptor();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return descriptor;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // =================================================================
|
|
|
|
+
|
|
|
|
+ /** Calls Class.getMethod and throws a RuntimeException if it fails. */
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ private static Method getMethodOrDie(
|
|
|
|
+ final Class clazz, final String name, final Class... params) {
|
|
|
|
+ try {
|
|
|
|
+ return clazz.getMethod(name, params);
|
|
|
|
+ } catch (NoSuchMethodException e) {
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "Generated message class \"" + clazz.getName() +
|
|
|
|
+ "\" missing method \"" + name + "\".", e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Calls invoke and throws a RuntimeException if it fails. */
|
|
|
|
+ private static Object invokeOrDie(
|
|
|
|
+ final Method method, final Object object, final Object... params) {
|
|
|
|
+ try {
|
|
|
|
+ return method.invoke(object, params);
|
|
|
|
+ } catch (IllegalAccessException e) {
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "Couldn't use Java reflection to implement protocol message " +
|
|
|
|
+ "reflection.", e);
|
|
|
|
+ } catch (InvocationTargetException e) {
|
|
|
|
+ final Throwable cause = e.getCause();
|
|
|
|
+ if (cause instanceof RuntimeException) {
|
|
|
|
+ throw (RuntimeException) cause;
|
|
|
|
+ } else if (cause instanceof Error) {
|
|
|
|
+ throw (Error) cause;
|
|
|
|
+ } else {
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "Unexpected exception thrown by generated accessor method.", cause);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Gets the map field with the given field number. This method should be
|
|
|
|
+ * overridden in the generated message class if the message contains map
|
|
|
|
+ * fields.
|
|
|
|
+ *
|
|
|
|
+ * Unlike other field types, reflection support for map fields can't be
|
|
|
|
+ * implemented based on generated public API because we need to access a
|
|
|
|
+ * map field as a list in reflection API but the generated API only allows
|
|
|
|
+ * us to access it as a map. This method returns the underlying map field
|
|
|
|
+ * directly and thus enables us to access the map field as a list.
|
|
|
|
+ */
|
|
|
|
+ @SuppressWarnings({"rawtypes", "unused"})
|
|
|
|
+ protected MapField internalGetMapField(int fieldNumber) {
|
|
|
|
+ // Note that we can't use descriptor names here because this method will
|
|
|
|
+ // be called when descriptor is being initialized.
|
|
|
|
+ throw new RuntimeException(
|
|
|
|
+ "No map fields found in " + getClass().getName());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Users should ignore this class. This class provides the implementation
|
|
|
|
+ * with access to the fields of a message object using Java reflection.
|
|
|
|
+ */
|
|
|
|
+ public static final class FieldAccessorTable {
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Construct a FieldAccessorTable for a particular message class. Only
|
|
|
|
+ * one FieldAccessorTable should ever be constructed per class.
|
|
|
|
+ *
|
|
|
|
+ * @param descriptor The type's descriptor.
|
|
|
|
+ * @param camelCaseNames The camelcase names of all fields in the message.
|
|
|
|
+ * These are used to derive the accessor method names.
|
|
|
|
+ * @param messageClass The message type.
|
|
|
|
+ * @param builderClass The builder type.
|
|
|
|
+ */
|
|
|
|
+ public FieldAccessorTable(
|
|
|
|
+ final Descriptor descriptor,
|
|
|
|
+ final String[] camelCaseNames,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ this(descriptor, camelCaseNames);
|
|
|
|
+ ensureFieldAccessorsInitialized(messageClass, builderClass);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Construct a FieldAccessorTable for a particular message class without
|
|
|
|
+ * initializing FieldAccessors.
|
|
|
|
+ */
|
|
|
|
+ public FieldAccessorTable(
|
|
|
|
+ final Descriptor descriptor,
|
|
|
|
+ final String[] camelCaseNames) {
|
|
|
|
+ this.descriptor = descriptor;
|
|
|
|
+ this.camelCaseNames = camelCaseNames;
|
|
|
|
+ fields = new FieldAccessor[descriptor.getFields().size()];
|
|
|
|
+ oneofs = new OneofAccessor[descriptor.getOneofs().size()];
|
|
|
|
+ initialized = false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private boolean isMapFieldEnabled(FieldDescriptor field) {
|
|
|
|
+ boolean result = true;
|
|
|
|
+ return result;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Ensures the field accessors are initialized. This method is thread-safe.
|
|
|
|
+ *
|
|
|
|
+ * @param messageClass The message type.
|
|
|
|
+ * @param builderClass The builder type.
|
|
|
|
+ * @return this
|
|
|
|
+ */
|
|
|
|
+ public FieldAccessorTable ensureFieldAccessorsInitialized(
|
|
|
|
+ Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ Class<? extends Builder> builderClass) {
|
|
|
|
+ if (initialized) { return this; }
|
|
|
|
+ synchronized (this) {
|
|
|
|
+ if (initialized) { return this; }
|
|
|
|
+ int fieldsSize = fields.length;
|
|
|
|
+ for (int i = 0; i < fieldsSize; i++) {
|
|
|
|
+ FieldDescriptor field = descriptor.getFields().get(i);
|
|
|
|
+ String containingOneofCamelCaseName = null;
|
|
|
|
+ if (field.getContainingOneof() != null) {
|
|
|
|
+ containingOneofCamelCaseName =
|
|
|
|
+ camelCaseNames[fieldsSize + field.getContainingOneof().getIndex()];
|
|
|
|
+ }
|
|
|
|
+ if (field.isRepeated()) {
|
|
|
|
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ if (field.isMapField() && isMapFieldEnabled(field)) {
|
|
|
|
+ fields[i] = new MapFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass);
|
|
|
|
+ } else {
|
|
|
|
+ fields[i] = new RepeatedMessageFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass);
|
|
|
|
+ }
|
|
|
|
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
|
|
|
|
+ fields[i] = new RepeatedEnumFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass);
|
|
|
|
+ } else {
|
|
|
|
+ fields[i] = new RepeatedFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass);
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ if (field.getJavaType() == FieldDescriptor.JavaType.MESSAGE) {
|
|
|
|
+ fields[i] = new SingularMessageFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.ENUM) {
|
|
|
|
+ fields[i] = new SingularEnumFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+ } else if (field.getJavaType() == FieldDescriptor.JavaType.STRING) {
|
|
|
|
+ fields[i] = new SingularStringFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+ } else {
|
|
|
|
+ fields[i] = new SingularFieldAccessor(
|
|
|
|
+ field, camelCaseNames[i], messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int oneofsSize = oneofs.length;
|
|
|
|
+ for (int i = 0; i < oneofsSize; i++) {
|
|
|
|
+ oneofs[i] = new OneofAccessor(
|
|
|
|
+ descriptor, camelCaseNames[i + fieldsSize],
|
|
|
|
+ messageClass, builderClass);
|
|
|
|
+ }
|
|
|
|
+ initialized = true;
|
|
|
|
+ camelCaseNames = null;
|
|
|
|
+ return this;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final Descriptor descriptor;
|
|
|
|
+ private final FieldAccessor[] fields;
|
|
|
|
+ private String[] camelCaseNames;
|
|
|
|
+ private final OneofAccessor[] oneofs;
|
|
|
|
+ private volatile boolean initialized;
|
|
|
|
+
|
|
|
|
+ /** Get the FieldAccessor for a particular field. */
|
|
|
|
+ private FieldAccessor getField(final FieldDescriptor field) {
|
|
|
|
+ if (field.getContainingType() != descriptor) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "FieldDescriptor does not match message type.");
|
|
|
|
+ } else if (field.isExtension()) {
|
|
|
|
+ // If this type had extensions, it would subclass ExtendableMessage,
|
|
|
|
+ // which overrides the reflection interface to handle extensions.
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "This type does not have extensions.");
|
|
|
|
+ }
|
|
|
|
+ return fields[field.getIndex()];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** Get the OneofAccessor for a particular oneof. */
|
|
|
|
+ private OneofAccessor getOneof(final OneofDescriptor oneof) {
|
|
|
|
+ if (oneof.getContainingType() != descriptor) {
|
|
|
|
+ throw new IllegalArgumentException(
|
|
|
|
+ "OneofDescriptor does not match message type.");
|
|
|
|
+ }
|
|
|
|
+ return oneofs[oneof.getIndex()];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Abstract interface that provides access to a single field. This is
|
|
|
|
+ * implemented differently depending on the field type and cardinality.
|
|
|
|
+ */
|
|
|
|
+ private interface FieldAccessor {
|
|
|
|
+ Object get(GeneratedMessageV3 message);
|
|
|
|
+ Object get(GeneratedMessageV3.Builder builder);
|
|
|
|
+ Object getRaw(GeneratedMessageV3 message);
|
|
|
|
+ Object getRaw(GeneratedMessageV3.Builder builder);
|
|
|
|
+ void set(Builder builder, Object value);
|
|
|
|
+ Object getRepeated(GeneratedMessageV3 message, int index);
|
|
|
|
+ Object getRepeated(GeneratedMessageV3.Builder builder, int index);
|
|
|
|
+ Object getRepeatedRaw(GeneratedMessageV3 message, int index);
|
|
|
|
+ Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index);
|
|
|
|
+ void setRepeated(Builder builder,
|
|
|
|
+ int index, Object value);
|
|
|
|
+ void addRepeated(Builder builder, Object value);
|
|
|
|
+ boolean has(GeneratedMessageV3 message);
|
|
|
|
+ boolean has(GeneratedMessageV3.Builder builder);
|
|
|
|
+ int getRepeatedCount(GeneratedMessageV3 message);
|
|
|
|
+ int getRepeatedCount(GeneratedMessageV3.Builder builder);
|
|
|
|
+ void clear(Builder builder);
|
|
|
|
+ Message.Builder newBuilder();
|
|
|
|
+ Message.Builder getBuilder(GeneratedMessageV3.Builder builder);
|
|
|
|
+ Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder,
|
|
|
|
+ int index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /** OneofAccessor provides access to a single oneof. */
|
|
|
|
+ private static class OneofAccessor {
|
|
|
|
+ OneofAccessor(
|
|
|
|
+ final Descriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ this.descriptor = descriptor;
|
|
|
|
+ caseMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Case");
|
|
|
|
+ caseMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Case");
|
|
|
|
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final Descriptor descriptor;
|
|
|
|
+ private final Method caseMethod;
|
|
|
|
+ private final Method caseMethodBuilder;
|
|
|
|
+ private final Method clearMethod;
|
|
|
|
+
|
|
|
|
+ public boolean has(final GeneratedMessageV3 message) {
|
|
|
|
+ if (((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber() == 0) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public boolean has(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ if (((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber() == 0) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public FieldDescriptor get(final GeneratedMessageV3 message) {
|
|
|
|
+ int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
|
|
|
|
+ if (fieldNumber > 0) {
|
|
|
|
+ return descriptor.findFieldByNumber(fieldNumber);
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public FieldDescriptor get(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ int fieldNumber = ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
|
|
|
|
+ if (fieldNumber > 0) {
|
|
|
|
+ return descriptor.findFieldByNumber(fieldNumber);
|
|
|
|
+ }
|
|
|
|
+ return null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public void clear(final Builder builder) {
|
|
|
|
+ invokeOrDie(clearMethod, builder);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static boolean supportFieldPresence(FileDescriptor file) {
|
|
|
|
+ return file.getSyntax() == FileDescriptor.Syntax.PROTO2;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ private static class SingularFieldAccessor implements FieldAccessor {
|
|
|
|
+ SingularFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass,
|
|
|
|
+ final String containingOneofCamelCaseName) {
|
|
|
|
+ field = descriptor;
|
|
|
|
+ isOneofField = descriptor.getContainingOneof() != null;
|
|
|
|
+ hasHasMethod = supportFieldPresence(descriptor.getFile())
|
|
|
|
+ || (!isOneofField && descriptor.getJavaType() == FieldDescriptor.JavaType.MESSAGE);
|
|
|
|
+ getMethod = getMethodOrDie(messageClass, "get" + camelCaseName);
|
|
|
|
+ getMethodBuilder = getMethodOrDie(builderClass, "get" + camelCaseName);
|
|
|
|
+ type = getMethod.getReturnType();
|
|
|
|
+ setMethod = getMethodOrDie(builderClass, "set" + camelCaseName, type);
|
|
|
|
+ hasMethod =
|
|
|
|
+ hasHasMethod ? getMethodOrDie(messageClass, "has" + camelCaseName) : null;
|
|
|
|
+ hasMethodBuilder =
|
|
|
|
+ hasHasMethod ? getMethodOrDie(builderClass, "has" + camelCaseName) : null;
|
|
|
|
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
|
|
|
|
+ caseMethod = isOneofField ? getMethodOrDie(
|
|
|
|
+ messageClass, "get" + containingOneofCamelCaseName + "Case") : null;
|
|
|
|
+ caseMethodBuilder = isOneofField ? getMethodOrDie(
|
|
|
|
+ builderClass, "get" + containingOneofCamelCaseName + "Case") : null;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Note: We use Java reflection to call public methods rather than
|
|
|
|
+ // access private fields directly as this avoids runtime security
|
|
|
|
+ // checks.
|
|
|
|
+ protected final Class<?> type;
|
|
|
|
+ protected final Method getMethod;
|
|
|
|
+ protected final Method getMethodBuilder;
|
|
|
|
+ protected final Method setMethod;
|
|
|
|
+ protected final Method hasMethod;
|
|
|
|
+ protected final Method hasMethodBuilder;
|
|
|
|
+ protected final Method clearMethod;
|
|
|
|
+ protected final Method caseMethod;
|
|
|
|
+ protected final Method caseMethodBuilder;
|
|
|
|
+ protected final FieldDescriptor field;
|
|
|
|
+ protected final boolean isOneofField;
|
|
|
|
+ protected final boolean hasHasMethod;
|
|
|
|
+
|
|
|
|
+ private int getOneofFieldNumber(final GeneratedMessageV3 message) {
|
|
|
|
+ return ((Internal.EnumLite) invokeOrDie(caseMethod, message)).getNumber();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private int getOneofFieldNumber(final GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return ((Internal.EnumLite) invokeOrDie(caseMethodBuilder, builder)).getNumber();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(final GeneratedMessageV3 message) {
|
|
|
|
+ return invokeOrDie(getMethod, message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return invokeOrDie(getMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(final GeneratedMessageV3 message) {
|
|
|
|
+ return get(message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return get(builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void set(final Builder builder, final Object value) {
|
|
|
|
+ invokeOrDie(setMethod, builder, value);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(final GeneratedMessageV3 message, final int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedField() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(final GeneratedMessageV3 message, final int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldRaw() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedField() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldRaw() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void setRepeated(final Builder builder, final int index, final Object value) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "setRepeatedField() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void addRepeated(final Builder builder, final Object value) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "addRepeatedField() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(final GeneratedMessageV3 message) {
|
|
|
|
+ if (!hasHasMethod) {
|
|
|
|
+ if (isOneofField) {
|
|
|
|
+ return getOneofFieldNumber(message) == field.getNumber();
|
|
|
|
+ }
|
|
|
|
+ return !get(message).equals(field.getDefaultValue());
|
|
|
|
+ }
|
|
|
|
+ return (Boolean) invokeOrDie(hasMethod, message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ if (!hasHasMethod) {
|
|
|
|
+ if (isOneofField) {
|
|
|
|
+ return getOneofFieldNumber(builder) == field.getNumber();
|
|
|
|
+ }
|
|
|
|
+ return !get(builder).equals(field.getDefaultValue());
|
|
|
|
+ }
|
|
|
|
+ return (Boolean) invokeOrDie(hasMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(final GeneratedMessageV3 message) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldSize() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldSize() called on a singular field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void clear(final Builder builder) {
|
|
|
|
+ invokeOrDie(clearMethod, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder newBuilder() {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "newBuilderForField() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getFieldBuilder() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldBuilder() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static class RepeatedFieldAccessor implements FieldAccessor {
|
|
|
|
+ protected final Class type;
|
|
|
|
+ protected final Method getMethod;
|
|
|
|
+ protected final Method getMethodBuilder;
|
|
|
|
+ protected final Method getRepeatedMethod;
|
|
|
|
+ protected final Method getRepeatedMethodBuilder;
|
|
|
|
+ protected final Method setRepeatedMethod;
|
|
|
|
+ protected final Method addRepeatedMethod;
|
|
|
|
+ protected final Method getCountMethod;
|
|
|
|
+ protected final Method getCountMethodBuilder;
|
|
|
|
+ protected final Method clearMethod;
|
|
|
|
+
|
|
|
|
+ RepeatedFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ getMethod = getMethodOrDie(messageClass,
|
|
|
|
+ "get" + camelCaseName + "List");
|
|
|
|
+ getMethodBuilder = getMethodOrDie(builderClass,
|
|
|
|
+ "get" + camelCaseName + "List");
|
|
|
|
+ getRepeatedMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "get" + camelCaseName, Integer.TYPE);
|
|
|
|
+ getRepeatedMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName, Integer.TYPE);
|
|
|
|
+ type = getRepeatedMethod.getReturnType();
|
|
|
|
+ setRepeatedMethod =
|
|
|
|
+ getMethodOrDie(builderClass, "set" + camelCaseName,
|
|
|
|
+ Integer.TYPE, type);
|
|
|
|
+ addRepeatedMethod =
|
|
|
|
+ getMethodOrDie(builderClass, "add" + camelCaseName, type);
|
|
|
|
+ getCountMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Count");
|
|
|
|
+ getCountMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Count");
|
|
|
|
+
|
|
|
|
+ clearMethod = getMethodOrDie(builderClass, "clear" + camelCaseName);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(final GeneratedMessageV3 message) {
|
|
|
|
+ return invokeOrDie(getMethod, message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return invokeOrDie(getMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(final GeneratedMessageV3 message) {
|
|
|
|
+ return get(message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return get(builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void set(final Builder builder, final Object value) {
|
|
|
|
+ // Add all the elements individually. This serves two purposes:
|
|
|
|
+ // 1) Verifies that each element has the correct type.
|
|
|
|
+ // 2) Insures that the caller cannot modify the list later on and
|
|
|
|
+ // have the modifications be reflected in the message.
|
|
|
|
+ clear(builder);
|
|
|
|
+ for (final Object element : (List<?>) value) {
|
|
|
|
+ addRepeated(builder, element);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(final GeneratedMessageV3 message, final int index) {
|
|
|
|
+ return invokeOrDie(getRepeatedMethod, message, index);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ return invokeOrDie(getRepeatedMethodBuilder, builder, index);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
|
|
|
|
+ return getRepeated(message, index);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ return getRepeated(builder, index);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void setRepeated(final Builder builder, final int index, final Object value) {
|
|
|
|
+ invokeOrDie(setRepeatedMethod, builder, index, value);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void addRepeated(final Builder builder, final Object value) {
|
|
|
|
+ invokeOrDie(addRepeatedMethod, builder, value);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(final GeneratedMessageV3 message) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "hasField() called on a repeated field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "hasField() called on a repeated field.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(final GeneratedMessageV3 message) {
|
|
|
|
+ return (Integer) invokeOrDie(getCountMethod, message);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return (Integer) invokeOrDie(getCountMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void clear(final Builder builder) {
|
|
|
|
+ invokeOrDie(clearMethod, builder);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder newBuilder() {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "newBuilderForField() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getFieldBuilder() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getRepeatedBuilder(GeneratedMessageV3.Builder builder, int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "getRepeatedFieldBuilder() called on a non-Message type.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static class MapFieldAccessor implements FieldAccessor {
|
|
|
|
+ MapFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ field = descriptor;
|
|
|
|
+ Method getDefaultInstanceMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "getDefaultInstance");
|
|
|
|
+ MapField defaultMapField = getMapField(
|
|
|
|
+ (GeneratedMessageV3) invokeOrDie(getDefaultInstanceMethod, null));
|
|
|
|
+ mapEntryMessageDefaultInstance =
|
|
|
|
+ defaultMapField.getMapEntryMessageDefaultInstance();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final FieldDescriptor field;
|
|
|
|
+ private final Message mapEntryMessageDefaultInstance;
|
|
|
|
+
|
|
|
|
+ private MapField<?, ?> getMapField(GeneratedMessageV3 message) {
|
|
|
|
+ return (MapField<?, ?>) message.internalGetMapField(field.getNumber());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private MapField<?, ?> getMapField(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return (MapField<?, ?>) builder.internalGetMapField(field.getNumber());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private MapField<?, ?> getMutableMapField(
|
|
|
|
+ GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return (MapField<?, ?>) builder.internalGetMutableMapField(
|
|
|
|
+ field.getNumber());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(GeneratedMessageV3 message) {
|
|
|
|
+ List result = new ArrayList();
|
|
|
|
+ for (int i = 0; i < getRepeatedCount(message); i++) {
|
|
|
|
+ result.add(getRepeated(message, i));
|
|
|
|
+ }
|
|
|
|
+ return Collections.unmodifiableList(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(Builder builder) {
|
|
|
|
+ List result = new ArrayList();
|
|
|
|
+ for (int i = 0; i < getRepeatedCount(builder); i++) {
|
|
|
|
+ result.add(getRepeated(builder, i));
|
|
|
|
+ }
|
|
|
|
+ return Collections.unmodifiableList(result);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(GeneratedMessageV3 message) {
|
|
|
|
+ return get(message);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return get(builder);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void set(Builder builder, Object value) {
|
|
|
|
+ clear(builder);
|
|
|
|
+ for (Object entry : (List) value) {
|
|
|
|
+ addRepeated(builder, entry);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(GeneratedMessageV3 message, int index) {
|
|
|
|
+ return getMapField(message).getList().get(index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(Builder builder, int index) {
|
|
|
|
+ return getMapField(builder).getList().get(index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(GeneratedMessageV3 message, int index) {
|
|
|
|
+ return getRepeated(message, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeatedRaw(Builder builder, int index) {
|
|
|
|
+ return getRepeated(builder, index);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void setRepeated(Builder builder, int index, Object value) {
|
|
|
|
+ getMutableMapField(builder).getMutableList().set(index, (Message) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void addRepeated(Builder builder, Object value) {
|
|
|
|
+ getMutableMapField(builder).getMutableList().add((Message) value);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(GeneratedMessageV3 message) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "hasField() is not supported for repeated fields.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public boolean has(Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "hasField() is not supported for repeated fields.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(GeneratedMessageV3 message) {
|
|
|
|
+ return getMapField(message).getList().size();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public int getRepeatedCount(Builder builder) {
|
|
|
|
+ return getMapField(builder).getList().size();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void clear(Builder builder) {
|
|
|
|
+ getMutableMapField(builder).getMutableList().clear();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public com.google.protobuf.Message.Builder newBuilder() {
|
|
|
|
+ return mapEntryMessageDefaultInstance.newBuilderForType();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public com.google.protobuf.Message.Builder getBuilder(Builder builder) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "Nested builder not supported for map fields.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public com.google.protobuf.Message.Builder getRepeatedBuilder(Builder builder, int index) {
|
|
|
|
+ throw new UnsupportedOperationException(
|
|
|
|
+ "Nested builder not supported for map fields.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ private static final class SingularEnumFieldAccessor
|
|
|
|
+ extends SingularFieldAccessor {
|
|
|
|
+ SingularEnumFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass,
|
|
|
|
+ final String containingOneofCamelCaseName) {
|
|
|
|
+ super(descriptor, camelCaseName, messageClass, builderClass, containingOneofCamelCaseName);
|
|
|
|
+
|
|
|
|
+ enumDescriptor = descriptor.getEnumType();
|
|
|
|
+
|
|
|
|
+ valueOfMethod = getMethodOrDie(type, "valueOf",
|
|
|
|
+ EnumValueDescriptor.class);
|
|
|
|
+ getValueDescriptorMethod =
|
|
|
|
+ getMethodOrDie(type, "getValueDescriptor");
|
|
|
|
+
|
|
|
|
+ supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ getValueMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Value");
|
|
|
|
+ getValueMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Value");
|
|
|
|
+ setValueMethod =
|
|
|
|
+ getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private EnumDescriptor enumDescriptor;
|
|
|
|
+
|
|
|
|
+ private Method valueOfMethod;
|
|
|
|
+ private Method getValueDescriptorMethod;
|
|
|
|
+
|
|
|
|
+ private boolean supportUnknownEnumValue;
|
|
|
|
+ private Method getValueMethod;
|
|
|
|
+ private Method getValueMethodBuilder;
|
|
|
|
+ private Method setValueMethod;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(final GeneratedMessageV3 message) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ int value = (Integer) invokeOrDie(getValueMethod, message);
|
|
|
|
+ return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
|
|
|
|
+ }
|
|
|
|
+ return invokeOrDie(getValueDescriptorMethod, super.get(message));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object get(final GeneratedMessageV3.Builder builder) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ int value = (Integer) invokeOrDie(getValueMethodBuilder, builder);
|
|
|
|
+ return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
|
|
|
|
+ }
|
|
|
|
+ return invokeOrDie(getValueDescriptorMethod, super.get(builder));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void set(final Builder builder, final Object value) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ invokeOrDie(setValueMethod, builder,
|
|
|
|
+ ((EnumValueDescriptor) value).getNumber());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ super.set(builder, invokeOrDie(valueOfMethod, null, value));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static final class RepeatedEnumFieldAccessor
|
|
|
|
+ extends RepeatedFieldAccessor {
|
|
|
|
+ RepeatedEnumFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ super(descriptor, camelCaseName, messageClass, builderClass);
|
|
|
|
+
|
|
|
|
+ enumDescriptor = descriptor.getEnumType();
|
|
|
|
+
|
|
|
|
+ valueOfMethod = getMethodOrDie(type, "valueOf",
|
|
|
|
+ EnumValueDescriptor.class);
|
|
|
|
+ getValueDescriptorMethod =
|
|
|
|
+ getMethodOrDie(type, "getValueDescriptor");
|
|
|
|
+
|
|
|
|
+ supportUnknownEnumValue = descriptor.getFile().supportsUnknownEnumValue();
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ getRepeatedValueMethod =
|
|
|
|
+ getMethodOrDie(messageClass, "get" + camelCaseName + "Value", int.class);
|
|
|
|
+ getRepeatedValueMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Value", int.class);
|
|
|
|
+ setRepeatedValueMethod =
|
|
|
|
+ getMethodOrDie(builderClass, "set" + camelCaseName + "Value", int.class, int.class);
|
|
|
|
+ addRepeatedValueMethod =
|
|
|
|
+ getMethodOrDie(builderClass, "add" + camelCaseName + "Value", int.class);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ private EnumDescriptor enumDescriptor;
|
|
|
|
+
|
|
|
|
+ private final Method valueOfMethod;
|
|
|
|
+ private final Method getValueDescriptorMethod;
|
|
|
|
+
|
|
|
|
+ private boolean supportUnknownEnumValue;
|
|
|
|
+ private Method getRepeatedValueMethod;
|
|
|
|
+ private Method getRepeatedValueMethodBuilder;
|
|
|
|
+ private Method setRepeatedValueMethod;
|
|
|
|
+ private Method addRepeatedValueMethod;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public Object get(final GeneratedMessageV3 message) {
|
|
|
|
+ final List newList = new ArrayList();
|
|
|
|
+ final int size = getRepeatedCount(message);
|
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
|
+ newList.add(getRepeated(message, i));
|
|
|
|
+ }
|
|
|
|
+ return Collections.unmodifiableList(newList);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
|
+ public Object get(final GeneratedMessageV3.Builder builder) {
|
|
|
|
+ final List newList = new ArrayList();
|
|
|
|
+ final int size = getRepeatedCount(builder);
|
|
|
|
+ for (int i = 0; i < size; i++) {
|
|
|
|
+ newList.add(getRepeated(builder, i));
|
|
|
|
+ }
|
|
|
|
+ return Collections.unmodifiableList(newList);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(final GeneratedMessageV3 message,
|
|
|
|
+ final int index) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ int value = (Integer) invokeOrDie(getRepeatedValueMethod, message, index);
|
|
|
|
+ return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
|
|
|
|
+ }
|
|
|
|
+ return invokeOrDie(getValueDescriptorMethod,
|
|
|
|
+ super.getRepeated(message, index));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRepeated(final GeneratedMessageV3.Builder builder,
|
|
|
|
+ final int index) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ int value = (Integer) invokeOrDie(getRepeatedValueMethodBuilder, builder, index);
|
|
|
|
+ return enumDescriptor.findValueByNumberCreatingIfUnknown(value);
|
|
|
|
+ }
|
|
|
|
+ return invokeOrDie(getValueDescriptorMethod,
|
|
|
|
+ super.getRepeated(builder, index));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void setRepeated(final Builder builder,
|
|
|
|
+ final int index, final Object value) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ invokeOrDie(setRepeatedValueMethod, builder, index,
|
|
|
|
+ ((EnumValueDescriptor) value).getNumber());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ super.setRepeated(builder, index, invokeOrDie(valueOfMethod, null,
|
|
|
|
+ value));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void addRepeated(final Builder builder, final Object value) {
|
|
|
|
+ if (supportUnknownEnumValue) {
|
|
|
|
+ invokeOrDie(addRepeatedValueMethod, builder,
|
|
|
|
+ ((EnumValueDescriptor) value).getNumber());
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ super.addRepeated(builder, invokeOrDie(valueOfMethod, null, value));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Field accessor for string fields.
|
|
|
|
+ *
|
|
|
|
+ * <p>This class makes getFooBytes() and setFooBytes() available for
|
|
|
|
+ * reflection API so that reflection based serialize/parse functions can
|
|
|
|
+ * access the raw bytes of the field to preserve non-UTF8 bytes in the
|
|
|
|
+ * string.
|
|
|
|
+ *
|
|
|
|
+ * <p>This ensures the serialize/parse round-trip safety, which is important
|
|
|
|
+ * for servers which forward messages.
|
|
|
|
+ */
|
|
|
|
+ private static final class SingularStringFieldAccessor
|
|
|
|
+ extends SingularFieldAccessor {
|
|
|
|
+ SingularStringFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass,
|
|
|
|
+ final String containingOneofCamelCaseName) {
|
|
|
|
+ super(descriptor, camelCaseName, messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+ getBytesMethod = getMethodOrDie(messageClass,
|
|
|
|
+ "get" + camelCaseName + "Bytes");
|
|
|
|
+ getBytesMethodBuilder = getMethodOrDie(builderClass,
|
|
|
|
+ "get" + camelCaseName + "Bytes");
|
|
|
|
+ setBytesMethodBuilder = getMethodOrDie(builderClass,
|
|
|
|
+ "set" + camelCaseName + "Bytes", ByteString.class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final Method getBytesMethod;
|
|
|
|
+ private final Method getBytesMethodBuilder;
|
|
|
|
+ private final Method setBytesMethodBuilder;
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(final GeneratedMessageV3 message) {
|
|
|
|
+ return invokeOrDie(getBytesMethod, message);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public Object getRaw(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return invokeOrDie(getBytesMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void set(GeneratedMessageV3.Builder builder, Object value) {
|
|
|
|
+ if (value instanceof ByteString) {
|
|
|
|
+ invokeOrDie(setBytesMethodBuilder, builder, value);
|
|
|
|
+ } else {
|
|
|
|
+ super.set(builder, value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // ---------------------------------------------------------------
|
|
|
|
+
|
|
|
|
+ private static final class SingularMessageFieldAccessor
|
|
|
|
+ extends SingularFieldAccessor {
|
|
|
|
+ SingularMessageFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass,
|
|
|
|
+ final String containingOneofCamelCaseName) {
|
|
|
|
+ super(descriptor, camelCaseName, messageClass, builderClass,
|
|
|
|
+ containingOneofCamelCaseName);
|
|
|
|
+
|
|
|
|
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
|
|
|
|
+ getBuilderMethodBuilder =
|
|
|
|
+ getMethodOrDie(builderClass, "get" + camelCaseName + "Builder");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final Method newBuilderMethod;
|
|
|
|
+ private final Method getBuilderMethodBuilder;
|
|
|
|
+
|
|
|
|
+ private Object coerceType(final Object value) {
|
|
|
|
+ if (type.isInstance(value)) {
|
|
|
|
+ return value;
|
|
|
|
+ } else {
|
|
|
|
+ // The value is not the exact right message type. However, if it
|
|
|
|
+ // is an alternative implementation of the same type -- e.g. a
|
|
|
|
+ // DynamicMessage -- we should accept it. In this case we can make
|
|
|
|
+ // a copy of the message.
|
|
|
|
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
|
|
|
|
+ .mergeFrom((Message) value).buildPartial();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void set(final Builder builder, final Object value) {
|
|
|
|
+ super.set(builder, coerceType(value));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder newBuilder() {
|
|
|
|
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getBuilder(GeneratedMessageV3.Builder builder) {
|
|
|
|
+ return (Message.Builder) invokeOrDie(getBuilderMethodBuilder, builder);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static final class RepeatedMessageFieldAccessor
|
|
|
|
+ extends RepeatedFieldAccessor {
|
|
|
|
+ RepeatedMessageFieldAccessor(
|
|
|
|
+ final FieldDescriptor descriptor, final String camelCaseName,
|
|
|
|
+ final Class<? extends GeneratedMessageV3> messageClass,
|
|
|
|
+ final Class<? extends Builder> builderClass) {
|
|
|
|
+ super(descriptor, camelCaseName, messageClass, builderClass);
|
|
|
|
+
|
|
|
|
+ newBuilderMethod = getMethodOrDie(type, "newBuilder");
|
|
|
|
+ getBuilderMethodBuilder = getMethodOrDie(builderClass,
|
|
|
|
+ "get" + camelCaseName + "Builder", Integer.TYPE);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private final Method newBuilderMethod;
|
|
|
|
+ private final Method getBuilderMethodBuilder;
|
|
|
|
+
|
|
|
|
+ private Object coerceType(final Object value) {
|
|
|
|
+ if (type.isInstance(value)) {
|
|
|
|
+ return value;
|
|
|
|
+ } else {
|
|
|
|
+ // The value is not the exact right message type. However, if it
|
|
|
|
+ // is an alternative implementation of the same type -- e.g. a
|
|
|
|
+ // DynamicMessage -- we should accept it. In this case we can make
|
|
|
|
+ // a copy of the message.
|
|
|
|
+ return ((Message.Builder) invokeOrDie(newBuilderMethod, null))
|
|
|
|
+ .mergeFrom((Message) value).build();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void setRepeated(final Builder builder,
|
|
|
|
+ final int index, final Object value) {
|
|
|
|
+ super.setRepeated(builder, index, coerceType(value));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public void addRepeated(final Builder builder, final Object value) {
|
|
|
|
+ super.addRepeated(builder, coerceType(value));
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder newBuilder() {
|
|
|
|
+ return (Message.Builder) invokeOrDie(newBuilderMethod, null);
|
|
|
|
+ }
|
|
|
|
+ @Override
|
|
|
|
+ public Message.Builder getRepeatedBuilder(
|
|
|
|
+ final GeneratedMessageV3.Builder builder, final int index) {
|
|
|
|
+ return (Message.Builder) invokeOrDie(
|
|
|
|
+ getBuilderMethodBuilder, builder, index);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Replaces this object in the output stream with a serialized form.
|
|
|
|
+ * Part of Java's serialization magic. Generated sub-classes must override
|
|
|
|
+ * this method by calling {@code return super.writeReplace();}
|
|
|
|
+ * @return a SerializedForm of this message
|
|
|
|
+ */
|
|
|
|
+ protected Object writeReplace() throws ObjectStreamException {
|
|
|
|
+ return new GeneratedMessageLite.SerializedForm(this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Checks that the {@link Extension} is non-Lite and returns it as a
|
|
|
|
+ * {@link GeneratedExtension}.
|
|
|
|
+ */
|
|
|
|
+ private static <MessageType extends ExtendableMessage<MessageType>, T>
|
|
|
|
+ Extension<MessageType, T> checkNotLite(
|
|
|
|
+ ExtensionLite<MessageType, T> extension) {
|
|
|
|
+ if (extension.isLite()) {
|
|
|
|
+ throw new IllegalArgumentException("Expected non-lite extension.");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (Extension<MessageType, T>) extension;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static int computeStringSize(final int fieldNumber, final Object value) {
|
|
|
|
+ if (value instanceof String) {
|
|
|
|
+ return CodedOutputStream.computeStringSize(fieldNumber, (String) value);
|
|
|
|
+ } else {
|
|
|
|
+ return CodedOutputStream.computeBytesSize(fieldNumber, (ByteString) value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static int computeStringSizeNoTag(final Object value) {
|
|
|
|
+ if (value instanceof String) {
|
|
|
|
+ return CodedOutputStream.computeStringSizeNoTag((String) value);
|
|
|
|
+ } else {
|
|
|
|
+ return CodedOutputStream.computeBytesSizeNoTag((ByteString) value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static void writeString(
|
|
|
|
+ CodedOutputStream output, final int fieldNumber, final Object value) throws IOException {
|
|
|
|
+ if (value instanceof String) {
|
|
|
|
+ output.writeString(fieldNumber, (String) value);
|
|
|
|
+ } else {
|
|
|
|
+ output.writeBytes(fieldNumber, (ByteString) value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ protected static void writeStringNoTag(
|
|
|
|
+ CodedOutputStream output, final Object value) throws IOException {
|
|
|
|
+ if (value instanceof String) {
|
|
|
|
+ output.writeStringNoTag((String) value);
|
|
|
|
+ } else {
|
|
|
|
+ output.writeBytesNoTag((ByteString) value);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|