1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 4 // 5 // Redistribution and use in source and binary forms, with or without 6 // modification, are permitted provided that the following conditions are 7 // met: 8 // 9 // * Redistributions of source code must retain the above copyright 10 // notice, this list of conditions and the following disclaimer. 11 // * Redistributions in binary form must reproduce the above 12 // copyright notice, this list of conditions and the following disclaimer 13 // in the documentation and/or other materials provided with the 14 // distribution. 15 // * Neither the name of Google Inc. nor the names of its 16 // contributors may be used to endorse or promote products derived from 17 // this software without specific prior written permission. 18 // 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31 package com.google.protobuf; 32 33 import java.io.IOException; 34 35 /** 36 * Implements the lite version of map entry messages. 37 * 38 * This class serves as an utility class to help do serialization/parsing of 39 * map entries. It's used in generated code and also in the full version 40 * MapEntry message. 41 * 42 * Protobuf internal. Users shouldn't use. 43 */ 44 public class MapEntryLite<K, V> 45 extends AbstractMessageLite<MapEntryLite<K, V>, MapEntryLite.Builder<K, V>> { 46 private static class Metadata<K, V> { 47 public final MapEntryLite<K, V> defaultInstance; 48 public final WireFormat.FieldType keyType; 49 public final WireFormat.FieldType valueType; 50 public final Parser<MapEntryLite<K, V>> parser; Metadata( MapEntryLite<K, V> defaultInstance, WireFormat.FieldType keyType, WireFormat.FieldType valueType)51 public Metadata( 52 MapEntryLite<K, V> defaultInstance, 53 WireFormat.FieldType keyType, 54 WireFormat.FieldType valueType) { 55 this.defaultInstance = defaultInstance; 56 this.keyType = keyType; 57 this.valueType = valueType; 58 final Metadata<K, V> finalThis = this; 59 this.parser = new AbstractParser<MapEntryLite<K, V>>() { 60 @Override 61 public MapEntryLite<K, V> parsePartialFrom( 62 CodedInputStream input, ExtensionRegistryLite extensionRegistry) 63 throws InvalidProtocolBufferException { 64 return new MapEntryLite<K, V>(finalThis, input, extensionRegistry); 65 } 66 }; 67 } 68 } 69 70 private static final int KEY_FIELD_NUMBER = 1; 71 private static final int VALUE_FIELD_NUMBER = 2; 72 73 private final Metadata<K, V> metadata; 74 private final K key; 75 private final V value; 76 77 /** Creates a default MapEntryLite message instance. */ MapEntryLite( WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)78 private MapEntryLite( 79 WireFormat.FieldType keyType, K defaultKey, 80 WireFormat.FieldType valueType, V defaultValue) { 81 this.metadata = new Metadata<K, V>(this, keyType, valueType); 82 this.key = defaultKey; 83 this.value = defaultValue; 84 } 85 86 /** Creates a new MapEntryLite message. */ MapEntryLite(Metadata<K, V> metadata, K key, V value)87 private MapEntryLite(Metadata<K, V> metadata, K key, V value) { 88 this.metadata = metadata; 89 this.key = key; 90 this.value = value; 91 } 92 getKey()93 public K getKey() { 94 return key; 95 } 96 getValue()97 public V getValue() { 98 return value; 99 } 100 101 /** 102 * Creates a default MapEntryLite message instance. 103 * 104 * This method is used by generated code to create the default instance for 105 * a map entry message. The created default instance should be used to create 106 * new map entry messages of the same type. For each map entry message, only 107 * one default instance should be created. 108 */ newDefaultInstance( WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)109 public static <K, V> MapEntryLite<K, V> newDefaultInstance( 110 WireFormat.FieldType keyType, K defaultKey, 111 WireFormat.FieldType valueType, V defaultValue) { 112 return new MapEntryLite<K, V>( 113 keyType, defaultKey, valueType, defaultValue); 114 } 115 116 @Override writeTo(CodedOutputStream output)117 public void writeTo(CodedOutputStream output) throws IOException { 118 writeField(KEY_FIELD_NUMBER, metadata.keyType, key, output); 119 writeField(VALUE_FIELD_NUMBER, metadata.valueType, value, output); 120 } 121 writeField( int number, WireFormat.FieldType type, Object value, CodedOutputStream output)122 private void writeField( 123 int number, WireFormat.FieldType type, Object value, 124 CodedOutputStream output) throws IOException { 125 output.writeTag(number, type.getWireType()); 126 FieldSet.writeElementNoTag(output, type, value); 127 } 128 129 private volatile int cachedSerializedSize = -1; 130 @Override getSerializedSize()131 public int getSerializedSize() { 132 if (cachedSerializedSize != -1) { 133 return cachedSerializedSize; 134 } 135 int size = 0; 136 size += getFieldSize(KEY_FIELD_NUMBER, metadata.keyType, key); 137 size += getFieldSize(VALUE_FIELD_NUMBER, metadata.valueType, value); 138 cachedSerializedSize = size; 139 return size; 140 } 141 getFieldSize( int number, WireFormat.FieldType type, Object value)142 private int getFieldSize( 143 int number, WireFormat.FieldType type, Object value) { 144 return CodedOutputStream.computeTagSize(number) 145 + FieldSet.computeElementSizeNoTag(type, value); 146 } 147 148 /** Parsing constructor. */ MapEntryLite( Metadata<K, V> metadata, CodedInputStream input, ExtensionRegistryLite extensionRegistry)149 private MapEntryLite( 150 Metadata<K, V> metadata, 151 CodedInputStream input, 152 ExtensionRegistryLite extensionRegistry) 153 throws InvalidProtocolBufferException { 154 try { 155 K key = metadata.defaultInstance.key; 156 V value = metadata.defaultInstance.value; 157 while (true) { 158 int tag = input.readTag(); 159 if (tag == 0) { 160 break; 161 } 162 if (tag == WireFormat.makeTag( 163 KEY_FIELD_NUMBER, metadata.keyType.getWireType())) { 164 key = mergeField( 165 input, extensionRegistry, metadata.keyType, key); 166 } else if (tag == WireFormat.makeTag( 167 VALUE_FIELD_NUMBER, metadata.valueType.getWireType())) { 168 value = mergeField( 169 input, extensionRegistry, metadata.valueType, value); 170 } else { 171 if (!input.skipField(tag)) { 172 break; 173 } 174 } 175 } 176 this.metadata = metadata; 177 this.key = key; 178 this.value = value; 179 } catch (InvalidProtocolBufferException e) { 180 throw e.setUnfinishedMessage(this); 181 } catch (IOException e) { 182 throw new InvalidProtocolBufferException(e.getMessage()) 183 .setUnfinishedMessage(this); 184 } 185 } 186 187 @SuppressWarnings("unchecked") mergeField( CodedInputStream input, ExtensionRegistryLite extensionRegistry, WireFormat.FieldType type, T value)188 private <T> T mergeField( 189 CodedInputStream input, ExtensionRegistryLite extensionRegistry, 190 WireFormat.FieldType type, T value) throws IOException { 191 switch (type) { 192 case MESSAGE: 193 MessageLite.Builder subBuilder = ((MessageLite) value).toBuilder(); 194 input.readMessage(subBuilder, extensionRegistry); 195 return (T) subBuilder.buildPartial(); 196 case ENUM: 197 return (T) (java.lang.Integer) input.readEnum(); 198 case GROUP: 199 throw new RuntimeException("Groups are not allowed in maps."); 200 default: 201 return (T) FieldSet.readPrimitiveField(input, type, true); 202 } 203 } 204 205 @Override getParserForType()206 public Parser<MapEntryLite<K, V>> getParserForType() { 207 return metadata.parser; 208 } 209 210 @Override newBuilderForType()211 public Builder<K, V> newBuilderForType() { 212 return new Builder<K, V>(metadata); 213 } 214 215 @Override toBuilder()216 public Builder<K, V> toBuilder() { 217 return new Builder<K, V>(metadata, key, value); 218 } 219 220 @Override getDefaultInstanceForType()221 public MapEntryLite<K, V> getDefaultInstanceForType() { 222 return metadata.defaultInstance; 223 } 224 225 @Override isInitialized()226 public boolean isInitialized() { 227 if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { 228 return ((MessageLite) value).isInitialized(); 229 } 230 return true; 231 } 232 233 /** 234 * Builder used to create {@link MapEntryLite} messages. 235 */ 236 public static class Builder<K, V> 237 extends AbstractMessageLite.Builder<MapEntryLite<K, V>, Builder<K, V>> { 238 private final Metadata<K, V> metadata; 239 private K key; 240 private V value; 241 Builder(Metadata<K, V> metadata)242 private Builder(Metadata<K, V> metadata) { 243 this.metadata = metadata; 244 this.key = metadata.defaultInstance.key; 245 this.value = metadata.defaultInstance.value; 246 } 247 getKey()248 public K getKey() { 249 return key; 250 } 251 getValue()252 public V getValue() { 253 return value; 254 } 255 setKey(K key)256 public Builder<K, V> setKey(K key) { 257 this.key = key; 258 return this; 259 } 260 setValue(V value)261 public Builder<K, V> setValue(V value) { 262 this.value = value; 263 return this; 264 } 265 clearKey()266 public Builder<K, V> clearKey() { 267 this.key = metadata.defaultInstance.key; 268 return this; 269 } 270 clearValue()271 public Builder<K, V> clearValue() { 272 this.value = metadata.defaultInstance.value; 273 return this; 274 } 275 276 @Override clear()277 public Builder<K, V> clear() { 278 this.key = metadata.defaultInstance.key; 279 this.value = metadata.defaultInstance.value; 280 return this; 281 } 282 283 @Override build()284 public MapEntryLite<K, V> build() { 285 MapEntryLite<K, V> result = buildPartial(); 286 if (!result.isInitialized()) { 287 throw newUninitializedMessageException(result); 288 } 289 return result; 290 } 291 292 @Override buildPartial()293 public MapEntryLite<K, V> buildPartial() { 294 return new MapEntryLite<K, V>(metadata, key, value); 295 } 296 297 @Override getDefaultInstanceForType()298 public MessageLite getDefaultInstanceForType() { 299 return metadata.defaultInstance; 300 } 301 302 @Override isInitialized()303 public boolean isInitialized() { 304 if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { 305 return ((MessageLite) value).isInitialized(); 306 } 307 return true; 308 } 309 Builder(Metadata<K, V> metadata, K key, V value)310 private Builder(Metadata<K, V> metadata, K key, V value) { 311 this.metadata = metadata; 312 this.key = key; 313 this.value = value; 314 } 315 316 @Override clone()317 public Builder<K, V> clone() { 318 return new Builder<K, V>(metadata, key, value); 319 } 320 321 @Override mergeFrom( CodedInputStream input, ExtensionRegistryLite extensionRegistry)322 public Builder<K, V> mergeFrom( 323 CodedInputStream input, ExtensionRegistryLite extensionRegistry) 324 throws IOException { 325 MapEntryLite<K, V> entry = 326 new MapEntryLite<K, V>(metadata, input, extensionRegistry); 327 this.key = entry.key; 328 this.value = entry.value; 329 return this; 330 } 331 332 @Override internalMergeFrom(MapEntryLite<K, V> message)333 protected Builder<K, V> internalMergeFrom(MapEntryLite<K, V> message) { 334 throw new UnsupportedOperationException(); 335 } 336 } 337 } 338