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