• 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 #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   (*variables)["key_type"] = TypeName(key, name_resolver, false);
92   (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
93   (*variables)["key_wire_type"] = WireType(key);
94   (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
95   if (GetJavaType(value) == JAVATYPE_ENUM) {
96     // We store enums as Integers internally.
97     (*variables)["value_type"] = "int";
98     (*variables)["boxed_value_type"] = "java.lang.Integer";
99     (*variables)["value_wire_type"] = WireType(value);
100     (*variables)["value_default_value"] =
101         DefaultValue(value, true, name_resolver) + ".getNumber()";
102 
103     (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
104 
105     if (SupportUnknownEnumValue(descriptor->file())) {
106       // Map unknown values to a special UNRECOGNIZED value if supported.
107       (*variables)["unrecognized_value"] =
108           (*variables)["value_enum_type"] + ".UNRECOGNIZED";
109     } else {
110       // Map unknown values to the default value if we don't have UNRECOGNIZED.
111       (*variables)["unrecognized_value"] =
112           DefaultValue(value, true, name_resolver);
113     }
114   } else {
115     (*variables)["value_type"] = TypeName(value, name_resolver, false);
116     (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
117     (*variables)["value_wire_type"] = WireType(value);
118     (*variables)["value_default_value"] =
119         DefaultValue(value, true, name_resolver);
120   }
121   (*variables)["type_parameters"] =
122       (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
123   // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
124   // by the proto compiler
125   (*variables)["deprecation"] = descriptor->options().deprecated()
126       ? "@java.lang.Deprecated " : "";
127   (*variables)["on_changed"] = "onChanged();";
128 
129   // For repeated fields, one bit is used for whether the array is immutable
130   // in the parsing constructor.
131   (*variables)["get_mutable_bit_parser"] =
132       GenerateGetBitMutableLocal(builderBitIndex);
133   (*variables)["set_mutable_bit_parser"] =
134       GenerateSetBitMutableLocal(builderBitIndex);
135 
136   (*variables)["default_entry"] = (*variables)["capitalized_name"] +
137       "DefaultEntryHolder.defaultEntry";
138   (*variables)["lite"] = "";
139   (*variables)["map_field_parameter"] = (*variables)["default_entry"];
140   (*variables)["descriptor"] =
141       name_resolver->GetImmutableClassName(descriptor->file()) +
142       ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
143       "_descriptor, ";
144 }
145 
146 }  // namespace
147 
148 ImmutableMapFieldGenerator::
ImmutableMapFieldGenerator(const FieldDescriptor * descriptor,int messageBitIndex,int builderBitIndex,Context * context)149 ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
150                                        int messageBitIndex,
151                                        int builderBitIndex,
152                                        Context* context)
153   : descriptor_(descriptor), name_resolver_(context->GetNameResolver())  {
154   SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
155                       context->GetFieldGeneratorInfo(descriptor),
156                       context, &variables_);
157 }
158 
159 ImmutableMapFieldGenerator::
~ImmutableMapFieldGenerator()160 ~ImmutableMapFieldGenerator() {}
161 
GetNumBitsForMessage() const162 int ImmutableMapFieldGenerator::GetNumBitsForMessage() const {
163   return 0;
164 }
165 
GetNumBitsForBuilder() const166 int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
167   return 1;
168 }
169 
170 void ImmutableMapFieldGenerator::
GenerateInterfaceMembers(io::Printer * printer) const171 GenerateInterfaceMembers(io::Printer* printer) const {
172   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
173     WriteFieldDocComment(printer, descriptor_);
174     printer->Print(
175         variables_,
176         "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
177         "get$capitalized_name$();\n");
178     if (SupportUnknownEnumValue(descriptor_->file())) {
179       WriteFieldDocComment(printer, descriptor_);
180       printer->Print(
181           variables_,
182           "$deprecation$java.util.Map<$type_parameters$>\n"
183           "get$capitalized_name$Value();\n");
184     }
185   } else {
186     WriteFieldDocComment(printer, descriptor_);
187     printer->Print(
188         variables_,
189         "$deprecation$java.util.Map<$type_parameters$>\n"
190         "get$capitalized_name$();\n");
191   }
192 }
193 
194 void ImmutableMapFieldGenerator::
GenerateMembers(io::Printer * printer) const195 GenerateMembers(io::Printer* printer) const {
196   printer->Print(
197       variables_,
198       "private static final class $capitalized_name$DefaultEntryHolder {\n"
199       "  static final com.google.protobuf.MapEntry$lite$<\n"
200       "      $type_parameters$> defaultEntry =\n"
201       "          com.google.protobuf.MapEntry$lite$\n"
202       "          .<$type_parameters$>newDefaultInstance(\n"
203       "              $descriptor$\n"
204       "              $key_wire_type$,\n"
205       "              $key_default_value$,\n"
206       "              $value_wire_type$,\n"
207       "              $value_default_value$);\n"
208       "}\n");
209   printer->Print(
210       variables_,
211       "private com.google.protobuf.MapField$lite$<\n"
212       "    $type_parameters$> $name$_;\n"
213       "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
214       "internalGet$capitalized_name$() {\n"
215       "  if ($name$_ == null) {\n"
216       "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
217       "        $map_field_parameter$);\n"
218       "  }\n"
219       "  return $name$_;\n"
220       "}\n");
221   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
222     printer->Print(
223         variables_,
224         "private static final\n"
225         "com.google.protobuf.Internal.MapAdapter.Converter<\n"
226         "    java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
227         "        com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
228         "            $value_enum_type$.internalGetValueMap(),\n"
229         "            $unrecognized_value$);\n");
230     if (SupportUnknownEnumValue(descriptor_->file())) {
231       WriteFieldDocComment(printer, descriptor_);
232       printer->Print(
233           variables_,
234           "$deprecation$\n"
235           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
236           "get$capitalized_name$Value() {\n"
237           "  return internalGet$capitalized_name$().getMap();\n"
238           "}\n");
239     }
240     WriteFieldDocComment(printer, descriptor_);
241     printer->Print(
242         variables_,
243         "$deprecation$\n"
244         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
245         "get$capitalized_name$() {\n"
246         "  return new com.google.protobuf.Internal.MapAdapter<\n"
247         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
248         "          internalGet$capitalized_name$().getMap(),\n"
249         "          $name$ValueConverter);\n"
250         "}\n");
251   } else {
252     WriteFieldDocComment(printer, descriptor_);
253     printer->Print(
254         variables_,
255         "$deprecation$\n"
256         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
257         "  return internalGet$capitalized_name$().getMap();\n"
258         "}\n");
259   }
260 }
261 
262 void ImmutableMapFieldGenerator::
GenerateBuilderMembers(io::Printer * printer) const263 GenerateBuilderMembers(io::Printer* printer) const {
264   printer->Print(
265       variables_,
266       "private com.google.protobuf.MapField$lite$<\n"
267       "    $type_parameters$> $name$_;\n"
268       "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
269       "internalGet$capitalized_name$() {\n"
270       "  if ($name$_ == null) {\n"
271       "    return com.google.protobuf.MapField$lite$.emptyMapField(\n"
272       "        $map_field_parameter$);\n"
273       "  }\n"
274       "  return $name$_;\n"
275       "}\n"
276       "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
277       "internalGetMutable$capitalized_name$() {\n"
278       "  $on_changed$;\n"
279       "  if ($name$_ == null) {\n"
280       "    $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
281       "        $map_field_parameter$);\n"
282       "  }\n"
283       "  if (!$name$_.isMutable()) {\n"
284       "    $name$_ = $name$_.copy();\n"
285       "  }\n"
286       "  return $name$_;\n"
287       "}\n");
288   if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
289     WriteFieldDocComment(printer, descriptor_);
290     printer->Print(
291         variables_,
292         "$deprecation$\n"
293         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
294         "get$capitalized_name$() {\n"
295         "  return new com.google.protobuf.Internal.MapAdapter<\n"
296         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
297         "          internalGet$capitalized_name$().getMap(),\n"
298         "          $name$ValueConverter);\n"
299         "}\n");
300     WriteFieldDocComment(printer, descriptor_);
301     printer->Print(
302         variables_,
303         "$deprecation$\n"
304         "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
305         "getMutable$capitalized_name$() {\n"
306         "  return new com.google.protobuf.Internal.MapAdapter<\n"
307         "      $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
308         "          internalGetMutable$capitalized_name$().getMutableMap(),\n"
309         "          $name$ValueConverter);\n"
310         "}\n");
311     WriteFieldDocComment(printer, descriptor_);
312     printer->Print(
313         variables_,
314         "$deprecation$public Builder putAll$capitalized_name$(\n"
315         "    java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
316         "  getMutable$capitalized_name$().putAll(values);\n"
317         "  return this;\n"
318         "}\n");
319     if (SupportUnknownEnumValue(descriptor_->file())) {
320       WriteFieldDocComment(printer, descriptor_);
321       printer->Print(
322           variables_,
323           "$deprecation$\n"
324           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
325           "get$capitalized_name$Value() {\n"
326           "  return internalGet$capitalized_name$().getMap();\n"
327           "}\n");
328       WriteFieldDocComment(printer, descriptor_);
329       printer->Print(
330           variables_,
331           "$deprecation$\n"
332           "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
333           "getMutable$capitalized_name$Value() {\n"
334           "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
335           "}\n");
336       WriteFieldDocComment(printer, descriptor_);
337       printer->Print(
338           variables_,
339           "$deprecation$public Builder putAll$capitalized_name$Value(\n"
340           "    java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
341           "  getMutable$capitalized_name$Value().putAll(values);\n"
342           "  return this;\n"
343           "}\n");
344     }
345   } else {
346     WriteFieldDocComment(printer, descriptor_);
347     printer->Print(
348         variables_,
349         "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
350         "  return internalGet$capitalized_name$().getMap();\n"
351         "}\n");
352     WriteFieldDocComment(printer, descriptor_);
353     printer->Print(
354         variables_,
355         "public java.util.Map<$type_parameters$>\n"
356         "getMutable$capitalized_name$() {\n"
357         "  return internalGetMutable$capitalized_name$().getMutableMap();\n"
358         "}\n");
359     WriteFieldDocComment(printer, descriptor_);
360     printer->Print(
361         variables_,
362         "$deprecation$public Builder putAll$capitalized_name$(\n"
363         "    java.util.Map<$type_parameters$> values) {\n"
364         "  getMutable$capitalized_name$().putAll(values);\n"
365         "  return this;\n"
366         "}\n");
367   }
368 }
369 
370 void ImmutableMapFieldGenerator::
GenerateFieldBuilderInitializationCode(io::Printer * printer) const371 GenerateFieldBuilderInitializationCode(io::Printer* printer)  const {
372   // Nothing to initialize.
373 }
374 
375 void ImmutableMapFieldGenerator::
GenerateInitializationCode(io::Printer * printer) const376 GenerateInitializationCode(io::Printer* printer) const {
377   // Nothing to initialize.
378 }
379 
380 void ImmutableMapFieldGenerator::
GenerateBuilderClearCode(io::Printer * printer) const381 GenerateBuilderClearCode(io::Printer* printer) const {
382   printer->Print(
383       variables_,
384       "internalGetMutable$capitalized_name$().clear();\n");
385 }
386 
387 void ImmutableMapFieldGenerator::
GenerateMergingCode(io::Printer * printer) const388 GenerateMergingCode(io::Printer* printer) const {
389   printer->Print(
390       variables_,
391       "internalGetMutable$capitalized_name$().mergeFrom(\n"
392       "    other.internalGet$capitalized_name$());\n");
393 }
394 
395 void ImmutableMapFieldGenerator::
GenerateBuildingCode(io::Printer * printer) const396 GenerateBuildingCode(io::Printer* printer) const {
397   printer->Print(
398       variables_,
399       "result.$name$_ = internalGet$capitalized_name$();\n"
400       "result.$name$_.makeImmutable();\n");
401 }
402 
403 void ImmutableMapFieldGenerator::
GenerateParsingCode(io::Printer * printer) const404 GenerateParsingCode(io::Printer* printer) const {
405   printer->Print(
406       variables_,
407       "if (!$get_mutable_bit_parser$) {\n"
408       "  $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
409       "      $map_field_parameter$);\n"
410       "  $set_mutable_bit_parser$;\n"
411       "}\n");
412   if (!SupportUnknownEnumValue(descriptor_->file()) &&
413       GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
414     printer->Print(
415         variables_,
416         "com.google.protobuf.ByteString bytes = input.readBytes();\n"
417         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
418         "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
419     printer->Print(
420         variables_,
421         "if ($value_enum_type$.forNumber($name$.getValue()) == null) {\n"
422         "  unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
423         "} else {\n"
424         "  $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
425         "}\n");
426   } else {
427     printer->Print(
428         variables_,
429         "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
430         "$name$ = input.readMessage(\n"
431         "    $default_entry$.getParserForType(), extensionRegistry);\n"
432         "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
433   }
434 }
435 
436 void ImmutableMapFieldGenerator::
GenerateParsingDoneCode(io::Printer * printer) const437 GenerateParsingDoneCode(io::Printer* printer) const {
438   // Nothing to do here.
439 }
440 
441 void ImmutableMapFieldGenerator::
GenerateSerializationCode(io::Printer * printer) const442 GenerateSerializationCode(io::Printer* printer) const {
443   printer->Print(
444       variables_,
445       "for (java.util.Map.Entry<$type_parameters$> entry\n"
446       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
447       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
448       "  $name$ = $default_entry$.newBuilderForType()\n"
449       "      .setKey(entry.getKey())\n"
450       "      .setValue(entry.getValue())\n"
451       "      .build();\n"
452       "  output.writeMessage($number$, $name$);\n"
453       "}\n");
454 }
455 
456 void ImmutableMapFieldGenerator::
GenerateSerializedSizeCode(io::Printer * printer) const457 GenerateSerializedSizeCode(io::Printer* printer) const {
458   printer->Print(
459       variables_,
460       "for (java.util.Map.Entry<$type_parameters$> entry\n"
461       "     : internalGet$capitalized_name$().getMap().entrySet()) {\n"
462       "  com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
463       "  $name$ = $default_entry$.newBuilderForType()\n"
464       "      .setKey(entry.getKey())\n"
465       "      .setValue(entry.getValue())\n"
466       "      .build();\n"
467       "  size += com.google.protobuf.CodedOutputStream\n"
468       "      .computeMessageSize($number$, $name$);\n"
469       "}\n");
470 }
471 
472 void ImmutableMapFieldGenerator::
GenerateEqualsCode(io::Printer * printer) const473 GenerateEqualsCode(io::Printer* printer) const {
474   printer->Print(
475       variables_,
476       "result = result && internalGet$capitalized_name$().equals(\n"
477       "    other.internalGet$capitalized_name$());\n");
478 }
479 
480 void ImmutableMapFieldGenerator::
GenerateHashCode(io::Printer * printer) const481 GenerateHashCode(io::Printer* printer) const {
482   printer->Print(
483       variables_,
484       "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
485       "  hash = (37 * hash) + $constant_name$;\n"
486       "  hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
487       "}\n");
488 }
489 
GetBoxedType() const490 string ImmutableMapFieldGenerator::GetBoxedType() const {
491   return name_resolver_->GetImmutableClassName(descriptor_->message_type());
492 }
493 
494 }  // namespace java
495 }  // namespace compiler
496 }  // namespace protobuf
497 }  // namespace google
498