• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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