javanano_message.cc revision 5ae438cf71487d5bc8cb5c0d0e637f976734d110
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    "  clear();\n"
149    "}\n"
150    "\n",
151    "classname", descriptor_->name());
152
153  if (params_.store_unknown_fields()) {
154    printer->Print(
155        "private java.util.List<com.google.protobuf.nano.UnknownFieldData>\n"
156        "    unknownFieldData;\n");
157  }
158
159  // Nested types and extensions
160  for (int i = 0; i < descriptor_->extension_count(); i++) {
161    ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer);
162  }
163
164  for (int i = 0; i < descriptor_->enum_type_count(); i++) {
165    EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer);
166  }
167
168  for (int i = 0; i < descriptor_->nested_type_count(); i++) {
169    MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer);
170  }
171
172  // Integers for bit fields
173  int totalInts = (field_generators_.total_bits() + 31) / 32;
174  for (int i = 0; i < totalInts; i++) {
175    printer->Print("private int $bit_field_name$;\n",
176      "bit_field_name", GetBitFieldName(i));
177  }
178
179  // Fields
180  for (int i = 0; i < descriptor_->field_count(); i++) {
181    PrintFieldComment(printer, descriptor_->field(i));
182    field_generators_.get(descriptor_->field(i)).GenerateMembers(printer);
183    printer->Print("\n");
184  }
185
186  GenerateClear(printer);
187
188  // If we have an extension range, generate accessors for extensions.
189  if (params_.store_unknown_fields()
190      && descriptor_->extension_range_count() > 0) {
191    printer->Print(
192      "public <T> T getExtension(com.google.protobuf.nano.Extension<T> extension) {\n"
193      "  return com.google.protobuf.nano.WireFormatNano.getExtension(\n"
194      "      extension, unknownFieldData);\n"
195      "}\n\n"
196      "public <T> void setExtension(com.google.protobuf.nano.Extension<T> extension, T value) {\n"
197      "  if (unknownFieldData == null) {\n"
198      "    unknownFieldData = \n"
199      "        new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
200      "  }\n"
201      "  com.google.protobuf.nano.WireFormatNano.setExtension(\n"
202      "      extension, value, unknownFieldData);\n"
203      "}\n\n");
204  }
205  GenerateMessageSerializationMethods(printer);
206  GenerateMergeFromMethods(printer);
207  GenerateParseFromMethods(printer);
208
209  printer->Outdent();
210  printer->Print("}\n\n");
211}
212
213// ===================================================================
214
215void MessageGenerator::
216GenerateMessageSerializationMethods(io::Printer* printer) {
217  scoped_array<const FieldDescriptor*> sorted_fields(
218    SortFieldsByNumber(descriptor_));
219
220  // writeTo only throws an exception if it contains one or more fields to write
221  if (descriptor_->field_count() > 0 || params_.store_unknown_fields()) {
222    printer->Print(
223      "@Override\n"
224      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n"
225      "                    throws java.io.IOException {\n");
226  } else {
227    printer->Print(
228      "@Override\n"
229      "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output) {\n");
230  }
231  printer->Indent();
232
233  // Output the fields in sorted order
234  for (int i = 0; i < descriptor_->field_count(); i++) {
235    GenerateSerializeOneField(printer, sorted_fields[i]);
236  }
237
238  // Write unknown fields.
239  if (params_.store_unknown_fields()) {
240    printer->Print(
241      "com.google.protobuf.nano.WireFormatNano.writeUnknownFields(\n"
242      "    unknownFieldData, output);\n");
243  }
244
245  printer->Outdent();
246  printer->Print(
247    "}\n"
248    "\n"
249    "private int cachedSize;\n"
250    "@Override\n"
251    "public int getCachedSize() {\n"
252    "  if (cachedSize < 0) {\n"
253    "    // getSerializedSize sets cachedSize\n"
254    "    getSerializedSize();\n"
255    "  }\n"
256    "  return cachedSize;\n"
257    "}\n"
258    "\n"
259    "@Override\n"
260    "public int getSerializedSize() {\n"
261    "  int size = 0;\n");
262  printer->Indent();
263
264  for (int i = 0; i < descriptor_->field_count(); i++) {
265    field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer);
266  }
267
268  if (params_.store_unknown_fields()) {
269    printer->Print(
270      "size += com.google.protobuf.nano.WireFormatNano.computeWireSize(unknownFieldData);\n");
271  }
272
273  printer->Outdent();
274  printer->Print(
275    "  cachedSize = size;\n"
276    "  return size;\n"
277    "}\n"
278    "\n");
279}
280
281void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
282  scoped_array<const FieldDescriptor*> sorted_fields(
283    SortFieldsByNumber(descriptor_));
284
285  printer->Print(
286    "@Override\n"
287    "public $classname$ mergeFrom(\n"
288    "    com.google.protobuf.nano.CodedInputByteBufferNano input)\n"
289    "    throws java.io.IOException {\n",
290    "classname", descriptor_->name());
291
292  printer->Indent();
293
294  printer->Print(
295    "while (true) {\n");
296  printer->Indent();
297
298  printer->Print(
299    "int tag = input.readTag();\n"
300    "switch (tag) {\n");
301  printer->Indent();
302
303  printer->Print(
304    "case 0:\n"          // zero signals EOF / limit reached
305    "  return this;\n"
306    "default: {\n");
307
308  printer->Indent();
309  if (params_.store_unknown_fields()) {
310    printer->Print(
311        "if (unknownFieldData == null) {\n"
312        "  unknownFieldData = \n"
313        "      new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
314        "}\n"
315        "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(unknownFieldData, \n"
316        "    input, tag)) {\n"
317        "  return this;\n"
318        "}\n");
319  } else {
320    printer->Print(
321        "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n"
322        "  return this;\n"   // it's an endgroup tag
323        "}\n");
324  }
325  printer->Print("break;\n");
326  printer->Outdent();
327  printer->Print("}\n");
328
329  for (int i = 0; i < descriptor_->field_count(); i++) {
330    const FieldDescriptor* field = sorted_fields[i];
331    uint32 tag = WireFormatLite::MakeTag(field->number(),
332      WireFormat::WireTypeForField(field));
333
334    printer->Print(
335      "case $tag$: {\n",
336      "tag", SimpleItoa(tag));
337    printer->Indent();
338
339    field_generators_.get(field).GenerateMergingCode(printer);
340
341    printer->Outdent();
342    printer->Print(
343      "  break;\n"
344      "}\n");
345  }
346
347  printer->Outdent();
348  printer->Outdent();
349  printer->Outdent();
350  printer->Print(
351    "    }\n"     // switch (tag)
352    "  }\n"       // while (true)
353    "}\n"
354    "\n");
355}
356
357void MessageGenerator::
358GenerateParseFromMethods(io::Printer* printer) {
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 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    "classname", descriptor_->name());
375}
376
377void MessageGenerator::GenerateSerializeOneField(
378    io::Printer* printer, const FieldDescriptor* field) {
379  field_generators_.get(field).GenerateSerializationCode(printer);
380}
381
382void MessageGenerator::GenerateClear(io::Printer* printer) {
383  printer->Print(
384    "public final $classname$ clear() {\n",
385    "classname", descriptor_->name());
386  printer->Indent();
387
388  // Clear bit fields.
389  int totalInts = (field_generators_.total_bits() + 31) / 32;
390  for (int i = 0; i < totalInts; i++) {
391    printer->Print("$bit_field_name$ = 0;\n",
392      "bit_field_name", GetBitFieldName(i));
393  }
394
395  // Call clear for all of the fields.
396  for (int i = 0; i < descriptor_->field_count(); i++) {
397    const FieldDescriptor* field = descriptor_->field(i);
398    field_generators_.get(field).GenerateClearCode(printer);
399  }
400
401  // Clear unknown fields.
402  if (params_.store_unknown_fields()) {
403    printer->Print("unknownFieldData = null;\n");
404  }
405
406  printer->Outdent();
407  printer->Print(
408    "  cachedSize = -1;\n"
409    "  return this;\n"
410    "}\n"
411    "\n");
412}
413
414// ===================================================================
415
416}  // namespace javanano
417}  // namespace compiler
418}  // namespace protobuf
419}  // namespace google
420