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