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