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 <map> 36#include <string> 37 38#include <google/protobuf/compiler/java/java_primitive_field.h> 39#include <google/protobuf/stubs/common.h> 40#include <google/protobuf/compiler/java/java_helpers.h> 41#include <google/protobuf/io/printer.h> 42#include <google/protobuf/wire_format.h> 43#include <google/protobuf/stubs/strutil.h> 44 45namespace google { 46namespace protobuf { 47namespace compiler { 48namespace java { 49 50using internal::WireFormat; 51using internal::WireFormatLite; 52 53namespace { 54 55const char* PrimitiveTypeName(JavaType type) { 56 switch (type) { 57 case JAVATYPE_INT : return "int"; 58 case JAVATYPE_LONG : return "long"; 59 case JAVATYPE_FLOAT : return "float"; 60 case JAVATYPE_DOUBLE : return "double"; 61 case JAVATYPE_BOOLEAN: return "boolean"; 62 case JAVATYPE_STRING : return "java.lang.String"; 63 case JAVATYPE_BYTES : return "com.google.protobuf.ByteString"; 64 case JAVATYPE_ENUM : return NULL; 65 case JAVATYPE_MESSAGE: return NULL; 66 67 // No default because we want the compiler to complain if any new 68 // JavaTypes are added. 69 } 70 71 GOOGLE_LOG(FATAL) << "Can't get here."; 72 return NULL; 73} 74 75bool IsReferenceType(JavaType type) { 76 switch (type) { 77 case JAVATYPE_INT : return false; 78 case JAVATYPE_LONG : return false; 79 case JAVATYPE_FLOAT : return false; 80 case JAVATYPE_DOUBLE : return false; 81 case JAVATYPE_BOOLEAN: return false; 82 case JAVATYPE_STRING : return true; 83 case JAVATYPE_BYTES : return true; 84 case JAVATYPE_ENUM : return true; 85 case JAVATYPE_MESSAGE: return true; 86 87 // No default because we want the compiler to complain if any new 88 // JavaTypes are added. 89 } 90 91 GOOGLE_LOG(FATAL) << "Can't get here."; 92 return false; 93} 94 95const char* GetCapitalizedType(const FieldDescriptor* field) { 96 switch (GetType(field)) { 97 case FieldDescriptor::TYPE_INT32 : return "Int32" ; 98 case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; 99 case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; 100 case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; 101 case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; 102 case FieldDescriptor::TYPE_INT64 : return "Int64" ; 103 case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; 104 case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; 105 case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; 106 case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; 107 case FieldDescriptor::TYPE_FLOAT : return "Float" ; 108 case FieldDescriptor::TYPE_DOUBLE : return "Double" ; 109 case FieldDescriptor::TYPE_BOOL : return "Bool" ; 110 case FieldDescriptor::TYPE_STRING : return "String" ; 111 case FieldDescriptor::TYPE_BYTES : return "Bytes" ; 112 case FieldDescriptor::TYPE_ENUM : return "Enum" ; 113 case FieldDescriptor::TYPE_GROUP : return "Group" ; 114 case FieldDescriptor::TYPE_MESSAGE : return "Message" ; 115 116 // No default because we want the compiler to complain if any new 117 // types are added. 118 } 119 120 GOOGLE_LOG(FATAL) << "Can't get here."; 121 return NULL; 122} 123 124// For encodings with fixed sizes, returns that size in bytes. Otherwise 125// returns -1. 126int FixedSize(FieldDescriptor::Type type) { 127 switch (type) { 128 case FieldDescriptor::TYPE_INT32 : return -1; 129 case FieldDescriptor::TYPE_INT64 : return -1; 130 case FieldDescriptor::TYPE_UINT32 : return -1; 131 case FieldDescriptor::TYPE_UINT64 : return -1; 132 case FieldDescriptor::TYPE_SINT32 : return -1; 133 case FieldDescriptor::TYPE_SINT64 : return -1; 134 case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; 135 case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; 136 case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; 137 case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; 138 case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; 139 case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; 140 141 case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; 142 case FieldDescriptor::TYPE_ENUM : return -1; 143 144 case FieldDescriptor::TYPE_STRING : return -1; 145 case FieldDescriptor::TYPE_BYTES : return -1; 146 case FieldDescriptor::TYPE_GROUP : return -1; 147 case FieldDescriptor::TYPE_MESSAGE : return -1; 148 149 // No default because we want the compiler to complain if any new 150 // types are added. 151 } 152 GOOGLE_LOG(FATAL) << "Can't get here."; 153 return -1; 154} 155 156void SetPrimitiveVariables(const FieldDescriptor* descriptor, 157 map<string, string>* variables) { 158 (*variables)["name"] = 159 UnderscoresToCamelCase(descriptor); 160 (*variables)["capitalized_name"] = 161 UnderscoresToCapitalizedCamelCase(descriptor); 162 (*variables)["number"] = SimpleItoa(descriptor->number()); 163 (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); 164 (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); 165 (*variables)["default"] = DefaultValue(descriptor); 166 (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); 167 (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); 168 (*variables)["tag_size"] = SimpleItoa( 169 WireFormat::TagSize(descriptor->number(), GetType(descriptor))); 170 if (IsReferenceType(GetJavaType(descriptor))) { 171 (*variables)["null_check"] = 172 " if (value == null) {\n" 173 " throw new NullPointerException();\n" 174 " }\n"; 175 } else { 176 (*variables)["null_check"] = ""; 177 } 178 int fixed_size = FixedSize(GetType(descriptor)); 179 if (fixed_size != -1) { 180 (*variables)["fixed_size"] = SimpleItoa(fixed_size); 181 } 182} 183} // namespace 184 185// =================================================================== 186 187PrimitiveFieldGenerator:: 188PrimitiveFieldGenerator(const FieldDescriptor* descriptor) 189 : descriptor_(descriptor) { 190 SetPrimitiveVariables(descriptor, &variables_); 191} 192 193PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} 194 195void PrimitiveFieldGenerator:: 196GenerateMembers(io::Printer* printer) const { 197 printer->Print(variables_, 198 "private boolean has$capitalized_name$;\n" 199 "private $type$ $name$_ = $default$;\n" 200 "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" 201 "public $type$ get$capitalized_name$() { return $name$_; }\n"); 202} 203 204void PrimitiveFieldGenerator:: 205GenerateBuilderMembers(io::Printer* printer) const { 206 printer->Print(variables_, 207 "public boolean has$capitalized_name$() {\n" 208 " return result.has$capitalized_name$();\n" 209 "}\n" 210 "public $type$ get$capitalized_name$() {\n" 211 " return result.get$capitalized_name$();\n" 212 "}\n" 213 "public Builder set$capitalized_name$($type$ value) {\n" 214 "$null_check$" 215 " result.has$capitalized_name$ = true;\n" 216 " result.$name$_ = value;\n" 217 " return this;\n" 218 "}\n" 219 "public Builder clear$capitalized_name$() {\n" 220 " result.has$capitalized_name$ = false;\n"); 221 JavaType type = GetJavaType(descriptor_); 222 if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { 223 // The default value is not a simple literal so we want to avoid executing 224 // it multiple times. Instead, get the default out of the default instance. 225 printer->Print(variables_, 226 " result.$name$_ = getDefaultInstance().get$capitalized_name$();\n"); 227 } else { 228 printer->Print(variables_, 229 " result.$name$_ = $default$;\n"); 230 } 231 printer->Print(variables_, 232 " return this;\n" 233 "}\n"); 234} 235 236void PrimitiveFieldGenerator:: 237GenerateInitializationCode(io::Printer* printer) const { 238 // Initialized inline. 239} 240 241void PrimitiveFieldGenerator:: 242GenerateMergingCode(io::Printer* printer) const { 243 printer->Print(variables_, 244 "if (other.has$capitalized_name$()) {\n" 245 " set$capitalized_name$(other.get$capitalized_name$());\n" 246 "}\n"); 247} 248 249void PrimitiveFieldGenerator:: 250GenerateBuildingCode(io::Printer* printer) const { 251 // Nothing to do here for primitive types. 252} 253 254void PrimitiveFieldGenerator:: 255GenerateParsingCode(io::Printer* printer) const { 256 printer->Print(variables_, 257 "set$capitalized_name$(input.read$capitalized_type$());\n"); 258} 259 260void PrimitiveFieldGenerator:: 261GenerateSerializationCode(io::Printer* printer) const { 262 printer->Print(variables_, 263 "if (has$capitalized_name$()) {\n" 264 " output.write$capitalized_type$($number$, get$capitalized_name$());\n" 265 "}\n"); 266} 267 268void PrimitiveFieldGenerator:: 269GenerateSerializedSizeCode(io::Printer* printer) const { 270 printer->Print(variables_, 271 "if (has$capitalized_name$()) {\n" 272 " size += com.google.protobuf.CodedOutputStream\n" 273 " .compute$capitalized_type$Size($number$, get$capitalized_name$());\n" 274 "}\n"); 275} 276 277string PrimitiveFieldGenerator::GetBoxedType() const { 278 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 279} 280 281// =================================================================== 282 283RepeatedPrimitiveFieldGenerator:: 284RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor) 285 : descriptor_(descriptor) { 286 SetPrimitiveVariables(descriptor, &variables_); 287} 288 289RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} 290 291void RepeatedPrimitiveFieldGenerator:: 292GenerateMembers(io::Printer* printer) const { 293 printer->Print(variables_, 294 "private java.util.List<$boxed_type$> $name$_ =\n" 295 " java.util.Collections.emptyList();\n" 296 "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n" 297 " return $name$_;\n" // note: unmodifiable list 298 "}\n" 299 "public int get$capitalized_name$Count() { return $name$_.size(); }\n" 300 "public $type$ get$capitalized_name$(int index) {\n" 301 " return $name$_.get(index);\n" 302 "}\n"); 303 304 if (descriptor_->options().packed() && 305 HasGeneratedMethods(descriptor_->containing_type())) { 306 printer->Print(variables_, 307 "private int $name$MemoizedSerializedSize = -1;\n"); 308 } 309} 310 311void RepeatedPrimitiveFieldGenerator:: 312GenerateBuilderMembers(io::Printer* printer) const { 313 printer->Print(variables_, 314 // Note: We return an unmodifiable list because otherwise the caller 315 // could hold on to the returned list and modify it after the message 316 // has been built, thus mutating the message which is supposed to be 317 // immutable. 318 "public java.util.List<$boxed_type$> get$capitalized_name$List() {\n" 319 " return java.util.Collections.unmodifiableList(result.$name$_);\n" 320 "}\n" 321 "public int get$capitalized_name$Count() {\n" 322 " return result.get$capitalized_name$Count();\n" 323 "}\n" 324 "public $type$ get$capitalized_name$(int index) {\n" 325 " return result.get$capitalized_name$(index);\n" 326 "}\n" 327 "public Builder set$capitalized_name$(int index, $type$ value) {\n" 328 "$null_check$" 329 " result.$name$_.set(index, value);\n" 330 " return this;\n" 331 "}\n" 332 "public Builder add$capitalized_name$($type$ value) {\n" 333 "$null_check$" 334 " if (result.$name$_.isEmpty()) {\n" 335 " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n" 336 " }\n" 337 " result.$name$_.add(value);\n" 338 " return this;\n" 339 "}\n" 340 "public Builder addAll$capitalized_name$(\n" 341 " java.lang.Iterable<? extends $boxed_type$> values) {\n" 342 " if (result.$name$_.isEmpty()) {\n" 343 " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n" 344 " }\n" 345 " super.addAll(values, result.$name$_);\n" 346 " return this;\n" 347 "}\n" 348 "public Builder clear$capitalized_name$() {\n" 349 " result.$name$_ = java.util.Collections.emptyList();\n" 350 " return this;\n" 351 "}\n"); 352} 353 354void RepeatedPrimitiveFieldGenerator:: 355GenerateInitializationCode(io::Printer* printer) const { 356 // Initialized inline. 357} 358 359void RepeatedPrimitiveFieldGenerator:: 360GenerateMergingCode(io::Printer* printer) const { 361 printer->Print(variables_, 362 "if (!other.$name$_.isEmpty()) {\n" 363 " if (result.$name$_.isEmpty()) {\n" 364 " result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n" 365 " }\n" 366 " result.$name$_.addAll(other.$name$_);\n" 367 "}\n"); 368} 369 370void RepeatedPrimitiveFieldGenerator:: 371GenerateBuildingCode(io::Printer* printer) const { 372 printer->Print(variables_, 373 "if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n" 374 " result.$name$_ =\n" 375 " java.util.Collections.unmodifiableList(result.$name$_);\n" 376 "}\n"); 377} 378 379void RepeatedPrimitiveFieldGenerator:: 380GenerateParsingCode(io::Printer* printer) const { 381 printer->Print(variables_, 382 "add$capitalized_name$(input.read$capitalized_type$());\n"); 383} 384 385void RepeatedPrimitiveFieldGenerator:: 386GenerateParsingCodeFromPacked(io::Printer* printer) const { 387 printer->Print(variables_, 388 "int length = input.readRawVarint32();\n" 389 "int limit = input.pushLimit(length);\n" 390 "while (input.getBytesUntilLimit() > 0) {\n" 391 " add$capitalized_name$(input.read$capitalized_type$());\n" 392 "}\n" 393 "input.popLimit(limit);\n"); 394} 395 396void RepeatedPrimitiveFieldGenerator:: 397GenerateSerializationCode(io::Printer* printer) const { 398 if (descriptor_->options().packed()) { 399 printer->Print(variables_, 400 "if (get$capitalized_name$List().size() > 0) {\n" 401 " output.writeRawVarint32($tag$);\n" 402 " output.writeRawVarint32($name$MemoizedSerializedSize);\n" 403 "}\n" 404 "for ($type$ element : get$capitalized_name$List()) {\n" 405 " output.write$capitalized_type$NoTag(element);\n" 406 "}\n"); 407 } else { 408 printer->Print(variables_, 409 "for ($type$ element : get$capitalized_name$List()) {\n" 410 " output.write$capitalized_type$($number$, element);\n" 411 "}\n"); 412 } 413} 414 415void RepeatedPrimitiveFieldGenerator:: 416GenerateSerializedSizeCode(io::Printer* printer) const { 417 printer->Print(variables_, 418 "{\n" 419 " int dataSize = 0;\n"); 420 printer->Indent(); 421 422 if (FixedSize(GetType(descriptor_)) == -1) { 423 printer->Print(variables_, 424 "for ($type$ element : get$capitalized_name$List()) {\n" 425 " dataSize += com.google.protobuf.CodedOutputStream\n" 426 " .compute$capitalized_type$SizeNoTag(element);\n" 427 "}\n"); 428 } else { 429 printer->Print(variables_, 430 "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n"); 431 } 432 433 printer->Print( 434 "size += dataSize;\n"); 435 436 if (descriptor_->options().packed()) { 437 printer->Print(variables_, 438 "if (!get$capitalized_name$List().isEmpty()) {\n" 439 " size += $tag_size$;\n" 440 " size += com.google.protobuf.CodedOutputStream\n" 441 " .computeInt32SizeNoTag(dataSize);\n" 442 "}\n"); 443 } else { 444 printer->Print(variables_, 445 "size += $tag_size$ * get$capitalized_name$List().size();\n"); 446 } 447 448 // cache the data size for packed fields. 449 if (descriptor_->options().packed()) { 450 printer->Print(variables_, 451 "$name$MemoizedSerializedSize = dataSize;\n"); 452 } 453 454 printer->Outdent(); 455 printer->Print("}\n"); 456} 457 458string RepeatedPrimitiveFieldGenerator::GetBoxedType() const { 459 return BoxedPrimitiveTypeName(GetJavaType(descriptor_)); 460} 461 462} // namespace java 463} // namespace compiler 464} // namespace protobuf 465} // namespace google 466