1 /*
2 * Copyright 2014 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // independent from idl_parser, since this code is not needed for most clients
18
19 #include "flatbuffers/code_generators.h"
20 #include "flatbuffers/flatbuffers.h"
21 #include "flatbuffers/idl.h"
22 #include "flatbuffers/util.h"
23
24 #if defined(FLATBUFFERS_CPP98_STL)
25 # include <cctype>
26 #endif // defined(FLATBUFFERS_CPP98_STL)
27
28 namespace flatbuffers {
29 namespace java {
30
31 static TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.", "NaN",
32 "POSITIVE_INFINITY",
33 "NEGATIVE_INFINITY");
34
35 static CommentConfig comment_config = {
36 "/**",
37 " *",
38 " */",
39 };
40
41 class JavaGenerator : public BaseGenerator {
42 public:
JavaGenerator(const Parser & parser,const std::string & path,const std::string & file_name)43 JavaGenerator(const Parser &parser, const std::string &path,
44 const std::string &file_name)
45 : BaseGenerator(parser, path, file_name, "", ".", "java"),
46 cur_name_space_(nullptr) {}
47
48 JavaGenerator &operator=(const JavaGenerator &);
generate()49 bool generate() {
50 std::string one_file_code;
51 cur_name_space_ = parser_.current_namespace_;
52
53 for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
54 ++it) {
55 std::string enumcode;
56 auto &enum_def = **it;
57 if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
58 GenEnum(enum_def, &enumcode);
59 if (parser_.opts.one_file) {
60 one_file_code += enumcode;
61 } else {
62 if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
63 /* needs_includes= */ false))
64 return false;
65 }
66 }
67
68 for (auto it = parser_.structs_.vec.begin();
69 it != parser_.structs_.vec.end(); ++it) {
70 std::string declcode;
71 auto &struct_def = **it;
72 if (!parser_.opts.one_file)
73 cur_name_space_ = struct_def.defined_namespace;
74 GenStruct(struct_def, &declcode);
75 if (parser_.opts.one_file) {
76 one_file_code += declcode;
77 } else {
78 if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
79 /* needs_includes= */ true))
80 return false;
81 }
82 }
83
84 if (parser_.opts.one_file) {
85 return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
86 /* needs_includes= */ true);
87 }
88 return true;
89 }
90
91 // Save out the generated code for a single class while adding
92 // declaration boilerplate.
SaveType(const std::string & defname,const Namespace & ns,const std::string & classcode,bool needs_includes) const93 bool SaveType(const std::string &defname, const Namespace &ns,
94 const std::string &classcode, bool needs_includes) const {
95 if (!classcode.length()) return true;
96
97 std::string code;
98 code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
99
100 std::string namespace_name = FullNamespace(".", ns);
101 if (!namespace_name.empty()) {
102 code += "package " + namespace_name + ";";
103 code += "\n\n";
104 }
105 if (needs_includes) {
106 code +=
107 "import java.nio.*;\nimport java.lang.*;\nimport "
108 "java.util.*;\nimport com.google.flatbuffers.*;\n";
109 if (parser_.opts.gen_nullable) {
110 code += "\nimport javax.annotation.Nullable;\n";
111 }
112 if (parser_.opts.java_checkerframework) {
113 code += "\nimport org.checkerframework.dataflow.qual.Pure;\n";
114 }
115 code += "\n";
116 }
117
118 code += classcode;
119 if (!namespace_name.empty()) code += "";
120 auto filename = NamespaceDir(ns) + defname + ".java";
121 return SaveFile(filename.c_str(), code, false);
122 }
123
CurrentNameSpace() const124 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
125
GenNullableAnnotation(const Type & t) const126 std::string GenNullableAnnotation(const Type &t) const {
127 return parser_.opts.gen_nullable &&
128 !IsScalar(DestinationType(t, true).base_type) &&
129 t.base_type != BASE_TYPE_VECTOR
130 ? " @Nullable "
131 : "";
132 }
133
GenPureAnnotation(const Type & t) const134 std::string GenPureAnnotation(const Type &t) const {
135 return parser_.opts.java_checkerframework &&
136 !IsScalar(DestinationType(t, true).base_type)
137 ? " @Pure "
138 : "";
139 }
140
GenTypeBasic(const Type & type) const141 std::string GenTypeBasic(const Type &type) const {
142 // clang-format off
143 static const char * const java_typename[] = {
144 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \
145 #JTYPE,
146 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
147 #undef FLATBUFFERS_TD
148 };
149 // clang-format on
150 return java_typename[type.base_type];
151 }
152
GenTypePointer(const Type & type) const153 std::string GenTypePointer(const Type &type) const {
154 switch (type.base_type) {
155 case BASE_TYPE_STRING: return "String";
156 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
157 case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
158 case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // else fall thru
159 default: return "Table";
160 }
161 }
162
GenTypeGet(const Type & type) const163 std::string GenTypeGet(const Type &type) const {
164 return IsScalar(type.base_type)
165 ? GenTypeBasic(type)
166 : (IsArray(type) ? GenTypeGet(type.VectorType())
167 : GenTypePointer(type));
168 }
169
170 // Find the destination type the user wants to receive the value in (e.g.
171 // one size higher signed types for unsigned serialized values in Java).
DestinationType(const Type & type,bool vectorelem) const172 Type DestinationType(const Type &type, bool vectorelem) const {
173 switch (type.base_type) {
174 // We use int for both uchar/ushort, since that generally means less
175 // casting than using short for uchar.
176 case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
177 case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
178 case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
179 case BASE_TYPE_ARRAY:
180 case BASE_TYPE_VECTOR:
181 if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
182 FLATBUFFERS_FALLTHROUGH(); // else fall thru
183 default: return type;
184 }
185 }
186
GenOffsetType() const187 std::string GenOffsetType() const { return "int"; }
188
GenOffsetConstruct(const std::string & variable_name) const189 std::string GenOffsetConstruct(const std::string &variable_name) const {
190 return variable_name;
191 }
192
GenVectorOffsetType() const193 std::string GenVectorOffsetType() const { return "int"; }
194
195 // Generate destination type name
GenTypeNameDest(const Type & type) const196 std::string GenTypeNameDest(const Type &type) const {
197 return GenTypeGet(DestinationType(type, true));
198 }
199
200 // Mask to turn serialized value into destination type value.
DestinationMask(const Type & type,bool vectorelem) const201 std::string DestinationMask(const Type &type, bool vectorelem) const {
202 switch (type.base_type) {
203 case BASE_TYPE_UCHAR: return " & 0xFF";
204 case BASE_TYPE_USHORT: return " & 0xFFFF";
205 case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
206 case BASE_TYPE_VECTOR:
207 if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
208 FLATBUFFERS_FALLTHROUGH(); // else fall thru
209 default: return "";
210 }
211 }
212
213 // Casts necessary to correctly read serialized data
DestinationCast(const Type & type) const214 std::string DestinationCast(const Type &type) const {
215 if (IsSeries(type)) {
216 return DestinationCast(type.VectorType());
217 } else {
218 // Cast necessary to correctly read serialized unsigned values.
219 if (type.base_type == BASE_TYPE_UINT) return "(long)";
220 }
221 return "";
222 }
223
224 // Cast statements for mutator method parameters.
225 // In Java, parameters representing unsigned numbers need to be cast down to
226 // their respective type. For example, a long holding an unsigned int value
227 // would be cast down to int before being put onto the buffer.
SourceCast(const Type & type,bool castFromDest) const228 std::string SourceCast(const Type &type, bool castFromDest) const {
229 if (IsSeries(type)) {
230 return SourceCast(type.VectorType(), castFromDest);
231 } else {
232 if (castFromDest) {
233 if (type.base_type == BASE_TYPE_UINT)
234 return "(int)";
235 else if (type.base_type == BASE_TYPE_USHORT)
236 return "(short)";
237 else if (type.base_type == BASE_TYPE_UCHAR)
238 return "(byte)";
239 }
240 }
241 return "";
242 }
243
SourceCast(const Type & type) const244 std::string SourceCast(const Type &type) const {
245 return SourceCast(type, true);
246 }
247
SourceCastBasic(const Type & type,bool castFromDest) const248 std::string SourceCastBasic(const Type &type, bool castFromDest) const {
249 return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
250 }
251
SourceCastBasic(const Type & type) const252 std::string SourceCastBasic(const Type &type) const {
253 return SourceCastBasic(type, true);
254 }
255
GenEnumDefaultValue(const FieldDef & field) const256 std::string GenEnumDefaultValue(const FieldDef &field) const {
257 auto &value = field.value;
258 FLATBUFFERS_ASSERT(value.type.enum_def);
259 auto &enum_def = *value.type.enum_def;
260 auto enum_val = enum_def.FindByValue(value.constant);
261 return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
262 : value.constant;
263 }
264
GenDefaultValue(const FieldDef & field) const265 std::string GenDefaultValue(const FieldDef &field) const {
266 auto &value = field.value;
267 auto constant = field.IsScalarOptional() ? "0" : value.constant;
268 auto longSuffix = "L";
269 switch (value.type.base_type) {
270 case BASE_TYPE_BOOL: return constant == "0" ? "false" : "true";
271 case BASE_TYPE_ULONG: {
272 // Converts the ulong into its bits signed equivalent
273 uint64_t defaultValue = StringToUInt(constant.c_str());
274 return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
275 }
276 case BASE_TYPE_UINT:
277 case BASE_TYPE_LONG: return constant + longSuffix;
278 default:
279 if (IsFloat(value.type.base_type)) {
280 if (field.IsScalarOptional()) {
281 return value.type.base_type == BASE_TYPE_DOUBLE ? "0.0" : "0f";
282 }
283 return JavaFloatGen.GenFloatConstant(field);
284 } else {
285 return constant;
286 }
287 }
288 }
289
GenDefaultValueBasic(const FieldDef & field) const290 std::string GenDefaultValueBasic(const FieldDef &field) const {
291 auto &value = field.value;
292 if (!IsScalar(value.type.base_type)) { return "0"; }
293 return GenDefaultValue(field);
294 }
295
GenEnum(EnumDef & enum_def,std::string * code_ptr) const296 void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
297 std::string &code = *code_ptr;
298 if (enum_def.generated) return;
299
300 // Generate enum definitions of the form:
301 // public static (final) int name = value;
302 // In Java, we use ints rather than the Enum feature, because we want them
303 // to map directly to how they're used in C/C++ and file formats.
304 // That, and Java Enums are expensive, and not universally liked.
305 GenComment(enum_def.doc_comment, code_ptr, &comment_config);
306
307 if (enum_def.attributes.Lookup("private")) {
308 // For Java, we leave the enum unmarked to indicate package-private
309 } else {
310 code += "public ";
311 }
312 code += "final class " + enum_def.name;
313 code += " {\n";
314 code += " private " + enum_def.name + "() { }\n";
315 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
316 auto &ev = **it;
317 GenComment(ev.doc_comment, code_ptr, &comment_config, " ");
318 code += " public static final ";
319 code += GenTypeBasic(DestinationType(enum_def.underlying_type, false));
320 code += " ";
321 code += ev.name + " = ";
322 code += enum_def.ToString(ev);
323 code += ";\n";
324 }
325
326 // Generate a generate string table for enum values.
327 // Problem is, if values are very sparse that could generate really big
328 // tables. Ideally in that case we generate a map lookup instead, but for
329 // the moment we simply don't output a table at all.
330 auto range = enum_def.Distance();
331 // Average distance between values above which we consider a table
332 // "too sparse". Change at will.
333 static const uint64_t kMaxSparseness = 5;
334 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
335 code += "\n public static final String";
336 code += "[] names = { ";
337 auto val = enum_def.Vals().front();
338 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
339 ++it) {
340 auto ev = *it;
341 for (auto k = enum_def.Distance(val, ev); k > 1; --k) code += "\"\", ";
342 val = ev;
343 code += "\"" + (*it)->name + "\", ";
344 }
345 code += "};\n\n";
346 code += " public static ";
347 code += "String";
348 code += " " + MakeCamel("name", false);
349 code += "(int e) { return names[e";
350 if (enum_def.MinValue()->IsNonZero())
351 code += " - " + enum_def.MinValue()->name;
352 code += "]; }\n";
353 }
354
355 // Close the class
356 code += "}\n\n";
357 }
358
359 // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type) const360 std::string GenGetter(const Type &type) const {
361 switch (type.base_type) {
362 case BASE_TYPE_STRING: return "__string";
363 case BASE_TYPE_STRUCT: return "__struct";
364 case BASE_TYPE_UNION: return "__union";
365 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
366 case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
367 default: {
368 std::string getter = "bb.get";
369 if (type.base_type == BASE_TYPE_BOOL) {
370 getter = "0!=" + getter;
371 } else if (GenTypeBasic(type) != "byte") {
372 getter += MakeCamel(GenTypeBasic(type));
373 }
374 return getter;
375 }
376 }
377 }
378
379 // Returns the function name that is able to read a value of the given type.
GenGetterForLookupByKey(flatbuffers::FieldDef * key_field,const std::string & data_buffer,const char * num=nullptr) const380 std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
381 const std::string &data_buffer,
382 const char *num = nullptr) const {
383 auto type = key_field->value.type;
384 auto dest_mask = DestinationMask(type, true);
385 auto dest_cast = DestinationCast(type);
386 auto getter = data_buffer + ".get";
387 if (GenTypeBasic(type) != "byte") {
388 getter += MakeCamel(GenTypeBasic(type));
389 }
390 getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
391 dest_mask;
392 return getter;
393 }
394
395 // Direct mutation is only allowed for scalar fields.
396 // Hence a setter method will only be generated for such fields.
GenSetter(const Type & type) const397 std::string GenSetter(const Type &type) const {
398 if (IsScalar(type.base_type)) {
399 std::string setter = "bb.put";
400 if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
401 setter += MakeCamel(GenTypeBasic(type));
402 }
403 return setter;
404 } else {
405 return "";
406 }
407 }
408
409 // Returns the method name for use with add/put calls.
GenMethod(const Type & type) const410 std::string GenMethod(const Type &type) const {
411 return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type))
412 : (IsStruct(type) ? "Struct" : "Offset");
413 }
414
415 // Recursively generate arguments for a constructor, to deal with nested
416 // structs.
GenStructArgs(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t array_count=0) const417 void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
418 const char *nameprefix, size_t array_count = 0) const {
419 std::string &code = *code_ptr;
420 for (auto it = struct_def.fields.vec.begin();
421 it != struct_def.fields.vec.end(); ++it) {
422 auto &field = **it;
423 const auto &field_type = field.value.type;
424 const auto array_field = IsArray(field_type);
425 const auto &type = array_field ? field_type.VectorType()
426 : DestinationType(field_type, false);
427 const auto array_cnt = array_field ? (array_count + 1) : array_count;
428 if (IsStruct(type)) {
429 // Generate arguments for a struct inside a struct. To ensure names
430 // don't clash, and to make it obvious these arguments are constructing
431 // a nested struct, prefix the name with the field name.
432 GenStructArgs(*field_type.struct_def, code_ptr,
433 (nameprefix + (field.name + "_")).c_str(), array_cnt);
434 } else {
435 code += ", ";
436 code += GenTypeBasic(type);
437 for (size_t i = 0; i < array_cnt; i++) code += "[]";
438 code += " ";
439 code += nameprefix;
440 code += MakeCamel(field.name, false);
441 }
442 }
443 }
444
445 // Recusively generate struct construction statements of the form:
446 // builder.putType(name);
447 // and insert manual padding.
GenStructBody(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t index=0,bool in_array=false) const448 void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
449 const char *nameprefix, size_t index = 0,
450 bool in_array = false) const {
451 std::string &code = *code_ptr;
452 std::string indent((index + 1) * 2, ' ');
453 code += indent + " builder.prep(";
454 code += NumToString(struct_def.minalign) + ", ";
455 code += NumToString(struct_def.bytesize) + ");\n";
456 for (auto it = struct_def.fields.vec.rbegin();
457 it != struct_def.fields.vec.rend(); ++it) {
458 auto &field = **it;
459 const auto &field_type = field.value.type;
460 if (field.padding) {
461 code += indent + " builder.pad(";
462 code += NumToString(field.padding) + ");\n";
463 }
464 if (IsStruct(field_type)) {
465 GenStructBody(*field_type.struct_def, code_ptr,
466 (nameprefix + (field.name + "_")).c_str(), index,
467 in_array);
468 } else {
469 const auto &type =
470 IsArray(field_type) ? field_type.VectorType() : field_type;
471 const auto index_var = "_idx" + NumToString(index);
472 if (IsArray(field_type)) {
473 code += indent + " for (int " + index_var + " = ";
474 code += NumToString(field_type.fixed_length);
475 code += "; " + index_var + " > 0; " + index_var + "--) {\n";
476 in_array = true;
477 }
478 if (IsStruct(type)) {
479 GenStructBody(*field_type.struct_def, code_ptr,
480 (nameprefix + (field.name + "_")).c_str(), index + 1,
481 in_array);
482 } else {
483 code += IsArray(field_type) ? " " : "";
484 code += indent + " builder.put";
485 code += GenMethod(type) + "(";
486 code += SourceCast(type);
487 auto argname = nameprefix + MakeCamel(field.name, false);
488 code += argname;
489 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
490 for (size_t i = 0; in_array && i < array_cnt; i++) {
491 code += "[_idx" + NumToString(i) + "-1]";
492 }
493 code += ");\n";
494 }
495 if (IsArray(field_type)) { code += indent + " }\n"; }
496 }
497 }
498 }
499
GenByteBufferLength(const char * bb_name) const500 std::string GenByteBufferLength(const char *bb_name) const {
501 std::string bb_len = bb_name;
502 bb_len += ".capacity()";
503 return bb_len;
504 }
505
GenOffsetGetter(flatbuffers::FieldDef * key_field,const char * num=nullptr) const506 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
507 const char *num = nullptr) const {
508 std::string key_offset = "";
509 key_offset += "__offset(" + NumToString(key_field->value.offset) + ", ";
510 if (num) {
511 key_offset += num;
512 key_offset += ", _bb)";
513 } else {
514 key_offset += GenByteBufferLength("bb");
515 key_offset += " - tableOffset, bb)";
516 }
517 return key_offset;
518 }
519
GenLookupKeyGetter(flatbuffers::FieldDef * key_field) const520 std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
521 std::string key_getter = " ";
522 key_getter += "int tableOffset = ";
523 key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
524 key_getter += ", bb);\n ";
525 if (IsString(key_field->value.type)) {
526 key_getter += "int comp = ";
527 key_getter += "compareStrings(";
528 key_getter += GenOffsetGetter(key_field);
529 key_getter += ", byteKey, bb);\n";
530 } else {
531 auto get_val = GenGetterForLookupByKey(key_field, "bb");
532 key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
533 key_getter += get_val + ";\n";
534 key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
535 }
536 return key_getter;
537 }
538
GenKeyGetter(flatbuffers::FieldDef * key_field) const539 std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
540 std::string key_getter = "";
541 auto data_buffer = "_bb";
542 if (IsString(key_field->value.type)) {
543 key_getter += " return ";
544 key_getter += "";
545 key_getter += "compareStrings(";
546 key_getter += GenOffsetGetter(key_field, "o1") + ", ";
547 key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
548 key_getter += ";";
549 } else {
550 auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
551 key_getter +=
552 "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
553 key_getter +=
554 field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
555 key_getter += " val_2 = ";
556 field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
557 key_getter += field_getter + ";\n";
558 key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
559 }
560 return key_getter;
561 }
562
GenStruct(StructDef & struct_def,std::string * code_ptr) const563 void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
564 if (struct_def.generated) return;
565 std::string &code = *code_ptr;
566
567 // Generate a struct accessor class, with methods of the form:
568 // public type name() { return bb.getType(i + offset); }
569 // or for tables of the form:
570 // public type name() {
571 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
572 // }
573 GenComment(struct_def.doc_comment, code_ptr, &comment_config);
574
575 if (parser_.opts.gen_generated) {
576 code += "@javax.annotation.Generated(value=\"flatc\")\n";
577 }
578 code += "@SuppressWarnings(\"unused\")\n";
579 if (struct_def.attributes.Lookup("private")) {
580 // For Java, we leave the struct unmarked to indicate package-private
581 } else {
582 code += "public ";
583 }
584 code += "final class " + struct_def.name;
585 code += " extends ";
586 code += struct_def.fixed ? "Struct" : "Table";
587 code += " {\n";
588
589 if (!struct_def.fixed) {
590 // Generate verson check method.
591 // Force compile time error if not using the same version runtime.
592 code += " public static void ValidateVersion() {";
593 code += " Constants.";
594 code += "FLATBUFFERS_2_0_0(); ";
595 code += "}\n";
596
597 // Generate a special accessor for the table that when used as the root
598 // of a FlatBuffer
599 std::string method_name = "getRootAs" + struct_def.name;
600 std::string method_signature =
601 " public static " + struct_def.name + " " + method_name;
602
603 // create convenience method that doesn't require an existing object
604 code += method_signature + "(ByteBuffer _bb) ";
605 code += "{ return " + method_name + "(_bb, new " + struct_def.name +
606 "()); }\n";
607
608 // create method that allows object reuse
609 code +=
610 method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
611 code += "_bb.order(ByteOrder.LITTLE_ENDIAN); ";
612 code += "return (obj.__assign(_bb.getInt(_bb.";
613 code += "position()";
614 code += ") + _bb.";
615 code += "position()";
616 code += ", _bb)); }\n";
617 if (parser_.root_struct_def_ == &struct_def) {
618 if (parser_.file_identifier_.length()) {
619 // Check if a buffer has the identifier.
620 code += " public static ";
621 code += "boolean " + struct_def.name;
622 code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
623 code += "__has_identifier(_bb, \"";
624 code += parser_.file_identifier_;
625 code += "\"); }\n";
626 }
627 }
628 }
629 // Generate the __init method that sets the field in a pre-existing
630 // accessor object. This is to allow object reuse.
631 code += " public void __init(int _i, ByteBuffer _bb) ";
632 code += "{ ";
633 code += "__reset(_i, _bb); ";
634 code += "}\n";
635 code +=
636 " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
637 code += "{ __init(_i, _bb); return this; }\n\n";
638 for (auto it = struct_def.fields.vec.begin();
639 it != struct_def.fields.vec.end(); ++it) {
640 auto &field = **it;
641 if (field.deprecated) continue;
642 GenComment(field.doc_comment, code_ptr, &comment_config, " ");
643 std::string type_name = GenTypeGet(field.value.type);
644 std::string type_name_dest = GenTypeNameDest(field.value.type);
645 std::string conditional_cast = "";
646 std::string optional = "";
647 std::string dest_mask = DestinationMask(field.value.type, true);
648 std::string dest_cast = DestinationCast(field.value.type);
649 std::string src_cast = SourceCast(field.value.type);
650 std::string method_start =
651 " public " +
652 (field.IsRequired() ? "" : GenNullableAnnotation(field.value.type)) +
653 GenPureAnnotation(field.value.type) + type_name_dest + optional +
654 " " + MakeCamel(field.name, false);
655 std::string obj = "obj";
656
657 // Most field accessors need to retrieve and test the field offset first,
658 // this is the prefix code for that:
659 auto offset_prefix =
660 IsArray(field.value.type)
661 ? " { return "
662 : (" { int o = __offset(" + NumToString(field.value.offset) +
663 "); return o != 0 ? ");
664 // Generate the accessors that don't do object reuse.
665 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
666 // Calls the accessor that takes an accessor object with a new object.
667 code += method_start + "() { return ";
668 code += MakeCamel(field.name, false);
669 code += "(new ";
670 code += type_name + "()); }\n";
671 } else if (IsVector(field.value.type) &&
672 field.value.type.element == BASE_TYPE_STRUCT) {
673 // Accessors for vectors of structs also take accessor objects, this
674 // generates a variant without that argument.
675 code += method_start + "(int j) { return ";
676 code += MakeCamel(field.name, false);
677 code += "(new " + type_name + "(), j); }\n";
678 }
679
680 if (field.IsScalarOptional()) { code += GenOptionalScalarCheck(field); }
681 std::string getter = dest_cast + GenGetter(field.value.type);
682 code += method_start;
683 std::string default_cast = "";
684 std::string member_suffix = "; ";
685 if (IsScalar(field.value.type.base_type)) {
686 code += "()";
687 member_suffix += "";
688 if (struct_def.fixed) {
689 code += " { return " + getter;
690 code += "(bb_pos + ";
691 code += NumToString(field.value.offset) + ")";
692 code += dest_mask;
693 } else {
694 code += offset_prefix + getter;
695 code += "(o + bb_pos)" + dest_mask;
696 code += " : " + default_cast;
697 code += GenDefaultValue(field);
698 }
699 } else {
700 switch (field.value.type.base_type) {
701 case BASE_TYPE_STRUCT:
702 code += "(" + type_name + " obj)";
703 if (struct_def.fixed) {
704 code += " { return " + obj + ".__assign(";
705 code += "bb_pos + " + NumToString(field.value.offset) + ", ";
706 code += "bb)";
707 } else {
708 code += offset_prefix + conditional_cast;
709 code += obj + ".__assign(";
710 code += field.value.type.struct_def->fixed
711 ? "o + bb_pos"
712 : "__indirect(o + bb_pos)";
713 code += ", bb) : null";
714 }
715 break;
716 case BASE_TYPE_STRING:
717 code += "()";
718 member_suffix += "";
719 code += offset_prefix + getter + "(o + ";
720 code += "bb_pos) : null";
721 break;
722 case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru
723 case BASE_TYPE_VECTOR: {
724 auto vectortype = field.value.type.VectorType();
725 code += "(";
726 if (vectortype.base_type == BASE_TYPE_STRUCT) {
727 code += type_name + " obj, ";
728 getter = obj + ".__assign";
729 } else if (vectortype.base_type == BASE_TYPE_UNION) {
730 code += type_name + " obj, ";
731 }
732 code += "int j)";
733 const auto body = offset_prefix + conditional_cast + getter + "(";
734 if (vectortype.base_type == BASE_TYPE_UNION) {
735 code += body + "obj, ";
736 } else {
737 code += body;
738 }
739 std::string index;
740 if (IsArray(field.value.type)) {
741 index += "bb_pos + " + NumToString(field.value.offset) + " + ";
742 } else {
743 index += "__vector(o) + ";
744 }
745 index += "j * " + NumToString(InlineSize(vectortype));
746 if (vectortype.base_type == BASE_TYPE_STRUCT) {
747 code += vectortype.struct_def->fixed
748 ? index
749 : "__indirect(" + index + ")";
750 code += ", bb";
751 } else {
752 code += index;
753 }
754 code += ")" + dest_mask;
755 if (!IsArray(field.value.type)) {
756 code += " : ";
757 code +=
758 field.value.type.element == BASE_TYPE_BOOL
759 ? "false"
760 : (IsScalar(field.value.type.element) ? default_cast + "0"
761 : "null");
762 }
763
764 break;
765 }
766 case BASE_TYPE_UNION:
767 code += "(" + type_name + " obj)" + offset_prefix + getter;
768 code += "(obj, o + bb_pos) : null";
769 break;
770 default: FLATBUFFERS_ASSERT(0);
771 }
772 }
773 code += member_suffix;
774 code += "}\n";
775 if (IsVector(field.value.type)) {
776 code += " public int " + MakeCamel(field.name, false);
777 code += "Length";
778 code += "()";
779 code += offset_prefix;
780 code += "__vector_len(o) : 0; ";
781 code += "";
782 code += "}\n";
783 // See if we should generate a by-key accessor.
784 if (field.value.type.element == BASE_TYPE_STRUCT &&
785 !field.value.type.struct_def->fixed) {
786 auto &sd = *field.value.type.struct_def;
787 auto &fields = sd.fields.vec;
788 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
789 auto &key_field = **kit;
790 if (key_field.key) {
791 auto qualified_name = WrapInNameSpace(sd);
792 code += " public " + qualified_name + " ";
793 code += MakeCamel(field.name, false) + "ByKey(";
794 code += GenTypeNameDest(key_field.value.type) + " key)";
795 code += offset_prefix;
796 code += qualified_name + ".__lookup_by_key(";
797 code += "null, ";
798 code += "__vector(o), key, ";
799 code += "bb) : null; ";
800 code += "}\n";
801 code += " public " + qualified_name + " ";
802 code += MakeCamel(field.name, false) + "ByKey(";
803 code += qualified_name + " obj, ";
804 code += GenTypeNameDest(key_field.value.type) + " key)";
805 code += offset_prefix;
806 code += qualified_name + ".__lookup_by_key(obj, ";
807 code += "__vector(o), key, ";
808 code += "bb) : null; ";
809 code += "}\n";
810 break;
811 }
812 }
813 }
814 }
815 // Generate the accessors for vector of structs with vector access object
816 if (IsVector(field.value.type)) {
817 std::string vector_type_name;
818 const auto &element_base_type = field.value.type.VectorType().base_type;
819 if (IsScalar(element_base_type)) {
820 vector_type_name = MakeCamel(type_name, true) + "Vector";
821 } else if (element_base_type == BASE_TYPE_STRING) {
822 vector_type_name = "StringVector";
823 } else if (element_base_type == BASE_TYPE_UNION) {
824 vector_type_name = "UnionVector";
825 } else {
826 vector_type_name = type_name + ".Vector";
827 }
828 auto vector_method_start = GenNullableAnnotation(field.value.type) +
829 " public " + vector_type_name + optional +
830 " " + MakeCamel(field.name, false) +
831 "Vector";
832 code += vector_method_start + "() { return ";
833 code += MakeCamel(field.name, false) + "Vector";
834 code += "(new " + vector_type_name + "()); }\n";
835 code += vector_method_start + "(" + vector_type_name + " obj)";
836 code += offset_prefix + conditional_cast + obj + ".__assign(";
837 code += "__vector(o), ";
838 if (!IsScalar(element_base_type)) {
839 auto vectortype = field.value.type.VectorType();
840 code += NumToString(InlineSize(vectortype)) + ", ";
841 }
842 code += "bb) : null" + member_suffix + "}\n";
843 }
844 // Generate a ByteBuffer accessor for strings & vectors of scalars.
845 if ((IsVector(field.value.type) &&
846 IsScalar(field.value.type.VectorType().base_type)) ||
847 IsString(field.value.type)) {
848 code += " public ByteBuffer ";
849 code += MakeCamel(field.name, false);
850 code += "AsByteBuffer() { return ";
851 code += "__vector_as_bytebuffer(";
852 code += NumToString(field.value.offset) + ", ";
853 code += NumToString(IsString(field.value.type)
854 ? 1
855 : InlineSize(field.value.type.VectorType()));
856 code += "); }\n";
857 code += " public ByteBuffer ";
858 code += MakeCamel(field.name, false);
859 code += "InByteBuffer(ByteBuffer _bb) { return ";
860 code += "__vector_in_bytebuffer(_bb, ";
861 code += NumToString(field.value.offset) + ", ";
862 code += NumToString(IsString(field.value.type)
863 ? 1
864 : InlineSize(field.value.type.VectorType()));
865 code += "); }\n";
866 }
867 // generate object accessors if is nested_flatbuffer
868 if (field.nested_flatbuffer) {
869 auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
870 auto nested_method_name =
871 MakeCamel(field.name, false) + "As" + field.nested_flatbuffer->name;
872 auto get_nested_method_name = nested_method_name;
873 code += " public " + nested_type_name + " ";
874 code += nested_method_name + "() { return ";
875 code +=
876 get_nested_method_name + "(new " + nested_type_name + "()); }\n";
877 code += " public " + nested_type_name + " ";
878 code += get_nested_method_name + "(";
879 code += nested_type_name + " obj";
880 code += ") { int o = __offset(";
881 code += NumToString(field.value.offset) + "); ";
882 code += "return o != 0 ? " + conditional_cast + obj + ".__assign(";
883 code += "";
884 code += "__indirect(__vector(o)), ";
885 code += "bb) : null; }\n";
886 }
887 // Generate mutators for scalar fields or vectors of scalars.
888 if (parser_.opts.mutable_buffer) {
889 auto is_series = (IsSeries(field.value.type));
890 const auto &underlying_type =
891 is_series ? field.value.type.VectorType() : field.value.type;
892 // Boolean parameters have to be explicitly converted to byte
893 // representation.
894 auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
895 ? "(byte)(" + field.name + " ? 1 : 0)"
896 : field.name;
897 auto mutator_prefix = MakeCamel("mutate", false);
898 // A vector mutator also needs the index of the vector element it should
899 // mutate.
900 auto mutator_params = (is_series ? "(int j, " : "(") +
901 GenTypeNameDest(underlying_type) + " " +
902 field.name + ") { ";
903 auto setter_index =
904 is_series
905 ? (IsArray(field.value.type)
906 ? "bb_pos + " + NumToString(field.value.offset)
907 : "__vector(o)") +
908 +" + j * " + NumToString(InlineSize(underlying_type))
909 : (struct_def.fixed
910 ? "bb_pos + " + NumToString(field.value.offset)
911 : "o + bb_pos");
912 if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
913 code += " public ";
914 code += struct_def.fixed ? "void " : "boolean ";
915 code += mutator_prefix + MakeCamel(field.name, true);
916 code += mutator_params;
917 if (struct_def.fixed) {
918 code += GenSetter(underlying_type) + "(" + setter_index + ", ";
919 code += src_cast + setter_parameter + "); }\n";
920 } else {
921 code += "int o = __offset(";
922 code += NumToString(field.value.offset) + ");";
923 code += " if (o != 0) { " + GenSetter(underlying_type);
924 code += "(" + setter_index + ", " + src_cast + setter_parameter +
925 "); return true; } else { return false; } }\n";
926 }
927 }
928 }
929 if (parser_.opts.java_primitive_has_method &&
930 IsScalar(field.value.type.base_type) && !struct_def.fixed) {
931 auto vt_offset_constant = " public static final int VT_" +
932 MakeScreamingCamel(field.name) + " = " +
933 NumToString(field.value.offset) + ";";
934
935 code += vt_offset_constant;
936 code += "\n";
937 }
938 }
939 code += "\n";
940 flatbuffers::FieldDef *key_field = nullptr;
941 if (struct_def.fixed) {
942 // create a struct constructor function
943 code += " public static " + GenOffsetType() + " ";
944 code += "create";
945 code += struct_def.name + "(FlatBufferBuilder builder";
946 GenStructArgs(struct_def, code_ptr, "");
947 code += ") {\n";
948 GenStructBody(struct_def, code_ptr, "");
949 code += " return ";
950 code += GenOffsetConstruct("builder." + std::string("offset()"));
951 code += ";\n }\n";
952 } else {
953 // Generate a method that creates a table in one go. This is only possible
954 // when the table has no struct fields, since those have to be created
955 // inline, and there's no way to do so in Java.
956 bool has_no_struct_fields = true;
957 int num_fields = 0;
958 for (auto it = struct_def.fields.vec.begin();
959 it != struct_def.fields.vec.end(); ++it) {
960 auto &field = **it;
961 if (field.deprecated) continue;
962 if (IsStruct(field.value.type)) {
963 has_no_struct_fields = false;
964 } else {
965 num_fields++;
966 }
967 }
968 // JVM specifications restrict default constructor params to be < 255.
969 // Longs and doubles take up 2 units, so we set the limit to be < 127.
970 if (has_no_struct_fields && num_fields && num_fields < 127) {
971 // Generate a table constructor of the form:
972 // public static int createName(FlatBufferBuilder builder, args...)
973 code += " public static " + GenOffsetType() + " ";
974 code += "create" + struct_def.name;
975 code += "(FlatBufferBuilder builder";
976 for (auto it = struct_def.fields.vec.begin();
977 it != struct_def.fields.vec.end(); ++it) {
978 auto &field = **it;
979 if (field.deprecated) continue;
980 code += ",\n ";
981 code += GenTypeBasic(DestinationType(field.value.type, false));
982 code += " ";
983 code += field.name;
984 if (!IsScalar(field.value.type.base_type)) code += "Offset";
985 }
986 code += ") {\n builder.";
987 code += "startTable(";
988 code += NumToString(struct_def.fields.vec.size()) + ");\n";
989 for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
990 size; size /= 2) {
991 for (auto it = struct_def.fields.vec.rbegin();
992 it != struct_def.fields.vec.rend(); ++it) {
993 auto &field = **it;
994 if (!field.deprecated &&
995 (!struct_def.sortbysize ||
996 size == SizeOf(field.value.type.base_type))) {
997 code += " " + struct_def.name + ".";
998 code += "add";
999 code += MakeCamel(field.name) + "(builder, " + field.name;
1000 if (!IsScalar(field.value.type.base_type)) code += "Offset";
1001 code += ");\n";
1002 }
1003 }
1004 }
1005 code += " return " + struct_def.name + ".";
1006 code += "end" + struct_def.name;
1007 code += "(builder);\n }\n\n";
1008 }
1009 // Generate a set of static methods that allow table construction,
1010 // of the form:
1011 // public static void addName(FlatBufferBuilder builder, short name)
1012 // { builder.addShort(id, name, default); }
1013 // Unlike the Create function, these always work.
1014 code += " public static void start";
1015 code += struct_def.name;
1016 code += "(FlatBufferBuilder builder) { builder.";
1017 code += "startTable(";
1018 code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1019 for (auto it = struct_def.fields.vec.begin();
1020 it != struct_def.fields.vec.end(); ++it) {
1021 auto &field = **it;
1022 if (field.deprecated) continue;
1023 if (field.key) key_field = &field;
1024 code += " public static void add";
1025 code += MakeCamel(field.name);
1026 code += "(FlatBufferBuilder builder, ";
1027 code += GenTypeBasic(DestinationType(field.value.type, false));
1028 auto argname = MakeCamel(field.name, false);
1029 if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1030 code += " " + argname + ") { builder.add";
1031 code += GenMethod(field.value.type) + "(";
1032 code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
1033 code += SourceCastBasic(field.value.type);
1034 code += argname;
1035 code += ", ";
1036 code += SourceCastBasic(field.value.type);
1037 code += GenDefaultValue(field);
1038 code += "); }\n";
1039 if (IsVector(field.value.type)) {
1040 auto vector_type = field.value.type.VectorType();
1041 auto alignment = InlineAlignment(vector_type);
1042 auto elem_size = InlineSize(vector_type);
1043 if (!IsStruct(vector_type)) {
1044 // generate a method to create a vector from a java array.
1045 if ((vector_type.base_type == BASE_TYPE_CHAR ||
1046 vector_type.base_type == BASE_TYPE_UCHAR)) {
1047 // Handle byte[] and ByteBuffers separately for Java
1048 code += " public static " + GenVectorOffsetType() + " ";
1049 code += "create";
1050 code += MakeCamel(field.name);
1051 code += "Vector(FlatBufferBuilder builder, byte[] data) ";
1052 code += "{ return builder.createByteVector(data); }\n";
1053
1054 code += " public static " + GenVectorOffsetType() + " ";
1055 code += "create";
1056 code += MakeCamel(field.name);
1057 code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
1058 code += "{ return builder.createByteVector(data); }\n";
1059 } else {
1060 code += " public static " + GenVectorOffsetType() + " ";
1061 code += "create";
1062 code += MakeCamel(field.name);
1063 code += "Vector(FlatBufferBuilder builder, ";
1064 code += GenTypeBasic(vector_type) + "[] data) ";
1065 code += "{ builder.startVector(";
1066 code += NumToString(elem_size);
1067 code += ", data.length, ";
1068 code += NumToString(alignment);
1069 code += "); for (int i = data.";
1070 code += "length - 1; i >= 0; i--) builder.";
1071 code += "add";
1072 code += GenMethod(vector_type);
1073 code += "(";
1074 code += SourceCastBasic(vector_type, false);
1075 code += "data[i]";
1076 code += "); return ";
1077 code += "builder.endVector(); }\n";
1078 }
1079 }
1080 // Generate a method to start a vector, data to be added manually
1081 // after.
1082 code += " public static void start";
1083 code += MakeCamel(field.name);
1084 code += "Vector(FlatBufferBuilder builder, int numElems) ";
1085 code += "{ builder.startVector(";
1086 code += NumToString(elem_size);
1087 code += ", numElems, " + NumToString(alignment);
1088 code += "); }\n";
1089 }
1090 }
1091 code += " public static " + GenOffsetType() + " ";
1092 code += "end" + struct_def.name;
1093 code += "(FlatBufferBuilder builder) {\n int o = builder.";
1094 code += "endTable();\n";
1095 for (auto it = struct_def.fields.vec.begin();
1096 it != struct_def.fields.vec.end(); ++it) {
1097 auto &field = **it;
1098 if (!field.deprecated && field.IsRequired()) {
1099 code += " builder.required(o, ";
1100 code += NumToString(field.value.offset);
1101 code += "); // " + field.name + "\n";
1102 }
1103 }
1104 code += " return " + GenOffsetConstruct("o") + ";\n }\n";
1105 if (parser_.root_struct_def_ == &struct_def) {
1106 std::string size_prefix[] = { "", "SizePrefixed" };
1107 for (int i = 0; i < 2; ++i) {
1108 code += " public static void ";
1109 code += "finish" + size_prefix[i] + struct_def.name;
1110 code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType();
1111 code += " offset) {";
1112 code += " builder.finish" + size_prefix[i] + "(offset";
1113
1114 if (parser_.file_identifier_.length())
1115 code += ", \"" + parser_.file_identifier_ + "\"";
1116 code += "); }\n";
1117 }
1118 }
1119 }
1120 // Only generate key compare function for table,
1121 // because `key_field` is not set for struct
1122 if (struct_def.has_key && !struct_def.fixed) {
1123 FLATBUFFERS_ASSERT(key_field);
1124 code += "\n @Override\n protected int keysCompare(";
1125 code += "Integer o1, Integer o2, ByteBuffer _bb) {";
1126 code += GenKeyGetter(key_field);
1127 code += " }\n";
1128
1129 code += "\n public static " + struct_def.name;
1130 code += " __lookup_by_key(";
1131 code += struct_def.name + " obj, ";
1132 code += "int vectorLocation, ";
1133 code += GenTypeNameDest(key_field->value.type);
1134 code += " key, ByteBuffer bb) {\n";
1135 if (IsString(key_field->value.type)) {
1136 code += " byte[] byteKey = ";
1137 code += "key.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n";
1138 }
1139 code += " int span = ";
1140 code += "bb.getInt(vectorLocation - 4);\n";
1141 code += " int start = 0;\n";
1142 code += " while (span != 0) {\n";
1143 code += " int middle = span / 2;\n";
1144 code += GenLookupKeyGetter(key_field);
1145 code += " if (comp > 0) {\n";
1146 code += " span = middle;\n";
1147 code += " } else if (comp < 0) {\n";
1148 code += " middle++;\n";
1149 code += " start += middle;\n";
1150 code += " span -= middle;\n";
1151 code += " } else {\n";
1152 code += " return ";
1153 code += "(obj == null ? new " + struct_def.name + "() : obj)";
1154 code += ".__assign(tableOffset, bb);\n";
1155 code += " }\n }\n";
1156 code += " return null;\n";
1157 code += " }\n";
1158 }
1159 GenVectorAccessObject(struct_def, code_ptr);
1160 code += "}";
1161 code += "\n\n";
1162 }
1163
GenOptionalScalarCheck(FieldDef & field) const1164 std::string GenOptionalScalarCheck(FieldDef &field) const {
1165 if (!field.IsScalarOptional()) return "";
1166 return " public boolean has" + MakeCamel(field.name, true) +
1167 "() { return 0 != __offset(" + NumToString(field.value.offset) +
1168 "); }\n";
1169 }
1170
GenVectorAccessObject(StructDef & struct_def,std::string * code_ptr) const1171 void GenVectorAccessObject(StructDef &struct_def,
1172 std::string *code_ptr) const {
1173 auto &code = *code_ptr;
1174 // Generate a vector of structs accessor class.
1175 code += "\n";
1176 code += " ";
1177 if (!struct_def.attributes.Lookup("private")) code += "public ";
1178 code += "static ";
1179 code += "final ";
1180 code += "class Vector extends ";
1181 code += "BaseVector {\n";
1182
1183 // Generate the __assign method that sets the field in a pre-existing
1184 // accessor object. This is to allow object reuse.
1185 std::string method_indent = " ";
1186 code += method_indent + "public Vector ";
1187 code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1188 code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1189
1190 auto type_name = struct_def.name;
1191 auto method_start = method_indent + "public " + type_name + " get";
1192 // Generate the accessors that don't do object reuse.
1193 code += method_start + "(int j) { return get";
1194 code += "(new " + type_name + "(), j); }\n";
1195 code += method_start + "(" + type_name + " obj, int j) { ";
1196 code += " return obj.__assign(";
1197 std::string index = "__element(j)";
1198 code += struct_def.fixed ? index : "__indirect(" + index + ", bb)";
1199 code += ", bb); }\n";
1200 // See if we should generate a by-key accessor.
1201 if (!struct_def.fixed) {
1202 auto &fields = struct_def.fields.vec;
1203 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1204 auto &key_field = **kit;
1205 if (key_field.key) {
1206 auto nullable_annotation =
1207 parser_.opts.gen_nullable ? "@Nullable " : "";
1208 code += method_indent + nullable_annotation;
1209 code += "public " + type_name + " ";
1210 code += "getByKey(";
1211 code += GenTypeNameDest(key_field.value.type) + " key) { ";
1212 code += " return __lookup_by_key(null, ";
1213 code += "__vector(), key, ";
1214 code += "bb); ";
1215 code += "}\n";
1216 code += method_indent + nullable_annotation;
1217 code += "public " + type_name + " ";
1218 code += "getByKey(";
1219 code += type_name + " obj, ";
1220 code += GenTypeNameDest(key_field.value.type) + " key) { ";
1221 code += " return __lookup_by_key(obj, ";
1222 code += "__vector(), key, ";
1223 code += "bb); ";
1224 code += "}\n";
1225 break;
1226 }
1227 }
1228 }
1229 code += " }\n";
1230 }
1231
1232 // This tracks the current namespace used to determine if a type need to be
1233 // prefixed by its namespace
1234 const Namespace *cur_name_space_;
1235 };
1236 } // namespace java
1237
GenerateJava(const Parser & parser,const std::string & path,const std::string & file_name)1238 bool GenerateJava(const Parser &parser, const std::string &path,
1239 const std::string &file_name) {
1240 java::JavaGenerator generator(parser, path, file_name);
1241 return generator.generate();
1242 }
1243
1244 } // namespace flatbuffers
1245