blob: cf1ef5890cfbe93fd368c0ee27b6b8a20f031fd3 [file] [log] [blame]
Feng Xiao6ef984a2014-11-10 17:34:54 -08001// 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
39namespace google {
40namespace protobuf {
41namespace compiler {
42namespace java {
43
44namespace {
45
46const 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
53const 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
60string 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
73string WireType(const FieldDescriptor* field) {
74 return "com.google.protobuf.WireFormat.FieldType." +
75 string(FieldTypeName(field->type()));
76}
77
78void SetMessageVariables(const FieldDescriptor* descriptor,
79 int messageBitIndex,
80 int builderBitIndex,
81 const FieldGeneratorInfo* info,
82 ClassNameResolver* name_resolver,
83 map<string, string>* variables) {
84 SetCommonFieldVariables(descriptor, info, variables);
85
86 (*variables)["type"] =
87 name_resolver->GetImmutableClassName(descriptor->message_type());
88 const FieldDescriptor* key = KeyField(descriptor);
89 const FieldDescriptor* value = ValueField(descriptor);
90 (*variables)["key_type"] = TypeName(key, name_resolver, false);
91 (*variables)["boxed_key_type"] = TypeName(key, name_resolver, true);
92 (*variables)["key_wire_type"] = WireType(key);
93 (*variables)["key_default_value"] = DefaultValue(key, true, name_resolver);
94 if (GetJavaType(value) == JAVATYPE_ENUM) {
95 // We store enums as Integers internally.
96 (*variables)["value_type"] = "int";
97 (*variables)["boxed_value_type"] = "java.lang.Integer";
98 (*variables)["value_wire_type"] = WireType(value);
99 (*variables)["value_default_value"] =
100 DefaultValue(value, true, name_resolver) + ".getNumber()";
101
102 (*variables)["value_enum_type"] = TypeName(value, name_resolver, false);
103
104 if (SupportUnknownEnumValue(descriptor->file())) {
105 // Map unknown values to a special UNRECOGNIZED value if supported.
106 (*variables)["unrecognized_value"] =
107 (*variables)["value_enum_type"] + ".UNRECOGNIZED";
108 } else {
109 // Map unknown values to the default value if we don't have UNRECOGNIZED.
110 (*variables)["unrecognized_value"] =
111 DefaultValue(value, true, name_resolver);
112 }
113 } else {
114 (*variables)["value_type"] = TypeName(value, name_resolver, false);
115 (*variables)["boxed_value_type"] = TypeName(value, name_resolver, true);
116 (*variables)["value_wire_type"] = WireType(value);
117 (*variables)["value_default_value"] =
118 DefaultValue(value, true, name_resolver);
119 }
120 (*variables)["type_parameters"] =
121 (*variables)["boxed_key_type"] + ", " + (*variables)["boxed_value_type"];
122 // TODO(birdo): Add @deprecated javadoc when generating javadoc is supported
123 // by the proto compiler
124 (*variables)["deprecation"] = descriptor->options().deprecated()
125 ? "@java.lang.Deprecated " : "";
126 (*variables)["on_changed"] =
127 HasDescriptorMethods(descriptor->containing_type()) ? "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 if (HasDescriptorMethods(descriptor->file())) {
137 (*variables)["lite"] = "";
138 (*variables)["map_field_parameter"] = (*variables)["name"] + "DefaultEntry";
139 (*variables)["descriptor"] =
140 name_resolver->GetImmutableClassName(descriptor->file()) +
141 ".internal_" + UniqueFileScopeIdentifier(descriptor->message_type()) +
142 "_descriptor, ";
143 } else {
144 (*variables)["lite"] = "Lite";
145 (*variables)["map_field_parameter"] = "";
146 (*variables)["descriptor"] = "";
147 }
148}
149
150} // namespace
151
152ImmutableMapFieldGenerator::
153ImmutableMapFieldGenerator(const FieldDescriptor* descriptor,
154 int messageBitIndex,
155 int builderBitIndex,
156 Context* context)
157 : descriptor_(descriptor), messageBitIndex_(messageBitIndex),
158 builderBitIndex_(builderBitIndex), context_(context),
159 name_resolver_(context->GetNameResolver()) {
160 SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
161 context->GetFieldGeneratorInfo(descriptor),
162 name_resolver_, &variables_);
163}
164
165ImmutableMapFieldGenerator::
166~ImmutableMapFieldGenerator() {}
167
168int ImmutableMapFieldGenerator::GetNumBitsForMessage() const {
169 return 0;
170}
171
172int ImmutableMapFieldGenerator::GetNumBitsForBuilder() const {
173 return 1;
174}
175
176void ImmutableMapFieldGenerator::
177GenerateInterfaceMembers(io::Printer* printer) const {
178 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
179 WriteFieldDocComment(printer, descriptor_);
180 printer->Print(
181 variables_,
182 "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
183 "get$capitalized_name$();\n");
184 if (SupportUnknownEnumValue(descriptor_->file())) {
185 WriteFieldDocComment(printer, descriptor_);
186 printer->Print(
187 variables_,
188 "$deprecation$java.util.Map<$type_parameters$>\n"
189 "get$capitalized_name$Value();\n");
190 }
191 } else {
192 WriteFieldDocComment(printer, descriptor_);
193 printer->Print(
194 variables_,
195 "$deprecation$java.util.Map<$type_parameters$>\n"
196 "get$capitalized_name$();\n");
197 }
198}
199
200void ImmutableMapFieldGenerator::
Jisi Liu885b6122015-02-28 14:51:22 -0800201GenerateStaticInitializationCode(io::Printer* printer) const {
202 printer->Print(
203 variables_,
204 "$name$DefaultEntry =\n"
205 " com.google.protobuf.MapEntry$lite$\n"
206 " .<$type_parameters$>newDefaultInstance(\n"
207 " $descriptor$\n"
208 " $key_wire_type$,\n"
209 " $key_default_value$,\n"
210 " $value_wire_type$,\n"
211 " $value_default_value$);\n"
212 "\n");
213}
214
215void ImmutableMapFieldGenerator::
Feng Xiao6ef984a2014-11-10 17:34:54 -0800216GenerateMembers(io::Printer* printer) const {
217 printer->Print(
218 variables_,
219 "private static final com.google.protobuf.MapEntry$lite$<\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800220 " $type_parameters$> $name$DefaultEntry;\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800221 printer->Print(
222 variables_,
223 "private com.google.protobuf.MapField$lite$<\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800224 " $type_parameters$> $name$_;\n"
225 "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
226 "internalGet$capitalized_name$() {\n"
227 " if ($name$_ == null) {\n"
228 " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
229 " $map_field_parameter$);\n"
230 " }\n"
231 " return $name$_;\n"
232 "}\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800233 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
234 printer->Print(
235 variables_,
236 "private static final\n"
237 "com.google.protobuf.Internal.MapAdapter.Converter<\n"
238 " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
239 " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
240 " $value_enum_type$.internalGetValueMap(),\n"
241 " $unrecognized_value$);\n");
242 if (SupportUnknownEnumValue(descriptor_->file())) {
243 WriteFieldDocComment(printer, descriptor_);
244 printer->Print(
245 variables_,
246 "$deprecation$\n"
247 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
248 "get$capitalized_name$Value() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800249 " return internalGet$capitalized_name$().getMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800250 "}\n");
251 }
252 WriteFieldDocComment(printer, descriptor_);
253 printer->Print(
254 variables_,
255 "$deprecation$\n"
256 "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
257 "get$capitalized_name$() {\n"
258 " return new com.google.protobuf.Internal.MapAdapter<\n"
259 " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800260 " internalGet$capitalized_name$().getMap(),\n"
261 " $name$ValueConverter);\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800262 "}\n");
263 } else {
264 WriteFieldDocComment(printer, descriptor_);
265 printer->Print(
266 variables_,
267 "$deprecation$\n"
268 "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800269 " return internalGet$capitalized_name$().getMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800270 "}\n");
271 }
272}
273
274void ImmutableMapFieldGenerator::
275GenerateBuilderMembers(io::Printer* printer) const {
276 printer->Print(
277 variables_,
278 "private com.google.protobuf.MapField$lite$<\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800279 " $type_parameters$> $name$_;\n"
280 "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
281 "internalGet$capitalized_name$() {\n"
282 " if ($name$_ == null) {\n"
283 " return com.google.protobuf.MapField$lite$.emptyMapField(\n"
284 " $map_field_parameter$);\n"
285 " }\n"
286 " return $name$_;\n"
287 "}\n"
288 "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
289 "internalGetMutable$capitalized_name$() {\n"
290 " $on_changed$;\n"
291 " if ($name$_ == null) {\n"
292 " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
293 " $map_field_parameter$);\n"
294 " }\n"
295 " return $name$_;\n"
296 "}\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800297 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
298 WriteFieldDocComment(printer, descriptor_);
299 printer->Print(
300 variables_,
301 "$deprecation$\n"
302 "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
303 "get$capitalized_name$() {\n"
304 " return new com.google.protobuf.Internal.MapAdapter<\n"
305 " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800306 " internalGet$capitalized_name$().getMap(),\n"
307 " $name$ValueConverter);\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800308 "}\n");
309 WriteFieldDocComment(printer, descriptor_);
310 printer->Print(
311 variables_,
312 "$deprecation$\n"
313 "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
314 "getMutable$capitalized_name$() {\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800315 " return new com.google.protobuf.Internal.MapAdapter<\n"
316 " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800317 " internalGetMutable$capitalized_name$().getMutableMap(),\n"
318 " $name$ValueConverter);\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800319 "}\n");
320 if (SupportUnknownEnumValue(descriptor_->file())) {
321 WriteFieldDocComment(printer, descriptor_);
322 printer->Print(
323 variables_,
324 "$deprecation$\n"
325 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
326 "get$capitalized_name$Value() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800327 " return internalGet$capitalized_name$().getMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800328 "}\n");
329 WriteFieldDocComment(printer, descriptor_);
330 printer->Print(
331 variables_,
332 "$deprecation$\n"
333 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
334 "getMutable$capitalized_name$Value() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800335 " return internalGetMutable$capitalized_name$().getMutableMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800336 "}\n");
337 }
338 } else {
339 WriteFieldDocComment(printer, descriptor_);
340 printer->Print(
341 variables_,
342 "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800343 " return internalGet$capitalized_name$().getMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800344 "}\n");
345 WriteFieldDocComment(printer, descriptor_);
346 printer->Print(
347 variables_,
348 "public java.util.Map<$type_parameters$>\n"
349 "getMutable$capitalized_name$() {\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800350 " return internalGetMutable$capitalized_name$().getMutableMap();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800351 "}\n");
352 }
353}
354
355void ImmutableMapFieldGenerator::
356GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
357 // Nothing to initialize.
358}
359
360void ImmutableMapFieldGenerator::
361GenerateInitializationCode(io::Printer* printer) const {
362 // Nothing to initialize.
363}
364
365void ImmutableMapFieldGenerator::
366GenerateBuilderClearCode(io::Printer* printer) const {
367 printer->Print(
368 variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800369 "internalGetMutable$capitalized_name$().clear();\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800370}
371
372void ImmutableMapFieldGenerator::
373GenerateMergingCode(io::Printer* printer) const {
374 printer->Print(
375 variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800376 "internalGetMutable$capitalized_name$().mergeFrom(\n"
377 " other.internalGet$capitalized_name$());\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800378}
379
380void ImmutableMapFieldGenerator::
381GenerateBuildingCode(io::Printer* printer) const {
382 printer->Print(
383 variables_,
384 // We do a copy of the map field to ensure that the built result is
385 // immutable. Implementation of this copy() method can do copy-on-write
386 // to defer this copy until further modifications are made on the field.
Jisi Liu885b6122015-02-28 14:51:22 -0800387 "result.$name$_ = internalGet$capitalized_name$().copy();\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800388}
389
390void ImmutableMapFieldGenerator::
391GenerateParsingCode(io::Printer* printer) const {
392 printer->Print(
393 variables_,
394 "if (!$get_mutable_bit_parser$) {\n"
395 " $name$_ = com.google.protobuf.MapField$lite$.newMapField(\n"
396 " $map_field_parameter$);\n"
397 " $set_mutable_bit_parser$;\n"
398 "}\n");
399 if (!SupportUnknownEnumValue(descriptor_->file()) &&
400 GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
401 printer->Print(
402 variables_,
403 "com.google.protobuf.ByteString bytes = input.readBytes();\n"
404 "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
405 "$name$ = $name$DefaultEntry.getParserForType().parseFrom(bytes);\n");
406 printer->Print(
407 variables_,
408 "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
409 " unknownFields.mergeLengthDelimitedField($number$, bytes);\n"
410 "} else {\n"
411 " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
412 "}\n");
413 } else {
414 printer->Print(
415 variables_,
416 "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
417 "$name$ = input.readMessage(\n"
418 " $name$DefaultEntry.getParserForType(), extensionRegistry);\n"
419 "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
420 }
421}
422
423void ImmutableMapFieldGenerator::
424GenerateParsingDoneCode(io::Printer* printer) const {
425 // Nothing to do here.
426}
427
428void ImmutableMapFieldGenerator::
429GenerateSerializationCode(io::Printer* printer) const {
430 printer->Print(
431 variables_,
432 "for (java.util.Map.Entry<$type_parameters$> entry\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800433 " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800434 " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
435 " $name$ = $name$DefaultEntry.newBuilderForType()\n"
436 " .setKey(entry.getKey())\n"
437 " .setValue(entry.getValue())\n"
438 " .build();\n"
439 " output.writeMessage($number$, $name$);\n"
440 "}\n");
441}
442
443void ImmutableMapFieldGenerator::
444GenerateSerializedSizeCode(io::Printer* printer) const {
445 printer->Print(
446 variables_,
447 "for (java.util.Map.Entry<$type_parameters$> entry\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800448 " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800449 " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
450 " $name$ = $name$DefaultEntry.newBuilderForType()\n"
451 " .setKey(entry.getKey())\n"
452 " .setValue(entry.getValue())\n"
453 " .build();\n"
454 " size += com.google.protobuf.CodedOutputStream\n"
455 " .computeMessageSize($number$, $name$);\n"
456 "}\n");
457}
458
459void ImmutableMapFieldGenerator::
460GenerateEqualsCode(io::Printer* printer) const {
461 printer->Print(
462 variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800463 "result = result && internalGet$capitalized_name$().equals(\n"
464 " other.internalGet$capitalized_name$());\n");
Feng Xiao6ef984a2014-11-10 17:34:54 -0800465}
466
467void ImmutableMapFieldGenerator::
468GenerateHashCode(io::Printer* printer) const {
469 printer->Print(
470 variables_,
Jisi Liu885b6122015-02-28 14:51:22 -0800471 "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800472 " hash = (37 * hash) + $constant_name$;\n"
Jisi Liu885b6122015-02-28 14:51:22 -0800473 " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
Feng Xiao6ef984a2014-11-10 17:34:54 -0800474 "}\n");
475}
476
477string ImmutableMapFieldGenerator::GetBoxedType() const {
478 return name_resolver_->GetImmutableClassName(descriptor_->message_type());
479}
480
481} // namespace java
482} // namespace compiler
483} // namespace protobuf
484} // namespace google