javanano_message.cc revision 0e055f079f53b07de3705838a7b4742ce56839f8
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  bool is_own_file =
125    params_.java_multiple_files() || ((descriptor_->containing_type() == NULL)
126        && !params_.has_java_outer_classname(descriptor_->file()->name()));
127
128#if 0
129  GOOGLE_LOG(INFO) << "is_own_file=" << is_own_file;
130  GOOGLE_LOG(INFO) << "containing_type()=" << ((descriptor_->containing_type() == NULL) ? "NULL" : "not null");
131  GOOGLE_LOG(INFO) << "java_multiple_files()=" << params_.java_multiple_files();
132  GOOGLE_LOG(INFO) << "has_java_outer_classname()=" << params_.has_java_outer_classname(file_->name());
133#endif
134
135  if (!params_.store_unknown_fields() &&
136      (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) {
137    GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the "
138        "'store_unknown_fields' generator option is 'true'\n";
139  }
140
141  // Note: Fields (which will be emitted in the loop, below) may have the same names as fields in
142  // the inner or outer class.  This causes Java warnings, but is not fatal, so we suppress those
143  // warnings here in the class declaration.
144  printer->Print(
145    "@SuppressWarnings(\"hiding\")\n"
146    "public $modifiers$ final class $classname$ extends\n"
147    "    com.google.protobuf.nano.MessageNano {\n",
148    "modifiers", is_own_file ? "" : "static",
149    "classname", descriptor_->name());
150  printer->Indent();
151  printer->Print(
152    "public static final $classname$ EMPTY_ARRAY[] = {};\n"
153    "public $classname$() {}\n"
154    "\n",
155    "classname", descriptor_->name());
156
157  if (params_.store_unknown_fields()) {
158    printer->Print(
159        "private java.util.List<com.google.protobuf.nano.UnknownFieldData>\n"
160        "    unknownFieldData;\n");
161  }
162
163  // Nested types and extensions
164  for (int i = 0; i < descriptor_->extension_count(); i++) {
165    ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
166  }
167
168  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
169    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
170  }
171
172  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
173    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
174  }
175
176  // Fields
177  for (int i = 0; i < descriptor_->field_count(); i++) {
178    PrintFieldComment(printer, descriptor_->field(i));
179    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
180    printer->Print("\n");
181  }
182
183  GenerateClear(printer);
184
185  // If we have an extension range, generate accessors for extensions.
186  if (params_.store_unknown_fields()
187      && descriptor_->extension_range_count() > 0) {
188    printer->Print(
189      "public <T> T getExtension(com.google.protobuf.nano.Extension<T> extension) {\n"
190      "  return com.google.protobuf.nano.WireFormatNano.getExtension(\n"
191      "      extension, unknownFieldData);\n"
192      "}\n\n"
193      "public <T> void setExtension(com.google.protobuf.nano.Extension<T> extension, T value) {\n"
194      "  if (unknownFieldData == null) {\n"
195      "    unknownFieldData = \n"
196      "        new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
197      "  }\n"
198      "  com.google.protobuf.nano.WireFormatNano.setExtension(\n"
199      "      extension, value, unknownFieldData);\n"
200      "}\n\n");
201  }
202  GenerateMessageSerializationMethods(printer);
203  GenerateMergeFromMethods(printer);
204  GenerateParseFromMethods(printer);
205
206  printer->Outdent();
207  printer->Print("}\n\n");
208}
209
210// ===================================================================
211
212void MessageGenerator::
213GenerateMessageSerializationMethods(io::Printer* printer) {
214  scoped_array<const FieldDescriptor*> sorted_fields(
215    SortFieldsByNumber(descriptor_));
216
217  // writeTo only throws an exception if it contains one or more fields to write
218  if (descriptor_->field_count() > 0 || params_.store_unknown_fields()) {
219    printer->Print(
220      "@Override\n"
221      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
222      "                    throws java.io.IOException {\n");
223  } else {
224    printer->Print(
225      "@Override\n"
226      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) {\n");
227  }
228  printer->Indent();
229
230  // Output the fields in sorted order
231  for (int i = 0; i < descriptor_->field_count(); i++) {
232    GenerateSerializeOneField(printer, sorted_fields[i]);
233  }
234
235  // Write unknown fields.
236  if (params_.store_unknown_fields()) {
237    printer->Print(
238      "com.google.protobuf.nano.WireFormatNano.writeUnknownFields(\n"
239      "    unknownFieldData, output);\n");
240  }
241
242  printer->Outdent();
243  printer->Print(
244    "}\n"
245    "\n"
246    "private int cachedSize = -1;\n"
247    "@Override\n"
248    "public int getCachedSize() {\n"
249    "  if (cachedSize < 0) {\n"
250    "    // getSerializedSize sets cachedSize\n"
251    "    getSerializedSize();\n"
252    "  }\n"
253    "  return cachedSize;\n"
254    "}\n"
255    "\n"
256    "@Override\n"
257    "public int getSerializedSize() {\n"
258    "  int size = 0;\n");
259  printer->Indent();
260
261  for (int i = 0; i < descriptor_->field_count(); i++) {
262    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
263  }
264
265  if (params_.store_unknown_fields()) {
266    printer->Print(
267      "size += com.google.protobuf.nano.WireFormatNano.computeWireSize(unknownFieldData);\n");
268  }
269
270  printer->Outdent();
271  printer->Print(
272    "  cachedSize = size;\n"
273    "  return size;\n"
274    "}\n"
275    "\n");
276}
277
278void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
279  scoped_array<const FieldDescriptor*> sorted_fields(
280    SortFieldsByNumber(descriptor_));
281
282  printer->Print(
283    "@Override\n"
284    "public $classname$ mergeFrom(\n"
285    "    com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
286    "    throws java.io.IOException {\n",
287    "classname", descriptor_->name());
288
289  printer->Indent();
290
291  printer->Print(
292    "while (true) {\n");
293  printer->Indent();
294
295  printer->Print(
296    "int tag = input.readTag();\n"
297    "switch (tag) {\n");
298  printer->Indent();
299
300  printer->Print(
301    "case 0:\n"          // zero signals EOF / limit reached
302    "  return this;\n"
303    "default: {\n");
304
305  printer->Indent();
306  if (params_.store_unknown_fields()) {
307    printer->Print(
308        "if (unknownFieldData == null) {\n"
309        "  unknownFieldData = \n"
310        "      new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
311        "}\n"
312        "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(unknownFieldData, \n"
313        "    input, tag)) {\n"
314        "  return this;\n"
315        "}\n");
316  } else {
317    printer->Print(
318        "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
319        "  return this;\n"   // it's an endgroup tag
320        "}\n");
321  }
322  printer->Print("break;\n");
323  printer->Outdent();
324  printer->Print("}\n");
325
326  for (int i = 0; i < descriptor_->field_count(); i++) {
327    const FieldDescriptor* field = sorted_fields[i];
328    uint32 tag = WireFormatLite::MakeTag(field->number(),
329      WireFormat::WireTypeForField(field));
330
331    printer->Print(
332      "case $tag$: {\n",
333      "tag", SimpleItoa(tag));
334    printer->Indent();
335
336    field_generators_.get(field).GenerateParsingCode(printer);
337
338    printer->Outdent();
339    printer->Print(
340      "  break;\n"
341      "}\n");
342  }
343
344  printer->Outdent();
345  printer->Outdent();
346  printer->Outdent();
347  printer->Print(
348    "    }\n"     // switch (tag)
349    "  }\n"       // while (true)
350    "}\n"
351    "\n");
352}
353
354void MessageGenerator::
355GenerateParseFromMethods(io::Printer* printer) {
356  bool is_own_file =
357    descriptor_->containing_type() == NULL;
358
359  // Note:  These are separate from GenerateMessageSerializationMethods()
360  //   because they need to be generated even for messages that are optimized
361  //   for code size.
362  printer->Print(
363    "public $static$ $classname$ parseFrom(byte[] data)\n"
364    "    throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n"
365    "  return ($classname$) com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n"
366    "}\n"
367    "\n"
368    "public $static$ $classname$ parseFrom(\n"
369    "        com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
370    "    throws java.io.IOException {\n"
371    "  return new $classname$().mergeFrom(input);\n"
372    "}\n"
373    "\n",
374    "static", (is_own_file ? "static" : ""),
375    "classname", descriptor_->name());
376}
377
378void MessageGenerator::GenerateSerializeOneField(
379    io::Printer* printer, const FieldDescriptor* field) {
380  field_generators_.get(field).GenerateSerializationCode(printer);
381}
382
383void MessageGenerator::GenerateClear(io::Printer* printer) {
384  printer->Print(
385    "public final $classname$ clear() {\n",
386    "classname", descriptor_->name());
387  printer->Indent();
388
389  // Call clear for all of the fields.
390  for (int i = 0; i < descriptor_->field_count(); i++) {
391    const FieldDescriptor* field = descriptor_->field(i);
392
393    if (field->type() == FieldDescriptor::TYPE_BYTES &&
394        !field->default_value_string().empty()) {
395      // Need to clone the default value because it is of a mutable
396      // type.
397      printer->Print(
398        "$name$ = $default$.clone();\n",
399        "name", UnderscoresToCamelCase(field),
400        "default", DefaultValue(params_, field));
401    } else {
402      printer->Print(
403        "$name$ = $default$;\n",
404        "name", UnderscoresToCamelCase(field),
405        "default", DefaultValue(params_, field));
406    }
407  }
408
409  // Clear unknown fields.
410  if (params_.store_unknown_fields()) {
411    printer->Print("unknownFieldData = null;\n");
412  }
413
414  printer->Outdent();
415  printer->Print(
416    "  cachedSize = -1;\n"
417    "  return this;\n"
418    "}\n"
419    "\n");
420}
421
422// ===================================================================
423
424}  // namespace javanano
425}  // namespace compiler
426}  // namespace protobuf
427}  // namespace google
428