1
// Protocol Buffers - Google's data interchange format
2
// Copyright 2008 Google Inc. All rights reserved.
3
// http://code.google.com/p/protobuf/
5
// Redistribution and use in source and binary forms, with or without
6
// modification, are permitted provided that the following conditions are
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
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.
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.
31
// Author: kenton@google.com (Kenton Varda)
32
// Based on original Protocol Buffers design by
33
// Sanjay Ghemawat, Jeff Dean, and others.
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>
50
using internal::WireFormat;
51
using internal::WireFormatLite;
55
const char* PrimitiveTypeName(JavaType 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;
67
// No default because we want the compiler to complain if any new
68
// JavaTypes are added.
71
GOOGLE_LOG(FATAL) << "Can't get here.";
75
bool IsReferenceType(JavaType 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;
87
// No default because we want the compiler to complain if any new
88
// JavaTypes are added.
91
GOOGLE_LOG(FATAL) << "Can't get here.";
95
const 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" ;
116
// No default because we want the compiler to complain if any new
120
GOOGLE_LOG(FATAL) << "Can't get here.";
124
// For encodings with fixed sizes, returns that size in bytes. Otherwise
126
int FixedSize(FieldDescriptor::Type 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;
141
case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize;
142
case FieldDescriptor::TYPE_ENUM : return -1;
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;
149
// No default because we want the compiler to complain if any new
152
GOOGLE_LOG(FATAL) << "Can't get here.";
156
void 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"
176
(*variables)["null_check"] = "";
178
int fixed_size = FixedSize(GetType(descriptor));
179
if (fixed_size != -1) {
180
(*variables)["fixed_size"] = SimpleItoa(fixed_size);
185
// ===================================================================
187
PrimitiveFieldGenerator::
188
PrimitiveFieldGenerator(const FieldDescriptor* descriptor)
189
: descriptor_(descriptor) {
190
SetPrimitiveVariables(descriptor, &variables_);
193
PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {}
195
void PrimitiveFieldGenerator::
196
GenerateMembers(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
// Avoid double encoding for Java strings
203
// This field does not need to be volatile because ByteString is immutable.
204
// http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#finalRight
205
// However, it seems better to be safe than sorry.
206
if (ShouldUseStringEncodingCache()) {
207
printer->Print(variables_,
208
"private volatile com.google.protobuf.ByteString $name$EncodedCache_;\n");
212
void PrimitiveFieldGenerator::
213
GenerateBuilderMembers(io::Printer* printer) const {
214
printer->Print(variables_,
215
"public boolean has$capitalized_name$() {\n"
216
" return result.has$capitalized_name$();\n"
218
"public $type$ get$capitalized_name$() {\n"
219
" return result.get$capitalized_name$();\n"
221
"public Builder set$capitalized_name$($type$ value) {\n"
223
" result.has$capitalized_name$ = true;\n"
224
" result.$name$_ = value;\n"
227
"public Builder clear$capitalized_name$() {\n"
228
" result.has$capitalized_name$ = false;\n");
229
JavaType type = GetJavaType(descriptor_);
230
if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) {
231
// The default value is not a simple literal so we want to avoid executing
232
// it multiple times. Instead, get the default out of the default instance.
233
printer->Print(variables_,
234
" result.$name$_ = getDefaultInstance().get$capitalized_name$();\n");
236
printer->Print(variables_,
237
" result.$name$_ = $default$;\n");
239
printer->Print(variables_,
244
void PrimitiveFieldGenerator::
245
GenerateInitializationCode(io::Printer* printer) const {
246
// Initialized inline.
249
void PrimitiveFieldGenerator::
250
GenerateMergingCode(io::Printer* printer) const {
251
printer->Print(variables_,
252
"if (other.has$capitalized_name$()) {\n"
253
" set$capitalized_name$(other.get$capitalized_name$());\n"
257
void PrimitiveFieldGenerator::
258
GenerateBuildingCode(io::Printer* printer) const {
259
// Nothing to do here for primitive types.
262
void PrimitiveFieldGenerator::
263
GenerateParsingCode(io::Printer* printer) const {
264
printer->Print(variables_,
265
"set$capitalized_name$(input.read$capitalized_type$());\n");
268
void PrimitiveFieldGenerator::
269
GenerateSerializationCode(io::Printer* printer) const {
270
if (ShouldUseStringEncodingCache()) {
271
// Pass the cached serialized version, then forget it.
272
// The cached version could be null if we didn't compute the size first,
273
// or if there are two threads attempting to serialize simultaneously.
274
// CodedOutputStream.writeStringCached handles this for us.
275
printer->Print(variables_,
276
"if (has$capitalized_name$()) {\n"
277
" output.write$capitalized_type$Cached($number$,\n"
278
" get$capitalized_name$(),\n"
279
" $name$EncodedCache_);\n"
280
" $name$EncodedCache_ = null;\n"
283
printer->Print(variables_,
284
"if (has$capitalized_name$()) {\n"
285
" output.write$capitalized_type$($number$, get$capitalized_name$());\n"
290
void PrimitiveFieldGenerator::
291
GenerateSerializedSizeCode(io::Printer* printer) const {
292
// Avoid double encoding for strings: serialize the string here
293
if (ShouldUseStringEncodingCache()) {
294
printer->Print(variables_,
295
"if (has$capitalized_name$()) {\n"
296
" com.google.protobuf.ByteString serialized = \n"
297
" com.google.protobuf.ByteString.copyFromUtf8(\n"
298
" get$capitalized_name$());\n"
299
" $name$EncodedCache_ = serialized;\n"
300
" size += com.google.protobuf.CodedOutputStream\n"
301
" .computeBytesSize($number$, serialized);\n"
304
printer->Print(variables_,
305
"if (has$capitalized_name$()) {\n"
306
" size += com.google.protobuf.CodedOutputStream\n"
307
" .compute$capitalized_type$Size($number$, get$capitalized_name$());\n"
312
string PrimitiveFieldGenerator::GetBoxedType() const {
313
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
316
bool PrimitiveFieldGenerator::ShouldUseStringEncodingCache() const {
317
return GetType(descriptor_) == FieldDescriptor::TYPE_STRING &&
318
descriptor_->file()->options().optimize_for() == FileOptions::SPEED;
321
// ===================================================================
323
RepeatedPrimitiveFieldGenerator::
324
RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor)
325
: descriptor_(descriptor) {
326
SetPrimitiveVariables(descriptor, &variables_);
329
RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {}
331
void RepeatedPrimitiveFieldGenerator::
332
GenerateMembers(io::Printer* printer) const {
333
printer->Print(variables_,
334
"private java.util.List<$boxed_type$> $name$_ =\n"
335
" java.util.Collections.emptyList();\n"
336
"public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
337
" return $name$_;\n" // note: unmodifiable list
339
"public int get$capitalized_name$Count() { return $name$_.size(); }\n"
340
"public $type$ get$capitalized_name$(int index) {\n"
341
" return $name$_.get(index);\n"
344
if (descriptor_->options().packed() &&
345
HasGeneratedMethods(descriptor_->containing_type())) {
346
printer->Print(variables_,
347
"private int $name$MemoizedSerializedSize = -1;\n");
351
void RepeatedPrimitiveFieldGenerator::
352
GenerateBuilderMembers(io::Printer* printer) const {
353
printer->Print(variables_,
354
// Note: We return an unmodifiable list because otherwise the caller
355
// could hold on to the returned list and modify it after the message
356
// has been built, thus mutating the message which is supposed to be
358
"public java.util.List<$boxed_type$> get$capitalized_name$List() {\n"
359
" return java.util.Collections.unmodifiableList(result.$name$_);\n"
361
"public int get$capitalized_name$Count() {\n"
362
" return result.get$capitalized_name$Count();\n"
364
"public $type$ get$capitalized_name$(int index) {\n"
365
" return result.get$capitalized_name$(index);\n"
367
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
369
" result.$name$_.set(index, value);\n"
372
"public Builder add$capitalized_name$($type$ value) {\n"
374
" if (result.$name$_.isEmpty()) {\n"
375
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
377
" result.$name$_.add(value);\n"
380
"public Builder addAll$capitalized_name$(\n"
381
" java.lang.Iterable<? extends $boxed_type$> values) {\n"
382
" if (result.$name$_.isEmpty()) {\n"
383
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
385
" super.addAll(values, result.$name$_);\n"
388
"public Builder clear$capitalized_name$() {\n"
389
" result.$name$_ = java.util.Collections.emptyList();\n"
394
void RepeatedPrimitiveFieldGenerator::
395
GenerateInitializationCode(io::Printer* printer) const {
396
// Initialized inline.
399
void RepeatedPrimitiveFieldGenerator::
400
GenerateMergingCode(io::Printer* printer) const {
401
printer->Print(variables_,
402
"if (!other.$name$_.isEmpty()) {\n"
403
" if (result.$name$_.isEmpty()) {\n"
404
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
406
" result.$name$_.addAll(other.$name$_);\n"
410
void RepeatedPrimitiveFieldGenerator::
411
GenerateBuildingCode(io::Printer* printer) const {
412
printer->Print(variables_,
413
"if (result.$name$_ != java.util.Collections.EMPTY_LIST) {\n"
414
" result.$name$_ =\n"
415
" java.util.Collections.unmodifiableList(result.$name$_);\n"
419
void RepeatedPrimitiveFieldGenerator::
420
GenerateParsingCode(io::Printer* printer) const {
421
printer->Print(variables_,
422
"add$capitalized_name$(input.read$capitalized_type$());\n");
425
void RepeatedPrimitiveFieldGenerator::
426
GenerateParsingCodeFromPacked(io::Printer* printer) const {
427
printer->Print(variables_,
428
"int length = input.readRawVarint32();\n"
429
"int limit = input.pushLimit(length);\n"
430
"while (input.getBytesUntilLimit() > 0) {\n"
431
" add$capitalized_name$(input.read$capitalized_type$());\n"
433
"input.popLimit(limit);\n");
436
void RepeatedPrimitiveFieldGenerator::
437
GenerateSerializationCode(io::Printer* printer) const {
438
if (descriptor_->options().packed()) {
439
printer->Print(variables_,
440
"if (get$capitalized_name$List().size() > 0) {\n"
441
" output.writeRawVarint32($tag$);\n"
442
" output.writeRawVarint32($name$MemoizedSerializedSize);\n"
444
"for ($type$ element : get$capitalized_name$List()) {\n"
445
" output.write$capitalized_type$NoTag(element);\n"
448
printer->Print(variables_,
449
"for ($type$ element : get$capitalized_name$List()) {\n"
450
" output.write$capitalized_type$($number$, element);\n"
455
void RepeatedPrimitiveFieldGenerator::
456
GenerateSerializedSizeCode(io::Printer* printer) const {
457
printer->Print(variables_,
459
" int dataSize = 0;\n");
462
if (FixedSize(GetType(descriptor_)) == -1) {
463
printer->Print(variables_,
464
"for ($type$ element : get$capitalized_name$List()) {\n"
465
" dataSize += com.google.protobuf.CodedOutputStream\n"
466
" .compute$capitalized_type$SizeNoTag(element);\n"
469
printer->Print(variables_,
470
"dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
474
"size += dataSize;\n");
476
if (descriptor_->options().packed()) {
477
printer->Print(variables_,
478
"if (!get$capitalized_name$List().isEmpty()) {\n"
479
" size += $tag_size$;\n"
480
" size += com.google.protobuf.CodedOutputStream\n"
481
" .computeInt32SizeNoTag(dataSize);\n"
484
printer->Print(variables_,
485
"size += $tag_size$ * get$capitalized_name$List().size();\n");
488
// cache the data size for packed fields.
489
if (descriptor_->options().packed()) {
490
printer->Print(variables_,
491
"$name$MemoizedSerializedSize = dataSize;\n");
495
printer->Print("}\n");
498
string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
499
return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
503
} // namespace compiler
504
} // namespace protobuf
505
} // namespace google