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