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