blob: d2039403e9760492990c9356225c5573a652fb15 [file] [log] [blame]
Bo Yang5db21732015-05-21 14:28:59 -07001// 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_lite.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 (*variables)["default_entry"] = (*variables)["capitalized_name"] +
130 "DefaultEntryHolder.defaultEntry";
131 (*variables)["lite"] = "Lite";
132 (*variables)["descriptor"] = "";
133}
134
135} // namespace
136
137ImmutableMapFieldLiteGenerator::
138ImmutableMapFieldLiteGenerator(const FieldDescriptor* descriptor,
139 int messageBitIndex,
140 int builderBitIndex,
141 Context* context)
Tom Hughes93ba9332015-07-29 14:27:05 -0700142 : descriptor_(descriptor), name_resolver_(context->GetNameResolver()) {
Bo Yang5db21732015-05-21 14:28:59 -0700143 SetMessageVariables(descriptor, messageBitIndex, builderBitIndex,
144 context->GetFieldGeneratorInfo(descriptor),
145 name_resolver_, &variables_);
146}
147
148ImmutableMapFieldLiteGenerator::
149~ImmutableMapFieldLiteGenerator() {}
150
151int ImmutableMapFieldLiteGenerator::GetNumBitsForMessage() const {
152 return 0;
153}
154
155int ImmutableMapFieldLiteGenerator::GetNumBitsForBuilder() const {
156 return 0;
157}
158
159void ImmutableMapFieldLiteGenerator::
160GenerateInterfaceMembers(io::Printer* printer) const {
161 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
162 WriteFieldDocComment(printer, descriptor_);
163 printer->Print(
164 variables_,
165 "$deprecation$java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
166 "get$capitalized_name$();\n");
167 if (SupportUnknownEnumValue(descriptor_->file())) {
168 WriteFieldDocComment(printer, descriptor_);
169 printer->Print(
170 variables_,
171 "$deprecation$java.util.Map<$type_parameters$>\n"
172 "get$capitalized_name$Value();\n");
173 }
174 } else {
175 WriteFieldDocComment(printer, descriptor_);
176 printer->Print(
177 variables_,
178 "$deprecation$java.util.Map<$type_parameters$>\n"
179 "get$capitalized_name$();\n");
180 }
181}
182
183void ImmutableMapFieldLiteGenerator::
184GenerateMembers(io::Printer* printer) const {
185 printer->Print(
186 variables_,
187 "private static final class $capitalized_name$DefaultEntryHolder {\n"
188 " static final com.google.protobuf.MapEntry$lite$<\n"
189 " $type_parameters$> defaultEntry =\n"
190 " com.google.protobuf.MapEntry$lite$\n"
191 " .<$type_parameters$>newDefaultInstance(\n"
192 " $descriptor$\n"
193 " $key_wire_type$,\n"
194 " $key_default_value$,\n"
195 " $value_wire_type$,\n"
196 " $value_default_value$);\n"
197 "}\n");
198 printer->Print(
199 variables_,
200 "private com.google.protobuf.MapField$lite$<\n"
201 " $type_parameters$> $name$_ =\n"
202 " com.google.protobuf.MapField$lite$.emptyMapField();\n"
203 "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
204 "internalGet$capitalized_name$() {\n"
205 " return $name$_;\n"
206 "}\n"
207 "private com.google.protobuf.MapField$lite$<$type_parameters$>\n"
208 "internalGetMutable$capitalized_name$() {\n"
209 " if (!$name$_.isMutable()) {\n"
210 " $name$_ = $name$_.copy();\n"
211 " }\n"
212 " return $name$_;\n"
213 "}\n");
214 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
215 printer->Print(
216 variables_,
217 "private static final\n"
218 "com.google.protobuf.Internal.MapAdapter.Converter<\n"
219 " java.lang.Integer, $value_enum_type$> $name$ValueConverter =\n"
220 " com.google.protobuf.Internal.MapAdapter.newEnumConverter(\n"
221 " $value_enum_type$.internalGetValueMap(),\n"
222 " $unrecognized_value$);\n");
223 if (SupportUnknownEnumValue(descriptor_->file())) {
224 WriteFieldDocComment(printer, descriptor_);
225 printer->Print(
226 variables_,
227 "$deprecation$\n"
228 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
229 "get$capitalized_name$Value() {\n"
230 " return internalGet$capitalized_name$().getMap();\n"
231 "}\n");
232 }
233 WriteFieldDocComment(printer, descriptor_);
234 printer->Print(
235 variables_,
236 "$deprecation$\n"
237 "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
238 "get$capitalized_name$() {\n"
239 " return new com.google.protobuf.Internal.MapAdapter<\n"
240 " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
241 " internalGet$capitalized_name$().getMap(),\n"
242 " $name$ValueConverter);\n"
243 "}\n");
244 } else {
245 WriteFieldDocComment(printer, descriptor_);
246 printer->Print(
247 variables_,
248 "$deprecation$\n"
249 "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
250 " return internalGet$capitalized_name$().getMap();\n"
251 "}\n");
252 }
253
254 // Generate private setters for the builder to proxy into.
255 if (GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
256 WriteFieldDocComment(printer, descriptor_);
257 printer->Print(
258 variables_,
259 "private java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
260 "getMutable$capitalized_name$() {\n"
261 " return new com.google.protobuf.Internal.MapAdapter<\n"
262 " $boxed_key_type$, $value_enum_type$, java.lang.Integer>(\n"
263 " internalGetMutable$capitalized_name$().getMutableMap(),\n"
264 " $name$ValueConverter);\n"
265 "}\n");
266 if (SupportUnknownEnumValue(descriptor_->file())) {
267 WriteFieldDocComment(printer, descriptor_);
268 printer->Print(
269 variables_,
270 "private java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
271 "getMutable$capitalized_name$Value() {\n"
272 " return internalGetMutable$capitalized_name$().getMutableMap();\n"
273 "}\n");
274 }
275 } else {
276 WriteFieldDocComment(printer, descriptor_);
277 printer->Print(
278 variables_,
279 "private java.util.Map<$type_parameters$>\n"
280 "getMutable$capitalized_name$() {\n"
281 " return internalGetMutable$capitalized_name$().getMutableMap();\n"
282 "}\n");
283 }
284}
285
286void ImmutableMapFieldLiteGenerator::
287GenerateBuilderMembers(io::Printer* printer) const {
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 instance.get$capitalized_name$();\n"
296 "}\n");
297 WriteFieldDocComment(printer, descriptor_);
298 printer->Print(
299 variables_,
300 "$deprecation$\n"
301 "public java.util.Map<$boxed_key_type$, $value_enum_type$>\n"
302 "getMutable$capitalized_name$() {\n"
303 " copyOnWrite();\n"
304 " return instance.getMutable$capitalized_name$();\n"
305 "}\n");
Feng Xiaoeee38b02015-08-22 18:25:48 -0700306 WriteFieldDocComment(printer, descriptor_);
307 printer->Print(
308 variables_,
309 "$deprecation$public Builder putAll$capitalized_name$(\n"
310 " java.util.Map<$boxed_key_type$, $value_enum_type$> values) {\n"
311 " getMutable$capitalized_name$().putAll(values);\n"
312 " return this;\n"
313 "}\n");
Bo Yang5db21732015-05-21 14:28:59 -0700314 if (SupportUnknownEnumValue(descriptor_->file())) {
315 WriteFieldDocComment(printer, descriptor_);
316 printer->Print(
317 variables_,
318 "$deprecation$\n"
319 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
320 "get$capitalized_name$Value() {\n"
321 " return instance.get$capitalized_name$Value();\n"
322 "}\n");
323 WriteFieldDocComment(printer, descriptor_);
324 printer->Print(
325 variables_,
326 "$deprecation$\n"
327 "public java.util.Map<$boxed_key_type$, $boxed_value_type$>\n"
328 "getMutable$capitalized_name$Value() {\n"
329 " copyOnWrite();\n"
330 " return instance.getMutable$capitalized_name$Value();\n"
331 "}\n");
Feng Xiaoeee38b02015-08-22 18:25:48 -0700332 WriteFieldDocComment(printer, descriptor_);
333 printer->Print(
334 variables_,
335 "$deprecation$public Builder putAll$capitalized_name$Value(\n"
336 " java.util.Map<$boxed_key_type$, $boxed_value_type$> values) {\n"
337 " getMutable$capitalized_name$Value().putAll(values);\n"
338 " return this;\n"
339 "}\n");
Bo Yang5db21732015-05-21 14:28:59 -0700340 }
341 } else {
342 WriteFieldDocComment(printer, descriptor_);
343 printer->Print(
344 variables_,
345 "public java.util.Map<$type_parameters$> get$capitalized_name$() {\n"
346 " return instance.get$capitalized_name$();\n"
347 "}\n");
348 WriteFieldDocComment(printer, descriptor_);
349 printer->Print(
350 variables_,
351 "public java.util.Map<$type_parameters$>\n"
352 "getMutable$capitalized_name$() {\n"
353 " copyOnWrite();\n"
354 " return instance.getMutable$capitalized_name$();\n"
355 "}\n");
Feng Xiaoeee38b02015-08-22 18:25:48 -0700356 WriteFieldDocComment(printer, descriptor_);
357 printer->Print(
358 variables_,
359 "public Builder putAll$capitalized_name$(\n"
360 " java.util.Map<$type_parameters$> values) {\n"
361 " getMutable$capitalized_name$().putAll(values);\n"
362 " return this;\n"
363 "}\n");
Bo Yang5db21732015-05-21 14:28:59 -0700364 }
365}
366
367void ImmutableMapFieldLiteGenerator::
368GenerateFieldBuilderInitializationCode(io::Printer* printer) const {
369 // Nothing to initialize.
370}
371
372void ImmutableMapFieldLiteGenerator::
373GenerateInitializationCode(io::Printer* printer) const {
374 // Nothing to initialize.
375}
376
377void ImmutableMapFieldLiteGenerator::
378GenerateMergingCode(io::Printer* printer) const {
379 printer->Print(
380 variables_,
381 "internalGetMutable$capitalized_name$().mergeFrom(\n"
382 " other.internalGet$capitalized_name$());\n");
383}
384
385void ImmutableMapFieldLiteGenerator::
386GenerateDynamicMethodMakeImmutableCode(io::Printer* printer) const {
387 printer->Print(variables_,
388 "$name$_.makeImmutable();\n");
389}
390
391void ImmutableMapFieldLiteGenerator::
392GenerateParsingCode(io::Printer* printer) const {
393 printer->Print(
394 variables_,
395 "if (!$name$_.isMutable()) {\n"
396 " $name$_ = $name$_.copy();\n"
397 "}\n");
398 if (!SupportUnknownEnumValue(descriptor_->file()) &&
399 GetJavaType(ValueField(descriptor_)) == JAVATYPE_ENUM) {
400 printer->Print(
401 variables_,
402 "com.google.protobuf.ByteString bytes = input.readBytes();\n"
403 "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
404 "$name$ = $default_entry$.getParserForType().parseFrom(bytes);\n");
405 printer->Print(
406 variables_,
407 "if ($value_enum_type$.valueOf($name$.getValue()) == null) {\n"
Jisi Liu46e8ff62015-10-05 11:59:43 -0700408 " super.mergeLengthDelimitedField($number$, bytes);\n"
Bo Yang5db21732015-05-21 14:28:59 -0700409 "} else {\n"
410 " $name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n"
411 "}\n");
412 } else {
413 printer->Print(
414 variables_,
415 "com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
416 "$name$ = input.readMessage(\n"
417 " $default_entry$.getParserForType(), extensionRegistry);\n"
418 "$name$_.getMutableMap().put($name$.getKey(), $name$.getValue());\n");
419 }
420}
421
422void ImmutableMapFieldLiteGenerator::
423GenerateParsingDoneCode(io::Printer* printer) const {
424 // Nothing to do here.
425}
426
427void ImmutableMapFieldLiteGenerator::
428GenerateSerializationCode(io::Printer* printer) const {
429 printer->Print(
430 variables_,
431 "for (java.util.Map.Entry<$type_parameters$> entry\n"
432 " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
433 " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
434 " $name$ = $default_entry$.newBuilderForType()\n"
435 " .setKey(entry.getKey())\n"
436 " .setValue(entry.getValue())\n"
437 " .build();\n"
438 " output.writeMessage($number$, $name$);\n"
439 "}\n");
440}
441
442void ImmutableMapFieldLiteGenerator::
443GenerateSerializedSizeCode(io::Printer* printer) const {
444 printer->Print(
445 variables_,
446 "for (java.util.Map.Entry<$type_parameters$> entry\n"
447 " : internalGet$capitalized_name$().getMap().entrySet()) {\n"
448 " com.google.protobuf.MapEntry$lite$<$type_parameters$>\n"
449 " $name$ = $default_entry$.newBuilderForType()\n"
450 " .setKey(entry.getKey())\n"
451 " .setValue(entry.getValue())\n"
452 " .build();\n"
453 " size += com.google.protobuf.CodedOutputStream\n"
454 " .computeMessageSize($number$, $name$);\n"
455 "}\n");
456}
457
458void ImmutableMapFieldLiteGenerator::
459GenerateEqualsCode(io::Printer* printer) const {
460 printer->Print(
461 variables_,
462 "result = result && internalGet$capitalized_name$().equals(\n"
463 " other.internalGet$capitalized_name$());\n");
464}
465
466void ImmutableMapFieldLiteGenerator::
467GenerateHashCode(io::Printer* printer) const {
468 printer->Print(
469 variables_,
470 "if (!internalGet$capitalized_name$().getMap().isEmpty()) {\n"
471 " hash = (37 * hash) + $constant_name$;\n"
472 " hash = (53 * hash) + internalGet$capitalized_name$().hashCode();\n"
473 "}\n");
474}
475
476string ImmutableMapFieldLiteGenerator::GetBoxedType() const {
477 return name_resolver_->GetImmutableClassName(descriptor_->message_type());
478}
479
480} // namespace java
481} // namespace compiler
482} // namespace protobuf
483} // namespace google