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