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