// 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.EnumValueDescriptor; import com.google.protobuf.Descriptors.FieldDescriptor; import java.io.IOException; import java.util.Collections; import java.util.Map; import java.util.TreeMap; /** * Implements MapEntry messages. * * In reflection API, map fields will be treated as repeated message fields and * each map entry is accessed as a message. This MapEntry class is used to * represent these map entry messages in reflection API. * * Protobuf internal. Users shouldn't use this class. */ public final class MapEntry extends AbstractMessage { private static class Metadata { public final Descriptor descriptor; public final MapEntry defaultInstance; public final AbstractParser> parser; public Metadata( final Descriptor descriptor, final MapEntry defaultInstance) { this.descriptor = descriptor; this.defaultInstance = defaultInstance; final Metadata thisMetadata = this; this.parser = new AbstractParser>() { private final Parser> dataParser = defaultInstance.data.getParserForType(); @Override public MapEntry parsePartialFrom( CodedInputStream input, ExtensionRegistryLite extensionRegistry) throws InvalidProtocolBufferException { MapEntryLite data = dataParser.parsePartialFrom(input, extensionRegistry); return new MapEntry(thisMetadata, data); } }; } } private final Metadata metadata; private final MapEntryLite data; /** Create a default MapEntry instance. */ private MapEntry(Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue) { this.data = MapEntryLite.newDefaultInstance( keyType, defaultKey, valueType, defaultValue); this.metadata = new Metadata(descriptor, this); } /** Create a new MapEntry message. */ private MapEntry(Metadata metadata, MapEntryLite data) { this.metadata = metadata; this.data = data; } /** * Create a default MapEntry instance. A default MapEntry instance should be * created only once for each map entry message type. Generated code should * store the created default instance and use it later to create new MapEntry * messages of the same type. */ public static MapEntry newDefaultInstance( Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue) { return new MapEntry( descriptor, keyType, defaultKey, valueType, defaultValue); } public K getKey() { return data.getKey(); } public V getValue() { return data.getValue(); } @Override public int getSerializedSize() { return data.getSerializedSize(); } @Override public void writeTo(CodedOutputStream output) throws IOException { data.writeTo(output); } @Override public boolean isInitialized() { return data.isInitialized(); } @Override public Parser> getParserForType() { return metadata.parser; } @Override public Builder newBuilderForType() { return new Builder(metadata); } @Override public Builder toBuilder() { return new Builder(metadata, data); } @Override public MapEntry getDefaultInstanceForType() { return metadata.defaultInstance; } @Override public Descriptor getDescriptorForType() { return metadata.descriptor; } @Override public Map getAllFields() { final TreeMap result = new TreeMap(); for (final FieldDescriptor field : metadata.descriptor.getFields()) { if (hasField(field)) { result.put(field, getField(field)); } } return Collections.unmodifiableMap(result); } private void checkFieldDescriptor(FieldDescriptor field) { if (field.getContainingType() != metadata.descriptor) { throw new RuntimeException( "Wrong FieldDescriptor \"" + field.getFullName() + "\" used in message \"" + metadata.descriptor.getFullName()); } } @Override public boolean hasField(FieldDescriptor field) { checkFieldDescriptor(field);; // A MapEntry always contains two fields. return true; } @Override public Object getField(FieldDescriptor field) { checkFieldDescriptor(field); Object result = field.getNumber() == 1 ? getKey() : getValue(); // Convert enums to EnumValueDescriptor. if (field.getType() == FieldDescriptor.Type.ENUM) { result = field.getEnumType().findValueByNumberCreatingIfUnknown( (java.lang.Integer) result); } return result; } @Override public int getRepeatedFieldCount(FieldDescriptor field) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public Object getRepeatedField(FieldDescriptor field, int index) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public UnknownFieldSet getUnknownFields() { return UnknownFieldSet.getDefaultInstance(); } /** * Builder to create {@link MapEntry} messages. */ public static class Builder extends AbstractMessage.Builder> { private final Metadata metadata; private MapEntryLite data; private MapEntryLite.Builder dataBuilder; private Builder(Metadata metadata) { this.metadata = metadata; this.data = metadata.defaultInstance.data; this.dataBuilder = null; } private Builder(Metadata metadata, MapEntryLite data) { this.metadata = metadata; this.data = data; this.dataBuilder = null; } public K getKey() { return dataBuilder == null ? data.getKey() : dataBuilder.getKey(); } public V getValue() { return dataBuilder == null ? data.getValue() : dataBuilder.getValue(); } private void ensureMutable() { if (dataBuilder == null) { dataBuilder = data.toBuilder(); } } public Builder setKey(K key) { ensureMutable(); dataBuilder.setKey(key); return this; } public Builder clearKey() { ensureMutable(); dataBuilder.clearKey(); return this; } public Builder setValue(V value) { ensureMutable(); dataBuilder.setValue(value); return this; } public Builder clearValue() { ensureMutable(); dataBuilder.clearValue(); return this; } @Override public MapEntry build() { MapEntry result = buildPartial(); if (!result.isInitialized()) { throw newUninitializedMessageException(result); } return result; } @Override public MapEntry buildPartial() { if (dataBuilder != null) { data = dataBuilder.buildPartial(); dataBuilder = null; } return new MapEntry(metadata, data); } @Override public Descriptor getDescriptorForType() { return metadata.descriptor; } private void checkFieldDescriptor(FieldDescriptor field) { if (field.getContainingType() != metadata.descriptor) { throw new RuntimeException( "Wrong FieldDescriptor \"" + field.getFullName() + "\" used in message \"" + metadata.descriptor.getFullName()); } } @Override public com.google.protobuf.Message.Builder newBuilderForField( FieldDescriptor field) { checkFieldDescriptor(field);; // This method should be called for message fields and in a MapEntry // message only the value field can possibly be a message field. if (field.getNumber() != 2 || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { throw new RuntimeException( "\"" + field.getFullName() + "\" is not a message value field."); } return ((Message) data.getValue()).newBuilderForType(); } @SuppressWarnings("unchecked") @Override public Builder setField(FieldDescriptor field, Object value) { checkFieldDescriptor(field); if (field.getNumber() == 1) { setKey((K) value); } else { if (field.getType() == FieldDescriptor.Type.ENUM) { value = ((EnumValueDescriptor) value).getNumber(); } setValue((V) value); } return this; } @Override public Builder clearField(FieldDescriptor field) { checkFieldDescriptor(field); if (field.getNumber() == 1) { clearKey(); } else { clearValue(); } return this; } @Override public Builder setRepeatedField(FieldDescriptor field, int index, Object value) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public Builder addRepeatedField(FieldDescriptor field, Object value) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public Builder setUnknownFields(UnknownFieldSet unknownFields) { // Unknown fields are discarded for MapEntry message. return this; } @Override public MapEntry getDefaultInstanceForType() { return metadata.defaultInstance; } @Override public boolean isInitialized() { if (dataBuilder != null) { return dataBuilder.isInitialized(); } else { return data.isInitialized(); } } @Override public Map getAllFields() { final TreeMap result = new TreeMap(); for (final FieldDescriptor field : metadata.descriptor.getFields()) { if (hasField(field)) { result.put(field, getField(field)); } } return Collections.unmodifiableMap(result); } @Override public boolean hasField(FieldDescriptor field) { checkFieldDescriptor(field); return true; } @Override public Object getField(FieldDescriptor field) { checkFieldDescriptor(field); Object result = field.getNumber() == 1 ? getKey() : getValue(); // Convert enums to EnumValueDescriptor. if (field.getType() == FieldDescriptor.Type.ENUM) { result = field.getEnumType().findValueByNumberCreatingIfUnknown( (java.lang.Integer) result); } return result; } @Override public int getRepeatedFieldCount(FieldDescriptor field) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public Object getRepeatedField(FieldDescriptor field, int index) { throw new RuntimeException( "There is no repeated field in a map entry message."); } @Override public UnknownFieldSet getUnknownFields() { return UnknownFieldSet.getDefaultInstance(); } @Override public Builder clone() { if (dataBuilder == null) { return new Builder(metadata, data); } else { return new Builder(metadata, dataBuilder.build()); } } } }