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 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 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 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@SuppressWarnings(\"unused\")\n";
116 }
117 if (parser_.opts.gen_generated) {
118 code += "\n@javax.annotation.Generated(value=\"flatc\")\n";
119 }
120 code += classcode;
121 if (!namespace_name.empty()) code += "";
122 auto filename = NamespaceDir(ns) + defname + ".java";
123 return SaveFile(filename.c_str(), code, false);
124 }
125
CurrentNameSpace() const126 const Namespace *CurrentNameSpace() const { return cur_name_space_; }
127
GenNullableAnnotation(const Type & t) const128 std::string GenNullableAnnotation(const Type &t) const {
129 return parser_.opts.gen_nullable &&
130 !IsScalar(DestinationType(t, true).base_type) &&
131 t.base_type != BASE_TYPE_VECTOR
132 ? " @Nullable "
133 : "";
134 }
135
GenPureAnnotation(const Type & t) const136 std::string GenPureAnnotation(const Type &t) const {
137 return parser_.opts.java_checkerframework &&
138 !IsScalar(DestinationType(t, true).base_type)
139 ? " @Pure "
140 : "";
141 }
142
GenTypeBasic(const Type & type) const143 std::string GenTypeBasic(const Type &type) const {
144 // clang-format off
145 static const char * const java_typename[] = {
146 #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \
147 #JTYPE,
148 FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
149 #undef FLATBUFFERS_TD
150 };
151 // clang-format on
152 return java_typename[type.base_type];
153 }
154
GenTypePointer(const Type & type) const155 std::string GenTypePointer(const Type &type) const {
156 switch (type.base_type) {
157 case BASE_TYPE_STRING: return "String";
158 case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
159 case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def);
160 case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // else fall thru
161 default: return "Table";
162 }
163 }
164
GenTypeGet(const Type & type) const165 std::string GenTypeGet(const Type &type) const {
166 return IsScalar(type.base_type)
167 ? GenTypeBasic(type)
168 : (IsArray(type) ? GenTypeGet(type.VectorType())
169 : GenTypePointer(type));
170 }
171
172 // Find the destination type the user wants to receive the value in (e.g.
173 // one size higher signed types for unsigned serialized values in Java).
DestinationType(const Type & type,bool vectorelem) const174 Type DestinationType(const Type &type, bool vectorelem) const {
175 switch (type.base_type) {
176 // We use int for both uchar/ushort, since that generally means less
177 // casting than using short for uchar.
178 case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
179 case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
180 case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
181 case BASE_TYPE_ARRAY:
182 case BASE_TYPE_VECTOR:
183 if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
184 FLATBUFFERS_FALLTHROUGH(); // else fall thru
185 default: return type;
186 }
187 }
188
GenOffsetType() const189 std::string GenOffsetType() const { return "int"; }
190
GenOffsetConstruct(const std::string & variable_name) const191 std::string GenOffsetConstruct(const std::string &variable_name) const {
192 return variable_name;
193 }
194
GenVectorOffsetType() const195 std::string GenVectorOffsetType() const { return "int"; }
196
197 // Generate destination type name
GenTypeNameDest(const Type & type) const198 std::string GenTypeNameDest(const Type &type) const {
199 return GenTypeGet(DestinationType(type, true));
200 }
201
202 // Mask to turn serialized value into destination type value.
DestinationMask(const Type & type,bool vectorelem) const203 std::string DestinationMask(const Type &type, bool vectorelem) const {
204 switch (type.base_type) {
205 case BASE_TYPE_UCHAR: return " & 0xFF";
206 case BASE_TYPE_USHORT: return " & 0xFFFF";
207 case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
208 case BASE_TYPE_VECTOR:
209 if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
210 FLATBUFFERS_FALLTHROUGH(); // else fall thru
211 default: return "";
212 }
213 }
214
215 // Casts necessary to correctly read serialized data
DestinationCast(const Type & type) const216 std::string DestinationCast(const Type &type) const {
217 if (IsSeries(type)) {
218 return DestinationCast(type.VectorType());
219 } else {
220 // Cast necessary to correctly read serialized unsigned values.
221 if (type.base_type == BASE_TYPE_UINT) return "(long)";
222 }
223 return "";
224 }
225
226 // Cast statements for mutator method parameters.
227 // In Java, parameters representing unsigned numbers need to be cast down to
228 // their respective type. For example, a long holding an unsigned int value
229 // would be cast down to int before being put onto the buffer. In C#, one cast
230 // directly cast an Enum to its underlying type, which is essential before
231 // putting it onto the buffer.
SourceCast(const Type & type,bool castFromDest) const232 std::string SourceCast(const Type &type, bool castFromDest) const {
233 if (IsSeries(type)) {
234 return SourceCast(type.VectorType(), castFromDest);
235 } else {
236 if (castFromDest) {
237 if (type.base_type == BASE_TYPE_UINT)
238 return "(int)";
239 else if (type.base_type == BASE_TYPE_USHORT)
240 return "(short)";
241 else if (type.base_type == BASE_TYPE_UCHAR)
242 return "(byte)";
243 }
244 }
245 return "";
246 }
247
SourceCast(const Type & type) const248 std::string SourceCast(const Type &type) const {
249 return SourceCast(type, true);
250 }
251
SourceCastBasic(const Type & type,bool castFromDest) const252 std::string SourceCastBasic(const Type &type, bool castFromDest) const {
253 return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
254 }
255
SourceCastBasic(const Type & type) const256 std::string SourceCastBasic(const Type &type) const {
257 return SourceCastBasic(type, true);
258 }
259
GenEnumDefaultValue(const FieldDef & field) const260 std::string GenEnumDefaultValue(const FieldDef &field) const {
261 auto &value = field.value;
262 FLATBUFFERS_ASSERT(value.type.enum_def);
263 auto &enum_def = *value.type.enum_def;
264 auto enum_val = enum_def.FindByValue(value.constant);
265 return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
266 : value.constant;
267 }
268
GenDefaultValue(const FieldDef & field) const269 std::string GenDefaultValue(const FieldDef &field) const {
270 auto &value = field.value;
271 auto longSuffix = "L";
272 switch (value.type.base_type) {
273 case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
274 case BASE_TYPE_ULONG: {
275 // Converts the ulong into its bits signed equivalent
276 uint64_t defaultValue = StringToUInt(value.constant.c_str());
277 return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
278 }
279 case BASE_TYPE_UINT:
280 case BASE_TYPE_LONG: return value.constant + longSuffix;
281 default:
282 if (IsFloat(value.type.base_type))
283 return JavaFloatGen.GenFloatConstant(field);
284 else
285 return value.constant;
286 }
287 }
288
GenDefaultValueBasic(const FieldDef & field) const289 std::string GenDefaultValueBasic(const FieldDef &field) const {
290 auto &value = field.value;
291 if (!IsScalar(value.type.base_type)) { return "0"; }
292 return GenDefaultValue(field);
293 }
294
GenEnum(EnumDef & enum_def,std::string * code_ptr) const295 void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
296 std::string &code = *code_ptr;
297 if (enum_def.generated) return;
298
299 // Generate enum definitions of the form:
300 // public static (final) int name = value;
301 // In Java, we use ints rather than the Enum feature, because we want them
302 // to map directly to how they're used in C/C++ and file formats.
303 // That, and Java Enums are expensive, and not universally liked.
304 GenComment(enum_def.doc_comment, code_ptr, &comment_config);
305
306 if (enum_def.attributes.Lookup("private")) {
307 // For Java, we leave the enum unmarked to indicate package-private
308 // For C# we mark the enum as internal
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(enum_def.underlying_type);
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 // We do not do that for C# where this functionality is native.
328 // Problem is, if values are very sparse that could generate really big
329 // tables. Ideally in that case we generate a map lookup instead, but for
330 // the moment we simply don't output a table at all.
331 auto range = enum_def.Distance();
332 // Average distance between values above which we consider a table
333 // "too sparse". Change at will.
334 static const uint64_t kMaxSparseness = 5;
335 if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
336 code += "\n public static final String";
337 code += "[] names = { ";
338 auto val = enum_def.Vals().front();
339 for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
340 ++it) {
341 auto ev = *it;
342 for (auto k = enum_def.Distance(val, ev); k > 1; --k) code += "\"\", ";
343 val = ev;
344 code += "\"" + (*it)->name + "\", ";
345 }
346 code += "};\n\n";
347 code += " public static ";
348 code += "String";
349 code += " " + MakeCamel("name", false);
350 code += "(int e) { return names[e";
351 if (enum_def.MinValue()->IsNonZero())
352 code += " - " + enum_def.MinValue()->name;
353 code += "]; }\n";
354 }
355
356 // Close the class
357 code += "}";
358 // Java does not need the closing semi-colon on class definitions.
359 code += "";
360 code += "\n\n";
361 }
362
363 // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type) const364 std::string GenGetter(const Type &type) const {
365 switch (type.base_type) {
366 case BASE_TYPE_STRING: return "__string";
367 case BASE_TYPE_STRUCT: return "__struct";
368 case BASE_TYPE_UNION: return "__union";
369 case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
370 case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
371 default: {
372 std::string getter = "bb.get";
373 if (type.base_type == BASE_TYPE_BOOL) {
374 getter = "0!=" + getter;
375 } else if (GenTypeBasic(type) != "byte") {
376 getter += MakeCamel(GenTypeBasic(type));
377 }
378 return getter;
379 }
380 }
381 }
382
383 // 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) const384 std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
385 const std::string &data_buffer,
386 const char *num = nullptr) const {
387 auto type = key_field->value.type;
388 auto dest_mask = DestinationMask(type, true);
389 auto dest_cast = DestinationCast(type);
390 auto getter = data_buffer + ".get";
391 if (GenTypeBasic(type) != "byte") {
392 getter += MakeCamel(GenTypeBasic(type));
393 }
394 getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
395 dest_mask;
396 return getter;
397 }
398
399 // Direct mutation is only allowed for scalar fields.
400 // Hence a setter method will only be generated for such fields.
GenSetter(const Type & type) const401 std::string GenSetter(const Type &type) const {
402 if (IsScalar(type.base_type)) {
403 std::string setter = "bb.put";
404 if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
405 setter += MakeCamel(GenTypeBasic(type));
406 }
407 return setter;
408 } else {
409 return "";
410 }
411 }
412
413 // Returns the method name for use with add/put calls.
GenMethod(const Type & type) const414 std::string GenMethod(const Type &type) const {
415 return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type))
416 : (IsStruct(type) ? "Struct" : "Offset");
417 }
418
419 // Recursively generate arguments for a constructor, to deal with nested
420 // structs.
GenStructArgs(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t array_count=0) const421 void GenStructArgs(const StructDef &struct_def, std::string *code_ptr,
422 const char *nameprefix, size_t array_count = 0) const {
423 std::string &code = *code_ptr;
424 for (auto it = struct_def.fields.vec.begin();
425 it != struct_def.fields.vec.end(); ++it) {
426 auto &field = **it;
427 const auto &field_type = field.value.type;
428 const auto array_field = IsArray(field_type);
429 const auto &type = array_field ? field_type.VectorType()
430 : DestinationType(field_type, false);
431 const auto array_cnt = array_field ? (array_count + 1) : array_count;
432 if (IsStruct(type)) {
433 // Generate arguments for a struct inside a struct. To ensure names
434 // don't clash, and to make it obvious these arguments are constructing
435 // a nested struct, prefix the name with the field name.
436 GenStructArgs(*field_type.struct_def, code_ptr,
437 (nameprefix + (field.name + "_")).c_str(), array_cnt);
438 } else {
439 code += ", ";
440 code += GenTypeBasic(type);
441 for (size_t i = 0; i < array_cnt; i++) code += "[]";
442 code += " ";
443 code += nameprefix;
444 code += MakeCamel(field.name, false);
445 }
446 }
447 }
448
449 // Recusively generate struct construction statements of the form:
450 // builder.putType(name);
451 // and insert manual padding.
GenStructBody(const StructDef & struct_def,std::string * code_ptr,const char * nameprefix,size_t index=0,bool in_array=false) const452 void GenStructBody(const StructDef &struct_def, std::string *code_ptr,
453 const char *nameprefix, size_t index = 0,
454 bool in_array = false) const {
455 std::string &code = *code_ptr;
456 std::string indent((index + 1) * 2, ' ');
457 code += indent + " builder.prep(";
458 code += NumToString(struct_def.minalign) + ", ";
459 code += NumToString(struct_def.bytesize) + ");\n";
460 for (auto it = struct_def.fields.vec.rbegin();
461 it != struct_def.fields.vec.rend(); ++it) {
462 auto &field = **it;
463 const auto &field_type = field.value.type;
464 if (field.padding) {
465 code += indent + " builder.pad(";
466 code += NumToString(field.padding) + ");\n";
467 }
468 if (IsStruct(field_type)) {
469 GenStructBody(*field_type.struct_def, code_ptr,
470 (nameprefix + (field.name + "_")).c_str(), index,
471 in_array);
472 } else {
473 const auto &type =
474 IsArray(field_type) ? field_type.VectorType() : field_type;
475 const auto index_var = "_idx" + NumToString(index);
476 if (IsArray(field_type)) {
477 code += indent + " for (int " + index_var + " = ";
478 code += NumToString(field_type.fixed_length);
479 code += "; " + index_var + " > 0; " + index_var + "--) {\n";
480 in_array = true;
481 }
482 if (IsStruct(type)) {
483 GenStructBody(*field_type.struct_def, code_ptr,
484 (nameprefix + (field.name + "_")).c_str(), index + 1,
485 in_array);
486 } else {
487 code += IsArray(field_type) ? " " : "";
488 code += indent + " builder.put";
489 code += GenMethod(type) + "(";
490 code += SourceCast(type);
491 auto argname = nameprefix + MakeCamel(field.name, false);
492 code += argname;
493 size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
494 for (size_t i = 0; in_array && i < array_cnt; i++) {
495 code += "[_idx" + NumToString(i) + "-1]";
496 }
497 code += ");\n";
498 }
499 if (IsArray(field_type)) { code += indent + " }\n"; }
500 }
501 }
502 }
503
GenByteBufferLength(const char * bb_name) const504 std::string GenByteBufferLength(const char *bb_name) const {
505 std::string bb_len = bb_name;
506 bb_len += ".capacity()";
507 return bb_len;
508 }
509
GenOffsetGetter(flatbuffers::FieldDef * key_field,const char * num=nullptr) const510 std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
511 const char *num = nullptr) const {
512 std::string key_offset = "";
513 key_offset += "__offset(" + NumToString(key_field->value.offset) + ", ";
514 if (num) {
515 key_offset += num;
516 key_offset += ", _bb)";
517 } else {
518 key_offset += GenByteBufferLength("bb");
519 key_offset += " - tableOffset, bb)";
520 }
521 return key_offset;
522 }
523
GenLookupKeyGetter(flatbuffers::FieldDef * key_field) const524 std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
525 std::string key_getter = " ";
526 key_getter += "int tableOffset = ";
527 key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
528 key_getter += ", bb);\n ";
529 if (key_field->value.type.base_type == BASE_TYPE_STRING) {
530 key_getter += "int comp = ";
531 key_getter += "compareStrings(";
532 key_getter += GenOffsetGetter(key_field);
533 key_getter += ", byteKey, bb);\n";
534 } else {
535 auto get_val = GenGetterForLookupByKey(key_field, "bb");
536 key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
537 key_getter += get_val + ";\n";
538 key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n";
539 }
540 return key_getter;
541 }
542
GenKeyGetter(flatbuffers::FieldDef * key_field) const543 std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
544 std::string key_getter = "";
545 auto data_buffer = "_bb";
546 if (key_field->value.type.base_type == BASE_TYPE_STRING) {
547 key_getter += " return ";
548 key_getter += "";
549 key_getter += "compareStrings(";
550 key_getter += GenOffsetGetter(key_field, "o1") + ", ";
551 key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
552 key_getter += ";";
553 } else {
554 auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
555 key_getter +=
556 "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
557 key_getter +=
558 field_getter + ";\n " + GenTypeNameDest(key_field->value.type);
559 key_getter += " val_2 = ";
560 field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
561 key_getter += field_getter + ";\n";
562 key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
563 }
564 return key_getter;
565 }
566
GenStruct(StructDef & struct_def,std::string * code_ptr) const567 void GenStruct(StructDef &struct_def, std::string *code_ptr) const {
568 if (struct_def.generated) return;
569 std::string &code = *code_ptr;
570
571 // Generate a struct accessor class, with methods of the form:
572 // public type name() { return bb.getType(i + offset); }
573 // or for tables of the form:
574 // public type name() {
575 // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
576 // }
577 GenComment(struct_def.doc_comment, code_ptr, &comment_config);
578 if (struct_def.attributes.Lookup("private")) {
579 // For Java, we leave the struct unmarked to indicate package-private
580 // For C# we mark the struct as internal
581 } else {
582 code += "public ";
583 }
584 code += "final ";
585 code += "class " + struct_def.name;
586 code += " extends ";
587 code += struct_def.fixed ? "Struct" : "Table";
588 code += " {\n";
589
590 if (!struct_def.fixed) {
591 // Generate verson check method.
592 // Force compile time error if not using the same version runtime.
593 code += " public static void ValidateVersion() {";
594 code += " Constants.";
595 code += "FLATBUFFERS_1_12_0(); ";
596 code += "}\n";
597
598 // Generate a special accessor for the table that when used as the root
599 // of a FlatBuffer
600 std::string method_name = "getRootAs" + struct_def.name;
601 std::string method_signature =
602 " public static " + struct_def.name + " " + method_name;
603
604 // create convenience method that doesn't require an existing object
605 code += method_signature + "(ByteBuffer _bb) ";
606 code += "{ return " + method_name + "(_bb, new " + struct_def.name +
607 "()); }\n";
608
609 // create method that allows object reuse
610 code +=
611 method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { ";
612 code += "_bb.order(ByteOrder.LITTLE_ENDIAN); ";
613 code += "return (obj.__assign(_bb.getInt(_bb.";
614 code += "position()";
615 code += ") + _bb.";
616 code += "position()";
617 code += ", _bb)); }\n";
618 if (parser_.root_struct_def_ == &struct_def) {
619 if (parser_.file_identifier_.length()) {
620 // Check if a buffer has the identifier.
621 code += " public static ";
622 code += "boolean " + struct_def.name;
623 code += "BufferHasIdentifier(ByteBuffer _bb) { return ";
624 code += "__has_identifier(_bb, \"";
625 code += parser_.file_identifier_;
626 code += "\"); }\n";
627 }
628 }
629 }
630 // Generate the __init method that sets the field in a pre-existing
631 // accessor object. This is to allow object reuse.
632 code += " public void __init(int _i, ByteBuffer _bb) ";
633 code += "{ ";
634 code += "__reset(_i, _bb); ";
635 code += "}\n";
636 code +=
637 " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) ";
638 code += "{ __init(_i, _bb); return this; }\n\n";
639 for (auto it = struct_def.fields.vec.begin();
640 it != struct_def.fields.vec.end(); ++it) {
641 auto &field = **it;
642 if (field.deprecated) continue;
643 GenComment(field.doc_comment, code_ptr, &comment_config, " ");
644 std::string type_name = GenTypeGet(field.value.type);
645 std::string type_name_dest = GenTypeNameDest(field.value.type);
646 std::string conditional_cast = "";
647 std::string optional = "";
648 std::string dest_mask = DestinationMask(field.value.type, true);
649 std::string dest_cast = DestinationCast(field.value.type);
650 std::string src_cast = SourceCast(field.value.type);
651 std::string method_start =
652 " public " +
653 (field.required ? "" : GenNullableAnnotation(field.value.type)) +
654 GenPureAnnotation(field.value.type) + type_name_dest + optional +
655 " " + MakeCamel(field.name, false);
656 std::string obj = "obj";
657
658 // Most field accessors need to retrieve and test the field offset first,
659 // this is the prefix code for that:
660 auto offset_prefix =
661 IsArray(field.value.type)
662 ? " { return "
663 : (" { int o = __offset(" + NumToString(field.value.offset) +
664 "); return o != 0 ? ");
665 // Generate the accessors that don't do object reuse.
666 if (field.value.type.base_type == BASE_TYPE_STRUCT) {
667 // Calls the accessor that takes an accessor object with a new object.
668 code += method_start + "() { return ";
669 code += MakeCamel(field.name, false);
670 code += "(new ";
671 code += type_name + "()); }\n";
672 } else if (field.value.type.base_type == BASE_TYPE_VECTOR &&
673 field.value.type.element == BASE_TYPE_STRUCT) {
674 // Accessors for vectors of structs also take accessor objects, this
675 // generates a variant without that argument.
676 code += method_start + "(int j) { return ";
677 code += MakeCamel(field.name, false);
678 code += "(new " + type_name + "(), j); }\n";
679 }
680
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 (field.value.type.base_type == BASE_TYPE_VECTOR) {
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 (field.value.type.base_type == BASE_TYPE_VECTOR) {
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 ((field.value.type.base_type == BASE_TYPE_VECTOR &&
846 IsScalar(field.value.type.VectorType().base_type)) ||
847 field.value.type.base_type == BASE_TYPE_STRING) {
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(field.value.type.base_type == BASE_TYPE_STRING
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(field.value.type.base_type == BASE_TYPE_STRING
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 (field.value.type.base_type == BASE_TYPE_VECTOR) {
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.required) {
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 (key_field->value.type.base_type == BASE_TYPE_STRING) {
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
GenVectorAccessObject(StructDef & struct_def,std::string * code_ptr) const1164 void GenVectorAccessObject(StructDef &struct_def,
1165 std::string *code_ptr) const {
1166 auto &code = *code_ptr;
1167 // Generate a vector of structs accessor class.
1168 code += "\n";
1169 code += " ";
1170 if (!struct_def.attributes.Lookup("private")) code += "public ";
1171 code += "static ";
1172 code += "final ";
1173 code += "class Vector extends ";
1174 code += "BaseVector {\n";
1175
1176 // Generate the __assign method that sets the field in a pre-existing
1177 // accessor object. This is to allow object reuse.
1178 std::string method_indent = " ";
1179 code += method_indent + "public Vector ";
1180 code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1181 code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1182
1183 auto type_name = struct_def.name;
1184 auto method_start = method_indent + "public " + type_name + " get";
1185 // Generate the accessors that don't do object reuse.
1186 code += method_start + "(int j) { return get";
1187 code += "(new " + type_name + "(), j); }\n";
1188 code += method_start + "(" + type_name + " obj, int j) { ";
1189 code += " return obj.__assign(";
1190 std::string index = "__element(j)";
1191 code += struct_def.fixed ? index : "__indirect(" + index + ", bb)";
1192 code += ", bb); }\n";
1193 // See if we should generate a by-key accessor.
1194 if (!struct_def.fixed) {
1195 auto &fields = struct_def.fields.vec;
1196 for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1197 auto &key_field = **kit;
1198 if (key_field.key) {
1199 auto nullable_annotation =
1200 parser_.opts.gen_nullable ? "@Nullable " : "";
1201 code += method_indent + nullable_annotation;
1202 code += "public " + type_name + " ";
1203 code += "getByKey(";
1204 code += GenTypeNameDest(key_field.value.type) + " key) { ";
1205 code += " return __lookup_by_key(null, ";
1206 code += "__vector(), key, ";
1207 code += "bb); ";
1208 code += "}\n";
1209 code += method_indent + nullable_annotation;
1210 code += "public " + type_name + " ";
1211 code += "getByKey(";
1212 code += type_name + " obj, ";
1213 code += GenTypeNameDest(key_field.value.type) + " key) { ";
1214 code += " return __lookup_by_key(obj, ";
1215 code += "__vector(), key, ";
1216 code += "bb); ";
1217 code += "}\n";
1218 break;
1219 }
1220 }
1221 }
1222 code += " }\n";
1223 }
1224
1225 // This tracks the current namespace used to determine if a type need to be
1226 // prefixed by its namespace
1227 const Namespace *cur_name_space_;
1228 };
1229 } // namespace java
1230
GenerateJava(const Parser & parser,const std::string & path,const std::string & file_name)1231 bool GenerateJava(const Parser &parser, const std::string &path,
1232 const std::string &file_name) {
1233 java::JavaGenerator generator(parser, path, file_name);
1234 return generator.generate();
1235 }
1236
1237 } // namespace flatbuffers
1238