javamicro_message.cc revision 25b5a76155860b450c1176684f8e6007aab8aa7b
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// http://code.google.com/p/protobuf/
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// Author: kenton@google.com (Kenton Varda)
32//  Based on original Protocol Buffers design by
33//  Sanjay Ghemawat, Jeff Dean, and others.
34
35#include <algorithm>
36#include <google/protobuf/stubs/hash.h>
37#include <google/protobuf/compiler/javamicro/javamicro_message.h>
38#include <google/protobuf/compiler/javamicro/javamicro_enum.h>
39#include <google/protobuf/compiler/javamicro/javamicro_helpers.h>
40#include <google/protobuf/stubs/strutil.h>
41#include <google/protobuf/io/printer.h>
42#include <google/protobuf/io/coded_stream.h>
43#include <google/protobuf/wire_format.h>
44#include <google/protobuf/descriptor.pb.h>
45
46namespace google {
47namespace protobuf {
48namespace compiler {
49namespace javamicro {
50
51using internal::WireFormat;
52using internal::WireFormatLite;
53
54namespace {
55
56void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
57  // Print the field's proto-syntax definition as a comment.  We don't want to
58  // print group bodies so we cut off after the first line.
59  string def = field->DebugString();
60  printer->Print("// $def$\n",
61    "def", def.substr(0, def.find_first_of('\n')));
62}
63
64struct FieldOrderingByNumber {
65  inline bool operator()(const FieldDescriptor* a,
66                         const FieldDescriptor* b) const {
67    return a->number() < b->number();
68  }
69};
70
71// Sort the fields of the given Descriptor by number into a new[]'d array
72// and return it.
73const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
74  const FieldDescriptor** fields =
75    new const FieldDescriptor*[descriptor->field_count()];
76  for (int i = 0; i < descriptor->field_count(); i++) {
77    fields[i] = descriptor->field(i);
78  }
79  sort(fields, fields + descriptor->field_count(),
80       FieldOrderingByNumber());
81  return fields;
82}
83
84// Get an identifier that uniquely identifies this type within the file.
85// This is used to declare static variables related to this type at the
86// outermost file scope.
87string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
88  return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
89}
90
91// Returns true if the message type has any required fields.  If it doesn't,
92// we can optimize out calls to its isInitialized() method.
93//
94// already_seen is used to avoid checking the same type multiple times
95// (and also to protect against recursion).
96static bool HasRequiredFields(
97    const Descriptor* type,
98    hash_set<const Descriptor*>* already_seen) {
99  if (already_seen->count(type) > 0) {
100    // The type is already in cache.  This means that either:
101    // a. The type has no required fields.
102    // b. We are in the midst of checking if the type has required fields,
103    //    somewhere up the stack.  In this case, we know that if the type
104    //    has any required fields, they'll be found when we return to it,
105    //    and the whole call to HasRequiredFields() will return true.
106    //    Therefore, we don't have to check if this type has required fields
107    //    here.
108    return false;
109  }
110  already_seen->insert(type);
111
112  // If the type has extensions, an extension with message type could contain
113  // required fields, so we have to be conservative and assume such an
114  // extension exists.
115  if (type->extension_range_count() > 0) return true;
116
117  for (int i = 0; i < type->field_count(); i++) {
118    const FieldDescriptor* field = type->field(i);
119    if (field->is_required()) {
120      return true;
121    }
122    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
123      if (HasRequiredFields(field->message_type(), already_seen)) {
124        return true;
125      }
126    }
127  }
128
129  return false;
130}
131
132static bool HasRequiredFields(const Descriptor* type) {
133  hash_set<const Descriptor*> already_seen;
134  return HasRequiredFields(type, &already_seen);
135}
136
137}  // namespace
138
139// ===================================================================
140
141MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
142  : params_(params),
143    descriptor_(descriptor),
144    field_generators_(descriptor, params) {
145}
146
147MessageGenerator::~MessageGenerator() {}
148
149void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
150  // Generate static members for all nested types.
151  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
152    // TODO(kenton):  Reuse MessageGenerator objects?
153    MessageGenerator(descriptor_->nested_type(i), params_)
154      .GenerateStaticVariables(printer);
155  }
156}
157
158void MessageGenerator::GenerateStaticVariableInitializers(
159    io::Printer* printer) {
160  // Generate static member initializers for all nested types.
161  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
162    // TODO(kenton):  Reuse MessageGenerator objects?
163    MessageGenerator(descriptor_->nested_type(i), params_)
164      .GenerateStaticVariableInitializers(printer);
165  }
166
167  if (descriptor_->extension_count() != 0) {
168    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
169  }
170}
171
172void MessageGenerator::Generate(io::Printer* printer) {
173  bool is_own_file =
174    params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
175        && !params_.has_java_outer_classname(descriptor_->file()->name()));
176
177#if 0
178  GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
179  GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
180  GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
181  GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
182#endif
183
184  if ((descriptor_->extension_count() != 0)
185      || (descriptor_->extension_range_count() != 0)) {
186    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
187  }
188
189  // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
190  // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
191  // warnings here in the class declaration.
192  printer->Print(
193    "@SuppressWarnings(\"hiding\")\n"
194    "public $modifiers$ final class $classname$ extends\n"
195    "    com.google.protobuf.micro.MessageMicro {\n",
196    "modifiers", is_own_file ? "" : "static",
197    "classname", descriptor_->name());
198  printer->Indent();
199  printer->Print(
200    "public $classname$() {}\n"
201    "\n",
202    "classname", descriptor_->name());
203
204  // Nested types and extensions
205  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
206    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
207  }
208
209  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
210    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
211  }
212
213  // Fields
214  for (int i = 0; i < descriptor_->field_count(); i++) {
215    PrintFieldComment(printer, descriptor_->field(i));
216    printer->Print("public static final int $constant_name$ = $number$;\n",
217      "constant_name", FieldConstantName(descriptor_->field(i)),
218      "number", SimpleItoa(descriptor_->field(i)->number()));
219    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
220    printer->Print("\n");
221  }
222
223  GenerateClear(printer);
224  GenerateIsInitialized(printer);
225  GenerateMessageSerializationMethods(printer);
226  GenerateMergeFromMethods(printer);
227  GenerateParseFromMethods(printer);
228
229  printer->Outdent();
230  printer->Print("}\n\n");
231}
232
233// ===================================================================
234
235void MessageGenerator::
236GenerateMessageSerializationMethods(io::Printer* printer) {
237  scoped_array<const FieldDescriptor*> sorted_fields(
238    SortFieldsByNumber(descriptor_));
239
240  if (descriptor_->extension_range_count() != 0) {
241    GOOGLE_LOG(FATAL) << "Extensions not supported in MICRO_RUNTIME\n";
242  }
243
244  // writeTo only throws an exception if it contains one or more fields to write
245  if (descriptor_->field_count() > 0) {
246    printer->Print(
247      "@Override\n"
248      "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output)\n"
249      "                    throws java.io.IOException {\n");
250  } else {
251    printer->Print(
252      "@Override\n"
253      "public void writeTo(com.google.protobuf.micro.CodedOutputStreamMicro output) {\n");
254  }
255  printer->Indent();
256
257  // Output the fields in sorted order
258  for (int i = 0; i < descriptor_->field_count(); i++) {
259      GenerateSerializeOneField(printer, sorted_fields[i]);
260  }
261
262  printer->Outdent();
263  printer->Print(
264    "}\n"
265    "\n"
266    "private int cachedSize = -1;\n"
267    "@Override\n"
268    "public int getCachedSize() {\n"
269    "  if (cachedSize < 0) {\n"
270    "    // getSerializedSize sets cachedSize\n"
271    "    getSerializedSize();\n"
272    "  }\n"
273    "  return cachedSize;\n"
274    "}\n"
275    "\n"
276    "@Override\n"
277    "public int getSerializedSize() {\n"
278    "  int size = 0;\n");
279  printer->Indent();
280
281  for (int i = 0; i < descriptor_->field_count(); i++) {
282    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
283  }
284
285  printer->Outdent();
286  printer->Print(
287    "  cachedSize = size;\n"
288    "  return size;\n"
289    "}\n"
290    "\n");
291}
292
293void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
294  scoped_array<const FieldDescriptor*> sorted_fields(
295    SortFieldsByNumber(descriptor_));
296
297  if (params_.java_use_vector()) {
298    printer->Print(
299      "@Override\n"
300      "public com.google.protobuf.micro.MessageMicro mergeFrom(\n"
301      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
302      "    throws java.io.IOException {\n",
303      "classname", descriptor_->name());
304  } else {
305    printer->Print(
306      "@Override\n"
307      "public $classname$ mergeFrom(\n"
308      "    com.google.protobuf.micro.CodedInputStreamMicro input)\n"
309      "    throws java.io.IOException {\n",
310      "classname", descriptor_->name());
311  }
312  printer->Indent();
313
314  printer->Print(
315    "while (true) {\n");
316  printer->Indent();
317
318  printer->Print(
319    "int tag = input.readTag();\n"
320    "switch (tag) {\n");
321  printer->Indent();
322
323  printer->Print(
324    "case 0:\n"          // zero signals EOF / limit reached
325    "  return this;\n"
326    "default: {\n"
327    "  if (!parseUnknownField(input, tag)) {\n"
328    "    return this;\n"   // it's an endgroup tag
329    "  }\n"
330    "  break;\n"
331    "}\n");
332
333  for (int i = 0; i < descriptor_->field_count(); i++) {
334    const FieldDescriptor* field = sorted_fields[i];
335    uint32 tag = WireFormatLite::MakeTag(field->number(),
336      WireFormat::WireTypeForField(field));
337
338    printer->Print(
339      "case $tag$: {\n",
340      "tag", SimpleItoa(tag));
341    printer->Indent();
342
343    field_generators_.get(field).GenerateParsingCode(printer);
344
345    printer->Outdent();
346    printer->Print(
347      "  break;\n"
348      "}\n");
349  }
350
351  printer->Outdent();
352  printer->Outdent();
353  printer->Outdent();
354  printer->Print(
355    "    }\n"     // switch (tag)
356    "  }\n"       // while (true)
357    "}\n"
358    "\n");
359}
360
361void MessageGenerator::
362GenerateParseFromMethods(io::Printer* printer) {
363  bool is_own_file =
364    descriptor_->containing_type() == NULL;
365
366  // Note:  These are separate from GenerateMessageSerializationMethods()
367  //   because they need to be generated even for messages that are optimized
368  //   for code size.
369  printer->Print(
370    "public $static$ $classname$ parseFrom(byte[] data)\n"
371    "    throws com.google.protobuf.micro.InvalidProtocolBufferMicroException {\n"
372    "  return ($classname$) (new $classname$().mergeFrom(data));\n"
373    "}\n"
374    "\n"
375    "public $static$ $classname$ parseFrom(\n"
376    "        com.google.protobuf.micro.CodedInputStreamMicro input)\n"
377    "    throws java.io.IOException {\n"
378    "  return new $classname$().mergeFrom(input);\n"
379    "}\n"
380    "\n",
381    "static", (is_own_file ? "static" : ""),
382    "classname", descriptor_->name());
383}
384
385void MessageGenerator::GenerateSerializeOneField(
386    io::Printer* printer, const FieldDescriptor* field) {
387  field_generators_.get(field).GenerateSerializationCode(printer);
388}
389
390void MessageGenerator::GenerateClear(io::Printer* printer) {
391  printer->Print(
392    "public final $classname$ clear() {\n",
393    "classname", descriptor_->name());
394  printer->Indent();
395
396  // Call clear for all of the fields.
397  for (int i = 0; i < descriptor_->field_count(); i++) {
398    const FieldDescriptor* field = descriptor_->field(i);
399
400    printer->Print(
401      "clear$name$();\n",
402      "name", UnderscoresToCapitalizedCamelCase(field));
403  }
404
405  printer->Outdent();
406  printer->Print(
407    "  cachedSize = -1;\n"
408    "  return this;\n"
409    "}\n"
410    "\n");
411}
412
413
414void MessageGenerator::GenerateIsInitialized(io::Printer* printer) {
415  printer->Print(
416    "public final boolean isInitialized() {\n");
417  printer->Indent();
418
419  // Check that all required fields in this message are set.
420  // TODO(kenton):  We can optimize this when we switch to putting all the
421  //   "has" fields into a single bitfield.
422  for (int i = 0; i < descriptor_->field_count(); i++) {
423    const FieldDescriptor* field = descriptor_->field(i);
424
425    if (field->is_required()) {
426      printer->Print(
427        "if (!has$name$) return false;\n",
428        "name", UnderscoresToCapitalizedCamelCase(field));
429    }
430  }
431
432  // Now check that all embedded messages are initialized.
433  for (int i = 0; i < descriptor_->field_count(); i++) {
434    const FieldDescriptor* field = descriptor_->field(i);
435    if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE &&
436        HasRequiredFields(field->message_type())) {
437      switch (field->label()) {
438        case FieldDescriptor::LABEL_REQUIRED:
439          printer->Print(
440            "if (!get$name$().isInitialized()) return false;\n",
441            "type", ClassName(params_, field->message_type()),
442            "name", UnderscoresToCapitalizedCamelCase(field));
443          break;
444        case FieldDescriptor::LABEL_OPTIONAL:
445          printer->Print(
446            "if (has$name$()) {\n"
447            "  if (!get$name$().isInitialized()) return false;\n"
448            "}\n",
449            "type", ClassName(params_, field->message_type()),
450            "name", UnderscoresToCapitalizedCamelCase(field));
451          break;
452        case FieldDescriptor::LABEL_REPEATED:
453          if (params_.java_use_vector()) {
454            printer->Print(
455              "for (int i = 0; i < get$name$List().size(); i++) {\n"
456              "  if (get$name$(i).isInitialized()) return false;\n"
457              "}\n",
458              "type", ClassName(params_, field->message_type()),
459              "name", UnderscoresToCapitalizedCamelCase(field));
460          } else {
461            printer->Print(
462              "for ($type$ element : get$name$List()) {\n"
463              "  if (!element.isInitialized()) return false;\n"
464              "}\n",
465              "type", ClassName(params_, field->message_type()),
466              "name", UnderscoresToCapitalizedCamelCase(field));
467          }
468          break;
469      }
470    }
471  }
472
473  if (descriptor_->extension_range_count() > 0) {
474    printer->Print(
475      "if (!extensionsAreInitialized()) return false;\n");
476  }
477
478  printer->Outdent();
479  printer->Print(
480    "  return true;\n"
481    "}\n"
482    "\n");
483}
484
485// ===================================================================
486
487}  // namespace javamicro
488}  // namespace compiler
489}  // namespace protobuf
490}  // namespace google
491