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