javanano_message.cc revision 624c448fbef20a1a2fad2289f622b468c25763d1
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/javanano/javanano_message.h>
38#include <google/protobuf/compiler/javanano/javanano_enum.h>
39#include <google/protobuf/compiler/javanano/javanano_extension.h>
40#include <google/protobuf/compiler/javanano/javanano_helpers.h>
41#include <google/protobuf/stubs/strutil.h>
42#include <google/protobuf/io/printer.h>
43#include <google/protobuf/io/coded_stream.h>
44#include <google/protobuf/wire_format.h>
45#include <google/protobuf/descriptor.pb.h>
46
47namespace google {
48namespace protobuf {
49namespace compiler {
50namespace javanano {
51
52using internal::WireFormat;
53using internal::WireFormatLite;
54
55namespace {
56
57void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) {
58  // Print the field's proto-syntax definition as a comment.  We don't want to
59  // print group bodies so we cut off after the first line.
60  string def = field->DebugString();
61  printer->Print("// $def$\n",
62    "def", def.substr(0, def.find_first_of('\n')));
63}
64
65struct FieldOrderingByNumber {
66  inline bool operator()(const FieldDescriptor* a,
67                         const FieldDescriptor* b) const {
68    return a->number() < b->number();
69  }
70};
71
72// Sort the fields of the given Descriptor by number into a new[]'d array
73// and return it.
74const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) {
75  const FieldDescriptor** fields =
76    new const FieldDescriptor*[descriptor->field_count()];
77  for (int i = 0; i < descriptor->field_count(); i++) {
78    fields[i] = descriptor->field(i);
79  }
80  sort(fields, fields + descriptor->field_count(),
81       FieldOrderingByNumber());
82  return fields;
83}
84
85// Get an identifier that uniquely identifies this type within the file.
86// This is used to declare static variables related to this type at the
87// outermost file scope.
88string UniqueFileScopeIdentifier(const Descriptor* descriptor) {
89  return "static_" + StringReplace(descriptor->full_name(), ".", "_", true);
90}
91
92}  // namespace
93
94// ===================================================================
95
96MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params)
97  : params_(params),
98    descriptor_(descriptor),
99    field_generators_(descriptor, params) {
100}
101
102MessageGenerator::~MessageGenerator() {}
103
104void MessageGenerator::GenerateStaticVariables(io::Printer* printer) {
105  // Generate static members for all nested types.
106  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
107    // TODO(kenton):  Reuse MessageGenerator objects?
108    MessageGenerator(descriptor_->nested_type(i), params_)
109      .GenerateStaticVariables(printer);
110  }
111}
112
113void MessageGenerator::GenerateStaticVariableInitializers(
114    io::Printer* printer) {
115  // Generate static member initializers for all nested types.
116  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
117   // TODO(kenton):  Reuse MessageGenerator objects?
118    MessageGenerator(descriptor_->nested_type(i), params_)
119      .GenerateStaticVariableInitializers(printer);
120  }
121}
122
123void MessageGenerator::Generate(io::Printer* printer) {
124  const string& file_name = descriptor_->file()->name();
125  bool is_own_file =
126    params_.java_multiple_files(file_name)
127      && descriptor_->containing_type() == NULL;
128
129  if (!params_.store_unknown_fields() &&
130      (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
131    GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
132        "'store_unknown_fields' generator option is 'true'\n";
133  }
134
135  // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
136  // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
137  // warnings here in the class declaration.
138  printer->Print(
139    "@SuppressWarnings(\"hiding\")\n"
140    "public $modifiers$ final class $classname$ extends\n"
141    "    com.google.protobuf.nano.MessageNano {\n",
142    "modifiers", is_own_file ? "" : "static",
143    "classname", descriptor_->name());
144  printer->Indent();
145  printer->Print(
146    "public static final $classname$ EMPTY_ARRAY[] = {};\n"
147    "public $classname$() {}\n"
148    "\n",
149    "classname", descriptor_->name());
150
151  if (params_.store_unknown_fields()) {
152    printer->Print(
153        "private java.util.List<com.google.protobuf.nano.UnknownFieldData>\n"
154        "    unknownFieldData;\n");
155  }
156
157  // Nested types and extensions
158  for (int i = 0; i < descriptor_->extension_count(); i++) {
159    ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
160  }
161
162  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
163    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
164  }
165
166  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
167    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
168  }
169
170  // Fields
171  for (int i = 0; i < descriptor_->field_count(); i++) {
172    PrintFieldComment(printer, descriptor_->field(i));
173    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
174    printer->Print("\n");
175  }
176
177  GenerateClear(printer);
178
179  // If we have an extension range, generate accessors for extensions.
180  if (params_.store_unknown_fields()
181      && descriptor_->extension_range_count() > 0) {
182    printer->Print(
183      "public <T> T getExtension(com.google.protobuf.nano.Extension<T> extension) {\n"
184      "  return com.google.protobuf.nano.WireFormatNano.getExtension(\n"
185      "      extension, unknownFieldData);\n"
186      "}\n\n"
187      "public <T> void setExtension(com.google.protobuf.nano.Extension<T> extension, T value) {\n"
188      "  if (unknownFieldData == null) {\n"
189      "    unknownFieldData = \n"
190      "        new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
191      "  }\n"
192      "  com.google.protobuf.nano.WireFormatNano.setExtension(\n"
193      "      extension, value, unknownFieldData);\n"
194      "}\n\n");
195  }
196  GenerateMessageSerializationMethods(printer);
197  GenerateMergeFromMethods(printer);
198  GenerateParseFromMethods(printer);
199
200  printer->Outdent();
201  printer->Print("}\n\n");
202}
203
204// ===================================================================
205
206void MessageGenerator::
207GenerateMessageSerializationMethods(io::Printer* printer) {
208  scoped_array<const FieldDescriptor*> sorted_fields(
209    SortFieldsByNumber(descriptor_));
210
211  // writeTo only throws an exception if it contains one or more fields to write
212  if (descriptor_->field_count() > 0 || params_.store_unknown_fields()) {
213    printer->Print(
214      "@Override\n"
215      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
216      "                    throws java.io.IOException {\n");
217  } else {
218    printer->Print(
219      "@Override\n"
220      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) {\n");
221  }
222  printer->Indent();
223
224  // Output the fields in sorted order
225  for (int i = 0; i < descriptor_->field_count(); i++) {
226    GenerateSerializeOneField(printer, sorted_fields[i]);
227  }
228
229  // Write unknown fields.
230  if (params_.store_unknown_fields()) {
231    printer->Print(
232      "com.google.protobuf.nano.WireFormatNano.writeUnknownFields(\n"
233      "    unknownFieldData, output);\n");
234  }
235
236  printer->Outdent();
237  printer->Print(
238    "}\n"
239    "\n"
240    "private int cachedSize = -1;\n"
241    "@Override\n"
242    "public int getCachedSize() {\n"
243    "  if (cachedSize < 0) {\n"
244    "    // getSerializedSize sets cachedSize\n"
245    "    getSerializedSize();\n"
246    "  }\n"
247    "  return cachedSize;\n"
248    "}\n"
249    "\n"
250    "@Override\n"
251    "public int getSerializedSize() {\n"
252    "  int size = 0;\n");
253  printer->Indent();
254
255  for (int i = 0; i < descriptor_->field_count(); i++) {
256    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
257  }
258
259  if (params_.store_unknown_fields()) {
260    printer->Print(
261      "size += com.google.protobuf.nano.WireFormatNano.computeWireSize(unknownFieldData);\n");
262  }
263
264  printer->Outdent();
265  printer->Print(
266    "  cachedSize = size;\n"
267    "  return size;\n"
268    "}\n"
269    "\n");
270}
271
272void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
273  scoped_array<const FieldDescriptor*> sorted_fields(
274    SortFieldsByNumber(descriptor_));
275
276  printer->Print(
277    "@Override\n"
278    "public $classname$ mergeFrom(\n"
279    "    com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
280    "    throws java.io.IOException {\n",
281    "classname", descriptor_->name());
282
283  printer->Indent();
284
285  printer->Print(
286    "while (true) {\n");
287  printer->Indent();
288
289  printer->Print(
290    "int tag = input.readTag();\n"
291    "switch (tag) {\n");
292  printer->Indent();
293
294  printer->Print(
295    "case 0:\n"          // zero signals EOF / limit reached
296    "  return this;\n"
297    "default: {\n");
298
299  printer->Indent();
300  if (params_.store_unknown_fields()) {
301    printer->Print(
302        "if (unknownFieldData == null) {\n"
303        "  unknownFieldData = \n"
304        "      new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
305        "}\n"
306        "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(unknownFieldData, \n"
307        "    input, tag)) {\n"
308        "  return this;\n"
309        "}\n");
310  } else {
311    printer->Print(
312        "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
313        "  return this;\n"   // it's an endgroup tag
314        "}\n");
315  }
316  printer->Print("break;\n");
317  printer->Outdent();
318  printer->Print("}\n");
319
320  for (int i = 0; i < descriptor_->field_count(); i++) {
321    const FieldDescriptor* field = sorted_fields[i];
322    uint32 tag = WireFormatLite::MakeTag(field->number(),
323      WireFormat::WireTypeForField(field));
324
325    printer->Print(
326      "case $tag$: {\n",
327      "tag", SimpleItoa(tag));
328    printer->Indent();
329
330    field_generators_.get(field).GenerateParsingCode(printer);
331
332    printer->Outdent();
333    printer->Print(
334      "  break;\n"
335      "}\n");
336  }
337
338  printer->Outdent();
339  printer->Outdent();
340  printer->Outdent();
341  printer->Print(
342    "    }\n"     // switch (tag)
343    "  }\n"       // while (true)
344    "}\n"
345    "\n");
346}
347
348void MessageGenerator::
349GenerateParseFromMethods(io::Printer* printer) {
350  // Note:  These are separate from GenerateMessageSerializationMethods()
351  //   because they need to be generated even for messages that are optimized
352  //   for code size.
353  printer->Print(
354    "public static $classname$ parseFrom(byte[] data)\n"
355    "    throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
356    "  return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n"
357    "}\n"
358    "\n"
359    "public static $classname$ parseFrom(\n"
360    "        com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
361    "    throws java.io.IOException {\n"
362    "  return new $classname$().mergeFrom(input);\n"
363    "}\n"
364    "\n",
365    "classname", descriptor_->name());
366}
367
368void MessageGenerator::GenerateSerializeOneField(
369    io::Printer* printer, const FieldDescriptor* field) {
370  field_generators_.get(field).GenerateSerializationCode(printer);
371}
372
373void MessageGenerator::GenerateClear(io::Printer* printer) {
374  printer->Print(
375    "public final $classname$ clear() {\n",
376    "classname", descriptor_->name());
377  printer->Indent();
378
379  // Call clear for all of the fields.
380  for (int i = 0; i < descriptor_->field_count(); i++) {
381    const FieldDescriptor* field = descriptor_->field(i);
382
383    if (field->type() == FieldDescriptor::TYPE_BYTES &&
384        !field->default_value_string().empty()) {
385      // Need to clone the default value because it is of a mutable
386      // type.
387      printer->Print(
388        "$name$ = $default$.clone();\n",
389        "name", RenameJavaKeywords(UnderscoresToCamelCase(field)),
390        "default", DefaultValue(params_, field));
391    } else {
392      printer->Print(
393        "$name$ = $default$;\n",
394        "name", RenameJavaKeywords(UnderscoresToCamelCase(field)),
395        "default", DefaultValue(params_, field));
396    }
397
398    if (params_.generate_has() &&
399        field->label() != FieldDescriptor::LABEL_REPEATED &&
400        field->type() != FieldDescriptor::TYPE_GROUP &&
401        field->type() != FieldDescriptor::TYPE_MESSAGE) {
402      printer->Print(
403        "has$capitalized_name$ = false;\n",
404        "capitalized_name", UnderscoresToCapitalizedCamelCase(field));
405    }
406  }
407
408  // Clear unknown fields.
409  if (params_.store_unknown_fields()) {
410    printer->Print("unknownFieldData = null;\n");
411  }
412
413  printer->Outdent();
414  printer->Print(
415    "  cachedSize = -1;\n"
416    "  return this;\n"
417    "}\n"
418    "\n");
419}
420
421// ===================================================================
422
423}  // namespace javanano
424}  // namespace compiler
425}  // namespace protobuf
426}  // namespace google
427