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