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 #include <google/protobuf/compiler/java/java_map_field.h>
32 
33 #include <google/protobuf/compiler/java/java_context.h>
34 #include <google/protobuf/compiler/java/java_doc_comment.h>
35 #include <google/protobuf/compiler/java/java_helpers.h>
36 #include <google/protobuf/compiler/java/java_name_resolver.h>
37 #include <google/protobuf/io/printer.h>
38 
39 namespace google {
40 namespace protobuf {
41 namespace compiler {
42 namespace java {
43 
44 namespace {
45 
KeyField(const FieldDescriptor * descriptor)46 const FieldDescriptor* KeyField(const FieldDescriptor* descriptor) {
47   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
48   const Descriptor* message = descriptor->message_type();
49   GOOGLE_CHECK(message->options().map_entry());
50   return message->FindFieldByName("key");
51 }
52 
ValueField(const FieldDescriptor * descriptor)53 const FieldDescriptor* ValueField(const FieldDescriptor* descriptor) {
54   GOOGLE_CHECK_EQ(FieldDescriptor::TYPE_MESSAGE, descriptor->type());
55   const Descriptor* message = descriptor->message_type();
56   GOOGLE_CHECK(message->options().map_entry());
57   return message->FindFieldByName("value");
58 }
59 
TypeName(const FieldDescriptor * field,ClassNameResolver * name_resolver,bool boxed)60 string TypeName(const FieldDescriptor* field,
61                 ClassNameResolver* name_resolver,
62                 bool boxed) {
63   if (GetJavaType(field) == JAVATYPE_MESSAGE) {
64     return name_resolver->GetImmutableClassName(field->message_type());
65   } else if (GetJavaType(field) == JAVATYPE_ENUM) {
66     return name_resolver->GetImmutableClassName(field->enum_type());
67   } else {
68     return boxed ? BoxedPrimitiveTypeName(GetJavaType(field))
69                  : PrimitiveTypeName(GetJavaType(field));
70   }
71 }
72 
WireType(const FieldDescriptor * field)73 string WireType(const FieldDescriptor* field) {
74   return "com.google.protobuf.WireFormat.FieldType." +
75       string(FieldTypeName(field->type()));
76 }
77 
SetMessageVariables(const FieldDescriptor * descriptor,int messageBitIndex,int builderBitIndex,const FieldGeneratorInfo * info,Context * context,map<string,string> * variables)78 void SetMessageVariables(const FieldDescriptor* descriptor,
79                          int messageBitIndex,
80                          int builderBitIndex,
81                          const FieldGeneratorInfo* info,
82                          Context* context,
83                          map<string, string>* variables) {
84   SetCommonFieldVariables(descriptor, info, variables);
85   ClassNameResolver* name_resolver = context->GetNameResolver();
86 
87   (*variables)["type"] =
88       name_resolver->GetImmutableClassName(descriptor->message_type());
89   const FieldDescriptor* key = KeyField(descriptor);
90   const FieldDescriptor* value = ValueField(descriptor);
91   const JavaType keyJavaType = GetJavaType(key);
92   const JavaType valueJavaType = GetJavaType(value);
93 
94   (*variables)["key_type"] = TypeName(key, name_resolver, false);
95   (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
96   (*variables)["key_wire_type"] = WireType(key);
97   (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
98   (*variables)["key_null_check"] = IsReferenceType(keyJavaType) ?
99       "if (key == null) { throw new java.lang.NullPointerException(); }" : "";
100   (*variables)["value_null_check"] = IsReferenceType(valueJavaType) ?
101       "if (value == null) { throw new java.lang.NullPointerException(); }" : "";
102   if (valueJavaType == JAVATYPE_ENUM) {
103     // We store enums as Integers internally.
104     (*variables)["value_type"] = "int";
105     (*variables)["boxed_value_type"] = "java.lang.Integer";
106     (*variables)["value_wire_type"] = WireType(value);
107     (*variables)["value_default_value"] =
108         DefaultValue(value, true, name_resolver) + ".getNumber()";
109 
110     (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
111 
112     if (SupportUnknownEnumValue(descriptor->file())) {
113       // Map unknown values to a special UNRECOGNIZED value if supported.
114       (*variables)["unrecognized_value"] =
115           (*variables)["value_enum_type"] + ".UNRECOGNIZED";
116     } else {
117       // Map unknown values to the default value if we don't have UNRECOGNIZED.
118       (*variables)["unrecognized_value"] =
119           DefaultValue(value, true, name_resolver);
120     }
121   } else {
122     (*variables)["value_type"] = TypeName(value, name_resolver, false);
123     (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
124     (*variables)["value_wire_type"] = WireType(value);
125     (*variables)["value_default_value"] =
126         DefaultValue(value, true, name_resolver);
127   }
128   (*variables)["type_parameters"] =
129       (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
130   // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
131   // by the proto compiler
132   (*variables)["deprecation"] = descriptor->options().deprecated()
133       ? "@java.lang.Deprecated " : "";
134   (*variables)["on_changed"] = "onChanged();";
135 
136   // For repeated fields, one bit is used for whether the array is immutable
137   // in the parsing constructor.
138   (*variables)["get_mutable_bit_parser"] =
139       GenerateGetBitMutableLocal(builderBitIndex);
140   (*variables)["set_mutable_bit_parser"] =
141       GenerateSetBitMutableLocal(builderBitIndex);
142 
143   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
144       "DefaultEntryHolder.defaultEntry";
145   (*variables)["map_field_parameter"] = (*variables)["default_entry"];
146   (*variables)["descriptor"] =
147       name_resolver->GetImmutableClassName(descriptor->file()) +
148       ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
149       "_descriptor, ";
150 }
151 
152 }  // namespace
153 
154 ImmutableMapFieldGenerator::
ImmutableMapFieldGenerator(const FieldDescriptor * descriptor,int messageBitIndex,int builderBitIndex,Context * context)155 ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
156                                        int messageBitIndex,
157                                        int builderBitIndex,
158                                        Context* context)
159   : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
160   SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
161                       context->GetFieldGeneratorInfo(descriptor),
162                       context, &variables_);
163 }
164 
165 ImmutableMapFieldGenerator::
~ImmutableMapFieldGenerator()166 ~ImmutableMapFieldGenerator() {}
167 
GetNumBitsForMessage() const168 int ImmutableMapFieldGenerator::GetNumBitsForMessage() const {
169   return 0;
170 }
171 
GetNumBitsForBuilder() const172 int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
173   return 1;
174 }
175 
176 void ImmutableMapFieldGenerator::
GenerateInterfaceMembers(io::Printer * printer) const177 GenerateInterfaceMembers(io::Printer* printer) const {
178   WriteFieldDocComment(printer, descriptor_);
179   printer->Print(
180       variables_,
181       "$deprecation$int get$capitalized_name$Count();\n");
182   WriteFieldDocComment(printer, descriptor_);
183   printer->Print(
184       variables_,
185       "$deprecation$boolean contains$capitalized_name$(\n"
186       "    $key_type$ key);\n");
187   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
188     printer->Print(
189         variables_,
190         "/**\n"
191         " * Use {@link #get$capitalized_name$Map()} instead.\n"
192         " */\n"
193         "@java.lang.Deprecated\n"
194         "java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
195         "get$capitalized_name$();\n");
196     WriteFieldDocComment(printer, descriptor_);
197     printer->Print(
198         variables_,
199         "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
200         "get$capitalized_name$Map();\n");
201     WriteFieldDocComment(printer, descriptor_);
202     printer->Print(
203         variables_,
204         "$deprecation$$value_enum_type$ get$capitalized_name$OrDefault(\n"
205         "    $key_type$ key,\n"
206         "    $value_enum_type$ defaultValue);\n");
207     WriteFieldDocComment(printer, descriptor_);
208     printer->Print(
209         variables_,
210         "$deprecation$$value_enum_type$ get$capitalized_name$OrThrow(\n"
211         "    $key_type$ key);\n");
212     if (SupportUnknownEnumValue(descriptor_->file())) {
213       printer->Print(
214           variables_,
215           "/**\n"
216           " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
217           " */\n"
218           "@java.lang.Deprecated\n"
219           "java.util.Map<$type_parameters$>\n"
220           "get$capitalized_name$Value();\n");
221       WriteFieldDocComment(printer, descriptor_);
222       printer->Print(
223           variables_,
224           "$deprecation$java.util.Map<$type_parameters$>\n"
225           "get$capitalized_name$ValueMap();\n");
226       WriteFieldDocComment(printer, descriptor_);
227       printer->Print(
228           variables_,
229           "$deprecation$\n"
230           "$value_type$ get$capitalized_name$ValueOrDefault(\n"
231           "    $key_type$ key,\n"
232           "    $value_type$ defaultValue);\n");
233       WriteFieldDocComment(printer, descriptor_);
234       printer->Print(
235           variables_,
236           "$deprecation$\n"
237           "$value_type$ get$capitalized_name$ValueOrThrow(\n"
238           "    $key_type$ key);\n");
239     }
240   } else {
241     printer->Print(
242         variables_,
243         "/**\n"
244         " * Use {@link #get$capitalized_name$Map()} instead.\n"
245         " */\n"
246         "@java.lang.Deprecated\n"
247         "java.util.Map<$type_parameters$>\n"
248         "get$capitalized_name$();\n");
249     WriteFieldDocComment(printer, descriptor_);
250     printer->Print(
251         variables_,
252         "$deprecation$java.util.Map<$type_parameters$>\n"
253         "get$capitalized_name$Map();\n");
254     WriteFieldDocComment(printer, descriptor_);
255     printer->Print(
256         variables_,
257         "$deprecation$\n"
258         "$value_type$ get$capitalized_name$OrDefault(\n"
259         "    $key_type$ key,\n"
260         "    $value_type$ defaultValue);\n");
261     WriteFieldDocComment(printer, descriptor_);
262     printer->Print(
263         variables_,
264         "$deprecation$\n"
265         "$value_type$ get$capitalized_name$OrThrow(\n"
266         "    $key_type$ key);\n");
267   }
268 }
269 
270 void ImmutableMapFieldGenerator::
GenerateMembers(io::Printer * printer) const271 GenerateMembers(io::Printer* printer) const {
272   printer->Print(
273       variables_,
274       "private static final class $capitalized_name$DefaultEntryHolder {\n"
275       "  static final com.google.protobuf.MapEntry<\n"
276       "      $type_parameters$> defaultEntry =\n"
277       "          com.google.protobuf.MapEntry\n"
278       "          .<$type_parameters$>newDefaultInstance(\n"
279       "              $descriptor$\n"
280       "              $key_wire_type$,\n"
281       "              $key_default_value$,\n"
282       "              $value_wire_type$,\n"
283       "              $value_default_value$);\n"
284       "}\n");
285   printer->Print(
286       variables_,
287       "private com.google.protobuf.MapField<\n"
288       "    $type_parameters$> $name$_;\n"
289       "private com.google.protobuf.MapField<$type_parameters$>\n"
290       "internalGet$capitalized_name$() {\n"
291       "  if ($name$_ == null) {\n"
292       "    return com.google.protobuf.MapField.emptyMapField(\n"
293       "        $map_field_parameter$);\n"
294       "  }\n"
295       "  return $name$_;\n"
296       "}\n");
297   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
298     printer->Print(
299         variables_,
300         "private static final\n"
301         "com.google.protobuf.Internal.MapAdapter.Converter<\n"
302         "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
303         "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
304         "            $value_enum_type$.internalGetValueMap(),\n"
305         "            $unrecognized_value$);\n");
306   }
307   GenerateMapGetters(printer);
308 }
309 
310 void ImmutableMapFieldGenerator::
GenerateBuilderMembers(io::Printer * printer) const311 GenerateBuilderMembers(io::Printer* printer) const {
312   printer->Print(
313       variables_,
314       "private com.google.protobuf.MapField<\n"
315       "    $type_parameters$> $name$_;\n"
316       "private com.google.protobuf.MapField<$type_parameters$>\n"
317       "internalGet$capitalized_name$() {\n"
318       "  if ($name$_ == null) {\n"
319       "    return com.google.protobuf.MapField.emptyMapField(\n"
320       "        $map_field_parameter$);\n"
321       "  }\n"
322       "  return $name$_;\n"
323       "}\n"
324       "private com.google.protobuf.MapField<$type_parameters$>\n"
325       "internalGetMutable$capitalized_name$() {\n"
326       "  $on_changed$;\n"
327       "  if ($name$_ == null) {\n"
328       "    $name$_ = com.google.protobuf.MapField.newMapField(\n"
329       "        $map_field_parameter$);\n"
330       "  }\n"
331       "  if (!$name$_.isMutable()) {\n"
332       "    $name$_ = $name$_.copy();\n"
333       "  }\n"
334       "  return $name$_;\n"
335       "}\n");
336   GenerateMapGetters(printer);
337   printer->Print(
338       variables_,
339       "$deprecation$\n"
340       "public Builder clear$capitalized_name$() {\n"
341       "  getMutable$capitalized_name$().clear();\n"
342       "  return this;\n"
343       "}\n");
344   WriteFieldDocComment(printer, descriptor_);
345   printer->Print(
346       variables_,
347       "$deprecation$\n"
348       "public Builder remove$capitalized_name$(\n"
349       "    $key_type$ key) {\n"
350       "  $key_null_check$\n"
351       "  getMutable$capitalized_name$().remove(key);\n"
352       "  return this;\n"
353       "}\n");
354   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
355     printer->Print(
356         variables_,
357         "/**\n"
358         " * Use alternate mutation accessors instead.\n"
359         " */\n"
360         "@java.lang.Deprecated\n"
361         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
362         "getMutable$capitalized_name$() {\n"
363         "  return new com.google.protobuf.Internal.MapAdapter<\n"
364         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
365         "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
366         "          $name$ValueConverter);\n"
367         "}\n");
368     WriteFieldDocComment(printer, descriptor_);
369     printer->Print(
370         variables_,
371         "$deprecation$public Builder put$capitalized_name$(\n"
372         "    $key_type$ key,\n"
373         "    $value_enum_type$ value) {\n"
374         "  $key_null_check$\n"
375         "  $value_null_check$\n"
376         "  getMutable$capitalized_name$().put(key, value);\n"
377         "  return this;\n"
378         "}\n");
379     WriteFieldDocComment(printer, descriptor_);
380     printer->Print(
381         variables_,
382         // TODO(arielb): null check map keys/values here and everywhere else
383         // related to putAll
384         "$deprecation$public Builder putAll$capitalized_name$(\n"
385         "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
386         "  getMutable$capitalized_name$().putAll(values);\n"
387         "  return this;\n"
388         "}\n");
389     if (SupportUnknownEnumValue(descriptor_->file())) {
390       printer->Print(
391           variables_,
392           "/**\n"
393           " * Use alternate mutation accessors instead.\n"
394           " */\n"
395           "@java.lang.Deprecated\n"
396           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
397           "getMutable$capitalized_name$Value() {\n"
398           "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
399           "}\n");
400       WriteFieldDocComment(printer, descriptor_);
401       printer->Print(
402           variables_,
403           "$deprecation$public Builder put$capitalized_name$Value(\n"
404           "    $key_type$ key,\n"
405           "    $value_type$ value) {\n"
406           "  $key_null_check$\n"
407           "  if ($value_enum_type$.forNumber(value) == null) {\n"
408           "    throw new java.lang.IllegalArgumentException();\n"
409           "  }\n"
410           "  getMutable$capitalized_name$Value().put(key, value);\n"
411           "  return this;\n"
412           "}\n");
413       WriteFieldDocComment(printer, descriptor_);
414       printer->Print(
415           variables_,
416           "$deprecation$public Builder putAll$capitalized_name$Value(\n"
417           "    java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
418           "  getMutable$capitalized_name$Value().putAll(values);\n"
419           "  return this;\n"
420           "}\n");
421     }
422   } else {
423     printer->Print(
424         variables_,
425         "/**\n"
426         " * Use alternate mutation accessors instead.\n"
427         " */\n"
428         "@java.lang.Deprecated\n"
429         "public java.util.Map<$type_parameters$>\n"
430         "getMutable$capitalized_name$() {\n"
431         "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
432         "}\n");
433     WriteFieldDocComment(printer, descriptor_);
434     printer->Print(
435         variables_,
436         "$deprecation$"
437         "public Builder put$capitalized_name$(\n"
438         "    $key_type$ key,\n"
439         "    $value_type$ value) {\n"
440         "  $key_null_check$\n"
441         "  $value_null_check$\n"
442         "  getMutable$capitalized_name$().put(key, value);\n"
443         "  return this;\n"
444         "}\n");
445     WriteFieldDocComment(printer, descriptor_);
446     printer->Print(
447         variables_,
448         "$deprecation$\n"
449         "public Builder putAll$capitalized_name$(\n"
450         "    java.util.Map<$type_parameters$> values) {\n"
451         "  getMutable$capitalized_name$().putAll(values);\n"
452         "  return this;\n"
453         "}\n");
454   }
455 }
456 
457 void ImmutableMapFieldGenerator::
GenerateMapGetters(io::Printer * printer) const458 GenerateMapGetters(io::Printer* printer) const {
459   printer->Print(
460       variables_,
461       "$deprecation$\n"
462       "public int get$capitalized_name$Count() {\n"
463       "  return internalGet$capitalized_name$().getMap().size();\n"
464       "}\n");
465   WriteFieldDocComment(printer, descriptor_);
466   printer->Print(
467       variables_,
468       "$deprecation$\n"
469       "public boolean contains$capitalized_name$(\n"
470       "    $key_type$ key) {\n"
471       "  $key_null_check$\n"
472       "  return internalGet$capitalized_name$().getMap().containsKey(key);\n"
473       "}\n");
474   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
475     printer->Print(
476         variables_,
477         "/**\n"
478         " * Use {@link #get$capitalized_name$Map()} instead.\n"
479         " */\n"
480         "@java.lang.Deprecated\n"
481         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
482         "get$capitalized_name$() {\n"
483         "  return get$capitalized_name$Map();\n"
484         "}\n");
485     WriteFieldDocComment(printer, descriptor_);
486     printer->Print(
487         variables_,
488         "$deprecation$\n"
489         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
490         "get$capitalized_name$Map() {\n"
491         "  return new com.google.protobuf.Internal.MapAdapter<\n"
492         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
493         "          internalGet$capitalized_name$().getMap(),\n"
494         "          $name$ValueConverter);\n"
495         "}\n");
496     WriteFieldDocComment(printer, descriptor_);
497     printer->Print(
498         variables_,
499         "$deprecation$\n"
500         "public $value_enum_type$ get$capitalized_name$OrDefault(\n"
501         "    $key_type$ key,\n"
502         "    $value_enum_type$ defaultValue) {\n"
503         "  $key_null_check$\n"
504         "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
505         "      internalGet$capitalized_name$().getMap();\n"
506         "  return map.containsKey(key)\n"
507         "         ? $name$ValueConverter.doForward(map.get(key))\n"
508         "         : defaultValue;\n"
509         "}\n");
510     WriteFieldDocComment(printer, descriptor_);
511     printer->Print(
512         variables_,
513         "$deprecation$\n"
514         "public $value_enum_type$ get$capitalized_name$OrThrow(\n"
515         "    $key_type$ key) {\n"
516         "  $key_null_check$\n"
517         "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
518         "      internalGet$capitalized_name$().getMap();\n"
519         "  if (!map.containsKey(key)) {\n"
520         "    throw new java.lang.IllegalArgumentException();\n"
521         "  }\n"
522         "  return $name$ValueConverter.doForward(map.get(key));\n"
523         "}\n");
524     if (SupportUnknownEnumValue(descriptor_->file())) {
525       printer->Print(
526           variables_,
527           "/**\n"
528           " * Use {@link #get$capitalized_name$ValueMap()} instead.\n"
529           " */\n"
530           "@java.lang.Deprecated\n"
531           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
532           "get$capitalized_name$Value() {\n"
533           "  return get$capitalized_name$ValueMap();\n"
534           "}\n");
535       WriteFieldDocComment(printer, descriptor_);
536       printer->Print(
537           variables_,
538           "$deprecation$\n"
539           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
540           "get$capitalized_name$ValueMap() {\n"
541           "  return internalGet$capitalized_name$().getMap();\n"
542           "}\n");
543       WriteFieldDocComment(printer, descriptor_);
544       printer->Print(
545           variables_,
546           "$deprecation$\n"
547           "public $value_type$ get$capitalized_name$ValueOrDefault(\n"
548           "    $key_type$ key,\n"
549           "    $value_type$ defaultValue) {\n"
550           "  $key_null_check$\n"
551           "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
552           "      internalGet$capitalized_name$().getMap();\n"
553           "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
554           "}\n");
555       WriteFieldDocComment(printer, descriptor_);
556       printer->Print(
557           variables_,
558           "$deprecation$\n"
559           "public $value_type$ get$capitalized_name$ValueOrThrow(\n"
560           "    $key_type$ key) {\n"
561           "  $key_null_check$\n"
562           "  java.util.Map<$boxed_key_type$, $boxed_value_type$> map =\n"
563           "      internalGet$capitalized_name$().getMap();\n"
564           "  if (!map.containsKey(key)) {\n"
565           "    throw new java.lang.IllegalArgumentException();\n"
566           "  }\n"
567           "  return map.get(key);\n"
568           "}\n");
569     }
570   } else {
571     printer->Print(
572         variables_,
573         "/**\n"
574         " * Use {@link #get$capitalized_name$Map()} instead.\n"
575         " */\n"
576         "@java.lang.Deprecated\n"
577         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
578         "  return get$capitalized_name$Map();\n"
579         "}\n");
580     WriteFieldDocComment(printer, descriptor_);
581     printer->Print(
582         variables_,
583         "$deprecation$\n"
584         "public java.util.Map<$type_parameters$> get$capitalized_name$Map() {\n"
585         "  return internalGet$capitalized_name$().getMap();\n"
586         "}\n");
587     WriteFieldDocComment(printer, descriptor_);
588     printer->Print(
589         variables_,
590         "$deprecation$\n"
591         "public $value_type$ get$capitalized_name$OrDefault(\n"
592         "    $key_type$ key,\n"
593         "    $value_type$ defaultValue) {\n"
594         "  $key_null_check$\n"
595         "  java.util.Map<$type_parameters$> map =\n"
596         "      internalGet$capitalized_name$().getMap();\n"
597         "  return map.containsKey(key) ? map.get(key) : defaultValue;\n"
598         "}\n");
599     WriteFieldDocComment(printer, descriptor_);
600     printer->Print(
601         variables_,
602         "$deprecation$\n"
603         "public $value_type$ get$capitalized_name$OrThrow(\n"
604         "    $key_type$ key) {\n"
605         "  $key_null_check$\n"
606         "  java.util.Map<$type_parameters$> map =\n"
607         "      internalGet$capitalized_name$().getMap();\n"
608         "  if (!map.containsKey(key)) {\n"
609         "    throw new java.lang.IllegalArgumentException();\n"
610         "  }\n"
611         "  return map.get(key);\n"
612         "}\n");
613   }
614 }
615 
616 void ImmutableMapFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer * printer) const617 GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
618   // Nothing to initialize.
619 }
620 
621 void ImmutableMapFieldGenerator::
GenerateInitializationCode(io::Printer * printer) const622 GenerateInitializationCode(io::Printer* printer) const {
623   // Nothing to initialize.
624 }
625 
626 void ImmutableMapFieldGenerator::
GenerateBuilderClearCode(io::Printer * printer) const627 GenerateBuilderClearCode(io::Printer* printer) const {
628   printer->Print(
629       variables_,
630       "internalGetMutable$capitalized_name$().clear();\n");
631 }
632 
633 void ImmutableMapFieldGenerator::
GenerateMergingCode(io::Printer * printer) const634 GenerateMergingCode(io::Printer* printer) const {
635   printer->Print(
636       variables_,
637       "internalGetMutable$capitalized_name$().mergeFrom(\n"
638       "    other.internalGet$capitalized_name$());\n");
639 }
640 
641 void ImmutableMapFieldGenerator::
GenerateBuildingCode(io::Printer * printer) const642 GenerateBuildingCode(io::Printer* printer) const {
643   printer->Print(
644       variables_,
645       "result.$name$_ = internalGet$capitalized_name$();\n"
646       "result.$name$_.makeImmutable();\n");
647 }
648 
649 void ImmutableMapFieldGenerator::
GenerateParsingCode(io::Printer * printer) const650 GenerateParsingCode(io::Printer* printer) const {
651   printer->Print(
652       variables_,
653       "if (!$get_mutable_bit_parser$) {\n"
654       "  $name$_ = com.google.protobuf.MapField.newMapField(\n"
655       "      $map_field_parameter$);\n"
656       "  $set_mutable_bit_parser$;\n"
657       "}\n");
658   if (!SupportUnknownEnumValue(descriptor_->file()) &&
659       GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
660     printer->Print(
661         variables_,
662         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
663         "com.google.protobuf.MapEntry<$type_parameters$>\n"
664         "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
665     printer->Print(
666         variables_,
667         "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
668         "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
669         "} else {\n"
670         "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
671         "}\n");
672   } else {
673     printer->Print(
674         variables_,
675         "com.google.protobuf.MapEntry<$type_parameters$>\n"
676         "$name$ = input.readMessage(\n"
677         "    $default_entry$.getParserForType(), extensionRegistry);\n"
678         "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
679   }
680 }
681 
682 void ImmutableMapFieldGenerator::
GenerateParsingDoneCode(io::Printer * printer) const683 GenerateParsingDoneCode(io::Printer* printer) const {
684   // Nothing to do here.
685 }
686 
687 void ImmutableMapFieldGenerator::
GenerateSerializationCode(io::Printer * printer) const688 GenerateSerializationCode(io::Printer* printer) const {
689   printer->Print(
690       variables_,
691       "for (java.util.Map.Entry<$type_parameters$> entry\n"
692       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
693       "  com.google.protobuf.MapEntry<$type_parameters$>\n"
694       "  $name$ = $default_entry$.newBuilderForType()\n"
695       "      .setKey(entry.getKey())\n"
696       "      .setValue(entry.getValue())\n"
697       "      .build();\n"
698       "  output.writeMessage($number$, $name$);\n"
699       "}\n");
700 }
701 
702 void ImmutableMapFieldGenerator::
GenerateSerializedSizeCode(io::Printer * printer) const703 GenerateSerializedSizeCode(io::Printer* printer) const {
704   printer->Print(
705       variables_,
706       "for (java.util.Map.Entry<$type_parameters$> entry\n"
707       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
708       "  com.google.protobuf.MapEntry<$type_parameters$>\n"
709       "  $name$ = $default_entry$.newBuilderForType()\n"
710       "      .setKey(entry.getKey())\n"
711       "      .setValue(entry.getValue())\n"
712       "      .build();\n"
713       "  size += com.google.protobuf.CodedOutputStream\n"
714       "      .computeMessageSize($number$, $name$);\n"
715       "}\n");
716 }
717 
718 void ImmutableMapFieldGenerator::
GenerateEqualsCode(io::Printer * printer) const719 GenerateEqualsCode(io::Printer* printer) const {
720   printer->Print(
721       variables_,
722       "result = result && internalGet$capitalized_name$().equals(\n"
723       "    other.internalGet$capitalized_name$());\n");
724 }
725 
726 void ImmutableMapFieldGenerator::
GenerateHashCode(io::Printer * printer) const727 GenerateHashCode(io::Printer* printer) const {
728   printer->Print(
729       variables_,
730       "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
731       "  hash = (37 * hash) + $constant_name$;\n"
732       "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
733       "}\n");
734 }
735 
GetBoxedType() const736 string ImmutableMapFieldGenerator::GetBoxedType() const {
737   return name_resolver_->GetImmutableClassName(descriptor_->message_type());
738 }
739 
740 }  // namespace java
741 }  // namespace compiler
742 }  // namespace protobuf
743 }  // namespace google
744