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