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 com.google.protobuf.Descriptors.Descriptor; 34 import com.google.protobuf.Descriptors.EnumValueDescriptor; 35 import com.google.protobuf.Descriptors.FieldDescriptor; 36 37 import java.io.IOException; 38 import java.util.Collections; 39 import java.util.Map; 40 import java.util.TreeMap; 41 42 /** 43 * Implements MapEntry messages. 44 * 45 * In reflection API, map fields will be treated as repeated message fields and 46 * each map entry is accessed as a message. This MapEntry class is used to 47 * represent these map entry messages in reflection API. 48 * 49 * Protobuf internal. Users shouldn't use this class. 50 */ 51 public final class MapEntry<K, V> extends AbstractMessage { 52 53 private static final class Metadata<K, V> extends MapEntryLite.Metadata<K, V> { 54 55 public final Descriptor descriptor; 56 public final Parser<MapEntry<K, V>> parser; 57 Metadata( Descriptor descriptor, MapEntry<K, V> defaultInstance, WireFormat.FieldType keyType, WireFormat.FieldType valueType)58 public Metadata( 59 Descriptor descriptor, 60 MapEntry<K, V> defaultInstance, 61 WireFormat.FieldType keyType, 62 WireFormat.FieldType valueType) { 63 super(keyType, defaultInstance.key, valueType, defaultInstance.value); 64 this.descriptor = descriptor; 65 this.parser = new AbstractParser<MapEntry<K, V>>() { 66 67 @Override 68 public MapEntry<K, V> parsePartialFrom( 69 CodedInputStream input, ExtensionRegistryLite extensionRegistry) 70 throws InvalidProtocolBufferException { 71 return new MapEntry<K, V>(Metadata.this, input, extensionRegistry); 72 } 73 }; 74 } 75 } 76 77 private final K key; 78 private final V value; 79 private final Metadata<K, V> metadata; 80 81 /** Create a default MapEntry instance. */ MapEntry( Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)82 private MapEntry( 83 Descriptor descriptor, 84 WireFormat.FieldType keyType, K defaultKey, 85 WireFormat.FieldType valueType, V defaultValue) { 86 this.key = defaultKey; 87 this.value = defaultValue; 88 this.metadata = new Metadata<K, V>(descriptor, this, keyType, valueType); 89 } 90 91 /** Create a MapEntry with the provided key and value. */ MapEntry(Metadata metadata, K key, V value)92 private MapEntry(Metadata metadata, K key, V value) { 93 this.key = key; 94 this.value = value; 95 this.metadata = metadata; 96 } 97 98 /** Parsing constructor. */ MapEntry( Metadata<K, V> metadata, CodedInputStream input, ExtensionRegistryLite extensionRegistry)99 private MapEntry( 100 Metadata<K, V> metadata, 101 CodedInputStream input, 102 ExtensionRegistryLite extensionRegistry) 103 throws InvalidProtocolBufferException { 104 try { 105 this.metadata = metadata; 106 Map.Entry<K, V> entry = MapEntryLite.parseEntry(input, metadata, extensionRegistry); 107 this.key = entry.getKey(); 108 this.value = entry.getValue(); 109 } catch (InvalidProtocolBufferException e) { 110 throw e.setUnfinishedMessage(this); 111 } catch (IOException e) { 112 throw new InvalidProtocolBufferException(e.getMessage()).setUnfinishedMessage(this); 113 } 114 } 115 116 /** 117 * Create a default MapEntry instance. A default MapEntry instance should be 118 * created only once for each map entry message type. Generated code should 119 * store the created default instance and use it later to create new MapEntry 120 * messages of the same type. 121 */ newDefaultInstance( Descriptor descriptor, WireFormat.FieldType keyType, K defaultKey, WireFormat.FieldType valueType, V defaultValue)122 public static <K, V> MapEntry<K, V> newDefaultInstance( 123 Descriptor descriptor, 124 WireFormat.FieldType keyType, K defaultKey, 125 WireFormat.FieldType valueType, V defaultValue) { 126 return new MapEntry<K, V>( 127 descriptor, keyType, defaultKey, valueType, defaultValue); 128 } 129 getKey()130 public K getKey() { 131 return key; 132 } 133 getValue()134 public V getValue() { 135 return value; 136 } 137 138 private volatile int cachedSerializedSize = -1; 139 140 @Override getSerializedSize()141 public int getSerializedSize() { 142 if (cachedSerializedSize != -1) { 143 return cachedSerializedSize; 144 } 145 146 int size = MapEntryLite.computeSerializedSize(metadata, key, value); 147 cachedSerializedSize = size; 148 return size; 149 } 150 151 @Override writeTo(CodedOutputStream output)152 public void writeTo(CodedOutputStream output) throws IOException { 153 MapEntryLite.writeTo(output, metadata, key, value); 154 } 155 156 @Override isInitialized()157 public boolean isInitialized() { 158 return isInitialized(metadata, value); 159 } 160 161 @Override getParserForType()162 public Parser<MapEntry<K, V>> getParserForType() { 163 return metadata.parser; 164 } 165 166 @Override newBuilderForType()167 public Builder<K, V> newBuilderForType() { 168 return new Builder<K, V>(metadata); 169 } 170 171 @Override toBuilder()172 public Builder<K, V> toBuilder() { 173 return new Builder<K, V>(metadata, key, value); 174 } 175 176 @Override getDefaultInstanceForType()177 public MapEntry<K, V> getDefaultInstanceForType() { 178 return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue); 179 } 180 181 @Override getDescriptorForType()182 public Descriptor getDescriptorForType() { 183 return metadata.descriptor; 184 } 185 186 @Override getAllFields()187 public Map<FieldDescriptor, Object> getAllFields() { 188 TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>(); 189 for (final FieldDescriptor field : metadata.descriptor.getFields()) { 190 if (hasField(field)) { 191 result.put(field, getField(field)); 192 } 193 } 194 return Collections.unmodifiableMap(result); 195 } 196 checkFieldDescriptor(FieldDescriptor field)197 private void checkFieldDescriptor(FieldDescriptor field) { 198 if (field.getContainingType() != metadata.descriptor) { 199 throw new RuntimeException( 200 "Wrong FieldDescriptor \"" + field.getFullName() 201 + "\" used in message \"" + metadata.descriptor.getFullName()); 202 } 203 } 204 205 @Override hasField(FieldDescriptor field)206 public boolean hasField(FieldDescriptor field) { 207 checkFieldDescriptor(field);; 208 // A MapEntry always contains two fields. 209 return true; 210 } 211 212 @Override getField(FieldDescriptor field)213 public Object getField(FieldDescriptor field) { 214 checkFieldDescriptor(field); 215 Object result = field.getNumber() == 1 ? getKey() : getValue(); 216 // Convert enums to EnumValueDescriptor. 217 if (field.getType() == FieldDescriptor.Type.ENUM) { 218 result = field.getEnumType().findValueByNumberCreatingIfUnknown( 219 (java.lang.Integer) result); 220 } 221 return result; 222 } 223 224 @Override getRepeatedFieldCount(FieldDescriptor field)225 public int getRepeatedFieldCount(FieldDescriptor field) { 226 throw new RuntimeException( 227 "There is no repeated field in a map entry message."); 228 } 229 230 @Override getRepeatedField(FieldDescriptor field, int index)231 public Object getRepeatedField(FieldDescriptor field, int index) { 232 throw new RuntimeException( 233 "There is no repeated field in a map entry message."); 234 } 235 236 @Override getUnknownFields()237 public UnknownFieldSet getUnknownFields() { 238 return UnknownFieldSet.getDefaultInstance(); 239 } 240 241 /** 242 * Builder to create {@link MapEntry} messages. 243 */ 244 public static class Builder<K, V> 245 extends AbstractMessage.Builder<Builder<K, V>> { 246 private final Metadata<K, V> metadata; 247 private K key; 248 private V value; 249 Builder(Metadata<K, V> metadata)250 private Builder(Metadata<K, V> metadata) { 251 this(metadata, metadata.defaultKey, metadata.defaultValue); 252 } 253 Builder(Metadata<K, V> metadata, K key, V value)254 private Builder(Metadata<K, V> metadata, K key, V value) { 255 this.metadata = metadata; 256 this.key = key; 257 this.value = value; 258 } 259 getKey()260 public K getKey() { 261 return key; 262 } 263 getValue()264 public V getValue() { 265 return value; 266 } 267 setKey(K key)268 public Builder<K, V> setKey(K key) { 269 this.key = key; 270 return this; 271 } 272 clearKey()273 public Builder<K, V> clearKey() { 274 this.key = metadata.defaultKey; 275 return this; 276 } 277 setValue(V value)278 public Builder<K, V> setValue(V value) { 279 this.value = value; 280 return this; 281 } 282 clearValue()283 public Builder<K, V> clearValue() { 284 this.value = metadata.defaultValue; 285 return this; 286 } 287 288 @Override build()289 public MapEntry<K, V> build() { 290 MapEntry<K, V> result = buildPartial(); 291 if (!result.isInitialized()) { 292 throw newUninitializedMessageException(result); 293 } 294 return result; 295 } 296 297 @Override buildPartial()298 public MapEntry<K, V> buildPartial() { 299 return new MapEntry<K, V>(metadata, key, value); 300 } 301 302 @Override getDescriptorForType()303 public Descriptor getDescriptorForType() { 304 return metadata.descriptor; 305 } 306 checkFieldDescriptor(FieldDescriptor field)307 private void checkFieldDescriptor(FieldDescriptor field) { 308 if (field.getContainingType() != metadata.descriptor) { 309 throw new RuntimeException( 310 "Wrong FieldDescriptor \"" + field.getFullName() 311 + "\" used in message \"" + metadata.descriptor.getFullName()); 312 } 313 } 314 315 @Override newBuilderForField(FieldDescriptor field)316 public Message.Builder newBuilderForField(FieldDescriptor field) { 317 checkFieldDescriptor(field);; 318 // This method should be called for message fields and in a MapEntry 319 // message only the value field can possibly be a message field. 320 if (field.getNumber() != 2 321 || field.getJavaType() != FieldDescriptor.JavaType.MESSAGE) { 322 throw new RuntimeException( 323 "\"" + field.getFullName() + "\" is not a message value field."); 324 } 325 return ((Message) value).newBuilderForType(); 326 } 327 328 @SuppressWarnings("unchecked") 329 @Override setField(FieldDescriptor field, Object value)330 public Builder<K, V> setField(FieldDescriptor field, Object value) { 331 checkFieldDescriptor(field); 332 if (field.getNumber() == 1) { 333 setKey((K) value); 334 } else { 335 if (field.getType() == FieldDescriptor.Type.ENUM) { 336 value = ((EnumValueDescriptor) value).getNumber(); 337 } 338 setValue((V) value); 339 } 340 return this; 341 } 342 343 @Override clearField(FieldDescriptor field)344 public Builder<K, V> clearField(FieldDescriptor field) { 345 checkFieldDescriptor(field); 346 if (field.getNumber() == 1) { 347 clearKey(); 348 } else { 349 clearValue(); 350 } 351 return this; 352 } 353 354 @Override setRepeatedField(FieldDescriptor field, int index, Object value)355 public Builder<K, V> setRepeatedField(FieldDescriptor field, int index, 356 Object value) { 357 throw new RuntimeException( 358 "There is no repeated field in a map entry message."); 359 } 360 361 @Override addRepeatedField(FieldDescriptor field, Object value)362 public Builder<K, V> addRepeatedField(FieldDescriptor field, Object value) { 363 throw new RuntimeException( 364 "There is no repeated field in a map entry message."); 365 } 366 367 @Override setUnknownFields(UnknownFieldSet unknownFields)368 public Builder<K, V> setUnknownFields(UnknownFieldSet unknownFields) { 369 // Unknown fields are discarded for MapEntry message. 370 return this; 371 } 372 373 @Override getDefaultInstanceForType()374 public MapEntry<K, V> getDefaultInstanceForType() { 375 return new MapEntry<K, V>(metadata, metadata.defaultKey, metadata.defaultValue); 376 } 377 378 @Override isInitialized()379 public boolean isInitialized() { 380 return MapEntry.isInitialized(metadata, value); 381 } 382 383 @Override getAllFields()384 public Map<FieldDescriptor, Object> getAllFields() { 385 final TreeMap<FieldDescriptor, Object> result = new TreeMap<FieldDescriptor, Object>(); 386 for (final FieldDescriptor field : metadata.descriptor.getFields()) { 387 if (hasField(field)) { 388 result.put(field, getField(field)); 389 } 390 } 391 return Collections.unmodifiableMap(result); 392 } 393 394 @Override hasField(FieldDescriptor field)395 public boolean hasField(FieldDescriptor field) { 396 checkFieldDescriptor(field); 397 return true; 398 } 399 400 @Override getField(FieldDescriptor field)401 public Object getField(FieldDescriptor field) { 402 checkFieldDescriptor(field); 403 Object result = field.getNumber() == 1 ? getKey() : getValue(); 404 // Convert enums to EnumValueDescriptor. 405 if (field.getType() == FieldDescriptor.Type.ENUM) { 406 result = field.getEnumType().findValueByNumberCreatingIfUnknown((Integer) result); 407 } 408 return result; 409 } 410 411 @Override getRepeatedFieldCount(FieldDescriptor field)412 public int getRepeatedFieldCount(FieldDescriptor field) { 413 throw new RuntimeException( 414 "There is no repeated field in a map entry message."); 415 } 416 417 @Override getRepeatedField(FieldDescriptor field, int index)418 public Object getRepeatedField(FieldDescriptor field, int index) { 419 throw new RuntimeException( 420 "There is no repeated field in a map entry message."); 421 } 422 423 @Override getUnknownFields()424 public UnknownFieldSet getUnknownFields() { 425 return UnknownFieldSet.getDefaultInstance(); 426 } 427 428 @Override clone()429 public Builder<K, V> clone() { 430 return new Builder(metadata, key, value); 431 } 432 } 433 isInitialized(Metadata metadata, V value)434 private static <V> boolean isInitialized(Metadata metadata, V value) { 435 if (metadata.valueType.getJavaType() == WireFormat.JavaType.MESSAGE) { 436 return ((MessageLite) value).isInitialized(); 437 } 438 return true; 439 } 440 } 441