• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "idl_gen_java.h"
20 
21 #include "flatbuffers/code_generators.h"
22 #include "flatbuffers/flatbuffers.h"
23 #include "flatbuffers/idl.h"
24 #include "flatbuffers/util.h"
25 #include "idl_namer.h"
26 
27 namespace flatbuffers {
28 namespace java {
29 
30 namespace {
31 
JavaDefaultConfig()32 static Namer::Config JavaDefaultConfig() {
33   return {
34     /*types=*/Case::kKeep,
35     /*constants=*/Case::kScreamingSnake,
36     /*methods=*/Case::kLowerCamel,
37     /*functions=*/Case::kLowerCamel,
38     /*fields=*/Case::kLowerCamel,
39     /*variables=*/Case::kLowerCamel,
40     /*variants=*/Case::kKeep,
41     /*enum_variant_seperator=*/".",
42     /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
43     /*namespaces=*/Case::kKeep,
44     /*namespace_seperator=*/".",
45     /*object_prefix=*/"",
46     /*object_suffix=*/"T",
47     /*keyword_prefix=*/"",
48     /*keyword_suffix=*/"_",
49     /*filenames=*/Case::kKeep,
50     /*directories=*/Case::kKeep,
51     /*output_path=*/"",
52     /*filename_suffix=*/"_generated",
53     /*filename_extension=*/".java",
54   };
55 }
56 
JavaKeywords()57 static std::set<std::string> JavaKeywords() {
58   return {
59     "abstract", "continue", "for",        "new",       "switch",
60     "assert",   "default",  "goto",       "package",   "synchronized",
61     "boolean",  "do",       "if",         "private",   "this",
62     "break",    "double",   "implements", "protected", "throw",
63     "byte",     "else",     "import",     "public",    "throws",
64     "case",     "enum",     "instanceof", "return",    "transient",
65     "catch",    "extends",  "int",        "short",     "try",
66     "char",     "final",    "interface",  "static",    "void",
67     "class",    "finally",  "long",       "strictfp",  "volatile",
68     "const",    "float",    "native",     "super",     "while",
69   };
70 }
71 
72 static const TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.",
73                                                       "NaN",
74                                                       "POSITIVE_INFINITY",
75                                                       "NEGATIVE_INFINITY");
76 
77 static const CommentConfig comment_config = {
78   "/**",
79   " *",
80   " */",
81 };
82 
83 }  // namespace
84 
85 class JavaGenerator : public BaseGenerator {
86   struct FieldArrayLength {
87     std::string name;
88     int length;
89   };
90 
91  public:
JavaGenerator(const Parser & parser,const std::string & path,const std::string & file_name,const std::string & package_prefix)92   JavaGenerator(const Parser &parser, const std::string &path,
93                 const std::string &file_name, const std::string &package_prefix)
94       : BaseGenerator(parser, path, file_name, "", ".", "java"),
95         cur_name_space_(nullptr),
96         namer_(WithFlagOptions(JavaDefaultConfig(), parser.opts, path),
97                JavaKeywords()) {
98     if (!package_prefix.empty()) {
99       std::istringstream iss(package_prefix);
100       std::string component;
101       while (std::getline(iss, component, '.')) {
102         package_prefix_ns_.components.push_back(component);
103       }
104       package_prefix_ = package_prefix_ns_.GetFullyQualifiedName("") + ".";
105     }
106   }
107 
108   JavaGenerator &operator=(const JavaGenerator &);
generate()109   bool generate() {
110     std::string one_file_code;
111     cur_name_space_ = parser_.current_namespace_;
112 
113     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
114          ++it) {
115       std::string enumcode;
116       auto &enum_def = **it;
117       if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
118       GenEnum(enum_def, enumcode);
119       if (parser_.opts.one_file) {
120         one_file_code += enumcode;
121       } else {
122         if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode,
123                       /* needs_includes= */ false))
124           return false;
125       }
126 
127       if (parser_.opts.generate_object_based_api && enum_def.is_union) {
128         enumcode = "";
129         GenEnum_ObjectAPI(enum_def, enumcode);
130         auto class_name = namer_.Type(enum_def) + "Union";
131         if (parser_.opts.one_file) {
132           one_file_code += enumcode;
133         } else {
134           if (!SaveType(class_name, *enum_def.defined_namespace, enumcode,
135                         /* needs_includes= */ false))
136             return false;
137         }
138       }
139     }
140 
141     for (auto it = parser_.structs_.vec.begin();
142          it != parser_.structs_.vec.end(); ++it) {
143       std::string declcode;
144       auto &struct_def = **it;
145       if (!parser_.opts.one_file)
146         cur_name_space_ = struct_def.defined_namespace;
147       GenStruct(struct_def, declcode, parser_.opts);
148       if (parser_.opts.one_file) {
149         one_file_code += declcode;
150       } else {
151         if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode,
152                       /* needs_includes= */ true))
153           return false;
154       }
155 
156       if (parser_.opts.generate_object_based_api) {
157         declcode = "";
158         GenStruct_ObjectAPI(struct_def, declcode);
159         auto class_name = namer_.ObjectType(struct_def);
160         if (parser_.opts.one_file) {
161           one_file_code += declcode;
162         } else {
163           if (!SaveType(class_name, *struct_def.defined_namespace, declcode,
164                         /* needs_includes= */ true))
165             return false;
166         }
167       }
168     }
169 
170     if (parser_.opts.one_file) {
171       return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
172                       /* needs_includes= */ true);
173     }
174     return true;
175   }
176 
177   // Save out the generated code for a single class while adding
178   // declaration boilerplate.
SaveType(const std::string & defname,const Namespace & ns,const std::string & classcode,bool needs_includes) const179   bool SaveType(const std::string &defname, const Namespace &ns,
180                 const std::string &classcode, bool needs_includes) const {
181     if (!classcode.length()) return true;
182 
183     std::string code;
184     code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
185 
186     Namespace combined_ns = package_prefix_ns_;
187     std::copy(ns.components.begin(), ns.components.end(),
188               std::back_inserter(combined_ns.components));
189 
190     const std::string namespace_name = FullNamespace(".", combined_ns);
191     if (!namespace_name.empty()) {
192       code += "package " + namespace_name + ";";
193       code += "\n\n";
194     }
195     if (needs_includes) {
196       code +=
197           "import com.google.flatbuffers.BaseVector;\n"
198           "import com.google.flatbuffers.BooleanVector;\n"
199           "import com.google.flatbuffers.ByteVector;\n"
200           "import com.google.flatbuffers.Constants;\n"
201           "import com.google.flatbuffers.DoubleVector;\n"
202           "import com.google.flatbuffers.FlatBufferBuilder;\n"
203           "import com.google.flatbuffers.FloatVector;\n"
204           "import com.google.flatbuffers.IntVector;\n"
205           "import com.google.flatbuffers.LongVector;\n"
206           "import com.google.flatbuffers.ShortVector;\n"
207           "import com.google.flatbuffers.StringVector;\n"
208           "import com.google.flatbuffers.Struct;\n"
209           "import com.google.flatbuffers.Table;\n"
210           "import com.google.flatbuffers.UnionVector;\n"
211           "import java.nio.ByteBuffer;\n"
212           "import java.nio.ByteOrder;\n";
213       if (parser_.opts.gen_nullable) {
214         code += "\nimport javax.annotation.Nullable;\n";
215       }
216       if (parser_.opts.java_checkerframework) {
217         code += "\nimport org.checkerframework.dataflow.qual.Pure;\n";
218       }
219       code += "\n";
220     }
221 
222     code += classcode;
223     if (!namespace_name.empty()) code += "";
224     const std::string dirs = namer_.Directories(combined_ns);
225     EnsureDirExists(dirs);
226     const std::string filename =
227         dirs + namer_.File(defname, /*skips=*/SkipFile::Suffix);
228     return SaveFile(filename.c_str(), code, false);
229   }
230 
CurrentNameSpace() const231   const Namespace *CurrentNameSpace() const { return cur_name_space_; }
232 
GenNullableAnnotation(const Type & t) const233   std::string GenNullableAnnotation(const Type &t) const {
234     return parser_.opts.gen_nullable &&
235                    !IsScalar(DestinationType(t, true).base_type) &&
236                    t.base_type != BASE_TYPE_VECTOR
237                ? " @Nullable "
238                : "";
239   }
240 
GenPureAnnotation(const Type & t) const241   std::string GenPureAnnotation(const Type &t) const {
242     return parser_.opts.java_checkerframework &&
243                    !IsScalar(DestinationType(t, true).base_type)
244                ? " @Pure "
245                : "";
246   }
247 
GenTypeBasic(const Type & type) const248   std::string GenTypeBasic(const Type &type) const {
249     // clang-format off
250     static const char * const java_typename[] = {
251       #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \
252         #JTYPE,
253         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
254       #undef FLATBUFFERS_TD
255     };
256     // clang-format on
257     return java_typename[type.base_type];
258   }
259 
GenTypePointer(const Type & type) const260   std::string GenTypePointer(const Type &type) const {
261     switch (type.base_type) {
262       case BASE_TYPE_STRING: return "String";
263       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
264       case BASE_TYPE_STRUCT:
265         return Prefixed(namer_.NamespacedType(*type.struct_def));
266       case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH();  // else fall thru
267       default: return "Table";
268     }
269   }
270 
GenTypeGet(const Type & type) const271   std::string GenTypeGet(const Type &type) const {
272     return IsScalar(type.base_type)
273                ? GenTypeBasic(type)
274                : (IsArray(type) ? GenTypeGet(type.VectorType())
275                                 : GenTypePointer(type));
276   }
277 
278   // Find the destination type the user wants to receive the value in (e.g.
279   // one size higher signed types for unsigned serialized values in Java).
DestinationType(const Type & type,bool vectorelem) const280   Type DestinationType(const Type &type, bool vectorelem) const {
281     switch (type.base_type) {
282       // We use int for both uchar/ushort, since that generally means less
283       // casting than using short for uchar.
284       case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT);
285       case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT);
286       case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG);
287       case BASE_TYPE_ARRAY:
288       case BASE_TYPE_VECTOR:
289         if (vectorelem) return DestinationType(type.VectorType(), vectorelem);
290         FLATBUFFERS_FALLTHROUGH();  // else fall thru
291       default: return type;
292     }
293   }
294 
GenOffsetType() const295   std::string GenOffsetType() const { return "int"; }
296 
GenOffsetConstruct(const std::string & variable_name) const297   std::string GenOffsetConstruct(const std::string &variable_name) const {
298     return variable_name;
299   }
300 
GenVectorOffsetType() const301   std::string GenVectorOffsetType() const { return "int"; }
302 
303   // Generate destination type name
GenTypeNameDest(const Type & type) const304   std::string GenTypeNameDest(const Type &type) const {
305     return GenTypeGet(DestinationType(type, true));
306   }
307 
308   // Mask to turn serialized value into destination type value.
DestinationMask(const Type & type,bool vectorelem) const309   std::string DestinationMask(const Type &type, bool vectorelem) const {
310     switch (type.base_type) {
311       case BASE_TYPE_UCHAR: return " & 0xFF";
312       case BASE_TYPE_USHORT: return " & 0xFFFF";
313       case BASE_TYPE_UINT: return " & 0xFFFFFFFFL";
314       case BASE_TYPE_VECTOR:
315         if (vectorelem) return DestinationMask(type.VectorType(), vectorelem);
316         FLATBUFFERS_FALLTHROUGH();  // else fall thru
317       default: return "";
318     }
319   }
320 
321   // Casts necessary to correctly read serialized data
DestinationCast(const Type & type) const322   std::string DestinationCast(const Type &type) const {
323     if (IsSeries(type)) {
324       return DestinationCast(type.VectorType());
325     } else {
326       // Cast necessary to correctly read serialized unsigned values.
327       if (type.base_type == BASE_TYPE_UINT) return "(long)";
328     }
329     return "";
330   }
331 
332   // Cast statements for mutator method parameters.
333   // In Java, parameters representing unsigned numbers need to be cast down to
334   // their respective type. For example, a long holding an unsigned int value
335   // would be cast down to int before being put onto the buffer.
SourceCast(const Type & type,bool castFromDest) const336   std::string SourceCast(const Type &type, bool castFromDest) const {
337     if (IsSeries(type)) {
338       return SourceCast(type.VectorType(), castFromDest);
339     } else {
340       if (castFromDest) {
341         if (type.base_type == BASE_TYPE_UINT)
342           return "(int) ";
343         else if (type.base_type == BASE_TYPE_USHORT)
344           return "(short) ";
345         else if (type.base_type == BASE_TYPE_UCHAR)
346           return "(byte) ";
347       }
348     }
349     return "";
350   }
351 
SourceCast(const Type & type) const352   std::string SourceCast(const Type &type) const {
353     return SourceCast(type, true);
354   }
355 
SourceCastBasic(const Type & type,bool castFromDest) const356   std::string SourceCastBasic(const Type &type, bool castFromDest) const {
357     return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
358   }
359 
SourceCastBasic(const Type & type) const360   std::string SourceCastBasic(const Type &type) const {
361     return SourceCastBasic(type, true);
362   }
363 
GenEnumDefaultValue(const FieldDef & field) const364   std::string GenEnumDefaultValue(const FieldDef &field) const {
365     auto &value = field.value;
366     FLATBUFFERS_ASSERT(value.type.enum_def);
367     auto &enum_def = *value.type.enum_def;
368     auto enum_val = enum_def.FindByValue(value.constant);
369     return enum_val
370                ? Prefixed(namer_.NamespacedEnumVariant(enum_def, *enum_val))
371                : value.constant;
372   }
373 
GenDefaultValue(const FieldDef & field) const374   std::string GenDefaultValue(const FieldDef &field) const {
375     auto &value = field.value;
376     auto constant = field.IsScalarOptional() ? "0" : value.constant;
377     auto longSuffix = "L";
378     switch (value.type.base_type) {
379       case BASE_TYPE_BOOL: return constant == "0" ? "false" : "true";
380       case BASE_TYPE_ULONG: {
381         // Converts the ulong into its bits signed equivalent
382         uint64_t defaultValue = StringToUInt(constant.c_str());
383         return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix;
384       }
385       case BASE_TYPE_UINT:
386       case BASE_TYPE_LONG: return constant + longSuffix;
387       default:
388         if (IsFloat(value.type.base_type)) {
389           if (field.IsScalarOptional()) {
390             return value.type.base_type == BASE_TYPE_DOUBLE ? "0.0" : "0f";
391           }
392           return JavaFloatGen.GenFloatConstant(field);
393         } else {
394           return constant;
395         }
396     }
397   }
398 
GenDefaultValueBasic(const FieldDef & field) const399   std::string GenDefaultValueBasic(const FieldDef &field) const {
400     auto &value = field.value;
401     if (!IsScalar(value.type.base_type)) { return "0"; }
402     return GenDefaultValue(field);
403   }
404 
GenEnum(EnumDef & enum_def,std::string & code) const405   void GenEnum(EnumDef &enum_def, std::string &code) const {
406     if (enum_def.generated) return;
407 
408     // Generate enum definitions of the form:
409     // public static (final) int name = value;
410     // In Java, we use ints rather than the Enum feature, because we want them
411     // to map directly to how they're used in C/C++ and file formats.
412     // That, and Java Enums are expensive, and not universally liked.
413     GenComment(enum_def.doc_comment, &code, &comment_config);
414 
415     code += "@SuppressWarnings(\"unused\")\n";
416     if (enum_def.attributes.Lookup("private")) {
417       // For Java, we leave the enum unmarked to indicate package-private
418     } else {
419       code += "public ";
420     }
421     code += "final class " + namer_.Type(enum_def);
422     code += " {\n";
423     code += "  private " + namer_.Type(enum_def) + "() { }\n";
424     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
425       auto &ev = **it;
426       GenComment(ev.doc_comment, &code, &comment_config, "  ");
427       code += "  public static final ";
428       code += GenTypeBasic(DestinationType(enum_def.underlying_type, false));
429       code += " ";
430       code += namer_.Variant(ev) + " = ";
431       code += enum_def.ToString(ev);
432       if (enum_def.underlying_type.base_type == BASE_TYPE_LONG ||
433           enum_def.underlying_type.base_type == BASE_TYPE_ULONG) {
434         code += "L";
435       }
436       code += ";\n";
437     }
438 
439     // Generate a string table for enum values.
440     // Problem is, if values are very sparse that could generate really big
441     // tables. Ideally in that case we generate a map lookup instead, but for
442     // the moment we simply don't output a table at all.
443     auto range = enum_def.Distance();
444     // Average distance between values above which we consider a table
445     // "too sparse". Change at will.
446     static const uint64_t kMaxSparseness = 5;
447     if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness &&
448         GenTypeBasic(DestinationType(enum_def.underlying_type, false)) !=
449             "long") {
450       code += "\n  public static final String";
451       code += "[] names = { ";
452       const EnumVal *prev = enum_def.Vals().front();
453       for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end();
454            ++it) {
455         const EnumVal &ev = **it;
456         for (auto k = enum_def.Distance(prev, &ev); k > 1; --k)
457           code += "\"\", ";
458         prev = &ev;
459         code += "\"" + namer_.Variant(ev) + "\", ";
460       }
461       code += "};\n\n";
462       code += "  public static ";
463       code += "String";
464       code += " name";
465       code += "(int e) { return names[e";
466       if (enum_def.MinValue()->IsNonZero())
467         code += " - " + namer_.Variant(enum_def.MinValue()->name);
468       code += "]; }\n";
469     }
470 
471     // Close the class
472     code += "}\n\n";
473   }
474 
475   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type) const476   std::string GenGetter(const Type &type) const {
477     switch (type.base_type) {
478       case BASE_TYPE_STRING: return "__string";
479       case BASE_TYPE_STRUCT: return "__struct";
480       case BASE_TYPE_UNION: return "__union";
481       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
482       case BASE_TYPE_ARRAY: return GenGetter(type.VectorType());
483       default: {
484         std::string getter = "bb.get";
485         if (type.base_type == BASE_TYPE_BOOL) {
486           getter = "0!=" + getter;
487         } else if (GenTypeBasic(type) != "byte") {
488           getter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
489         }
490         return getter;
491       }
492     }
493   }
494 
495   // 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) const496   std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
497                                       const std::string &data_buffer,
498                                       const char *num = nullptr) const {
499     auto type = key_field->value.type;
500     auto dest_mask = DestinationMask(type, true);
501     auto dest_cast = DestinationCast(type);
502     auto getter = data_buffer + ".get";
503     if (GenTypeBasic(type) != "byte") {
504       getter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
505     }
506     getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" +
507              dest_mask;
508     return getter;
509   }
510 
511   // Direct mutation is only allowed for scalar fields.
512   // Hence a setter method will only be generated for such fields.
GenSetter(const Type & type) const513   std::string GenSetter(const Type &type) const {
514     if (IsScalar(type.base_type)) {
515       std::string setter = "bb.put";
516       if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) {
517         setter += ConvertCase(GenTypeBasic(type), Case::kUpperCamel);
518       }
519       return setter;
520     } else {
521       return "";
522     }
523   }
524 
525   // Returns the method name for use with add/put calls.
GenMethod(const Type & type) const526   std::string GenMethod(const Type &type) const {
527     return IsScalar(type.base_type)
528                ? ConvertCase(GenTypeBasic(type), Case::kUpperCamel)
529                : (IsStruct(type) ? "Struct" : "Offset");
530   }
531 
532   // Recursively generate arguments for a constructor, to deal with nested
533   // structs.
GenStructArgs(const StructDef & struct_def,std::string & code,const char * nameprefix,size_t array_count=0) const534   void GenStructArgs(const StructDef &struct_def, std::string &code,
535                      const char *nameprefix, size_t array_count = 0) const {
536     for (auto it = struct_def.fields.vec.begin();
537          it != struct_def.fields.vec.end(); ++it) {
538       auto &field = **it;
539       const auto &field_type = field.value.type;
540       const auto array_field = IsArray(field_type);
541       const auto &type = array_field ? field_type.VectorType()
542                                      : DestinationType(field_type, false);
543       const auto array_cnt = array_field ? (array_count + 1) : array_count;
544       if (IsStruct(type)) {
545         // Generate arguments for a struct inside a struct. To ensure names
546         // don't clash, and to make it obvious these arguments are constructing
547         // a nested struct, prefix the name with the field name.
548         GenStructArgs(*field_type.struct_def, code,
549                       (nameprefix + (field.name + "_")).c_str(), array_cnt);
550       } else {
551         code += ", ";
552         code += GenTypeNameDest(field.value.type);
553         for (size_t i = 0; i < array_cnt; i++) code += "[]";
554         code += " ";
555         code += nameprefix;
556         code += namer_.Field(field);
557       }
558     }
559   }
560 
561   // Recusively generate struct construction statements of the form:
562   // builder.putType(name);
563   // and insert manual padding.
GenStructBody(const StructDef & struct_def,std::string & code,const char * nameprefix,size_t index=0,bool in_array=false) const564   void GenStructBody(const StructDef &struct_def, std::string &code,
565                      const char *nameprefix, size_t index = 0,
566                      bool in_array = false) const {
567     std::string indent((index + 1) * 2, ' ');
568     code += indent + "  builder.prep(";
569     code += NumToString(struct_def.minalign) + ", ";
570     code += NumToString(struct_def.bytesize) + ");\n";
571     for (auto it = struct_def.fields.vec.rbegin();
572          it != struct_def.fields.vec.rend(); ++it) {
573       auto &field = **it;
574       const auto &field_type = field.value.type;
575       if (field.padding) {
576         code += indent + "  builder.pad(";
577         code += NumToString(field.padding) + ");\n";
578       }
579       if (IsStruct(field_type)) {
580         GenStructBody(*field_type.struct_def, code,
581                       (nameprefix + (field.name + "_")).c_str(), index,
582                       in_array);
583       } else {
584         const auto &type =
585             IsArray(field_type) ? field_type.VectorType() : field_type;
586         const auto index_var = "_idx" + NumToString(index);
587         if (IsArray(field_type)) {
588           code += indent + "  for (int " + index_var + " = ";
589           code += NumToString(field_type.fixed_length);
590           code += "; " + index_var + " > 0; " + index_var + "--) {\n";
591           in_array = true;
592         }
593         if (IsStruct(type)) {
594           GenStructBody(*field_type.struct_def, code,
595                         (nameprefix + (field.name + "_")).c_str(), index + 1,
596                         in_array);
597         } else {
598           code += IsArray(field_type) ? "  " : "";
599           code += indent + "  builder.put";
600           code += GenMethod(type) + "(";
601           code += SourceCast(type);
602           auto argname = nameprefix + namer_.Variable(field);
603           code += argname;
604           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
605           for (size_t i = 0; in_array && i < array_cnt; i++) {
606             code += "[_idx" + NumToString(i) + "-1]";
607           }
608           code += ");\n";
609         }
610         if (IsArray(field_type)) { code += indent + "  }\n"; }
611       }
612     }
613   }
614 
GenOffsetGetter(flatbuffers::FieldDef * key_field,const char * num=nullptr) const615   std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
616                               const char *num = nullptr) const {
617     std::string key_offset = "";
618     key_offset += "__offset(" + NumToString(key_field->value.offset) + ", ";
619     if (num) {
620       key_offset += num;
621       key_offset += ", _bb)";
622     } else {
623       key_offset += "bb.capacity()";
624       key_offset += " - tableOffset, bb)";
625     }
626     return key_offset;
627   }
628 
GenLookupKeyGetter(flatbuffers::FieldDef * key_field) const629   std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const {
630     std::string key_getter = "      ";
631     key_getter += "int tableOffset = ";
632     key_getter += "__indirect(vectorLocation + 4 * (start + middle)";
633     key_getter += ", bb);\n      ";
634     if (IsString(key_field->value.type)) {
635       key_getter += "int comp = ";
636       key_getter += "compareStrings(";
637       key_getter += GenOffsetGetter(key_field);
638       key_getter += ", byteKey, bb);\n";
639     } else {
640       auto get_val = GenGetterForLookupByKey(key_field, "bb");
641       key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
642       key_getter += get_val + ";\n";
643       key_getter += "      int comp = val > key ? 1 : val < key ? -1 : 0;\n";
644     }
645     return key_getter;
646   }
647 
GenKeyGetter(flatbuffers::FieldDef * key_field) const648   std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const {
649     std::string key_getter = "";
650     auto data_buffer = "_bb";
651     if (IsString(key_field->value.type)) {
652       key_getter += " return ";
653       key_getter += "";
654       key_getter += "compareStrings(";
655       key_getter += GenOffsetGetter(key_field, "o1") + ", ";
656       key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")";
657       key_getter += ";";
658     } else {
659       auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
660       key_getter +=
661           "\n    " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
662       key_getter +=
663           field_getter + ";\n    " + GenTypeNameDest(key_field->value.type);
664       key_getter += " val_2 = ";
665       field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
666       key_getter += field_getter + ";\n";
667       key_getter += "    return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
668     }
669     return key_getter;
670   }
671 
GenStruct(StructDef & struct_def,std::string & code,const IDLOptions & opts) const672   void GenStruct(StructDef &struct_def, std::string &code,
673                  const IDLOptions &opts) const {
674     if (struct_def.generated) return;
675 
676     // Generate a struct accessor class, with methods of the form:
677     // public type name() { return bb.getType(i + offset); }
678     // or for tables of the form:
679     // public type name() {
680     //   int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default;
681     // }
682     GenComment(struct_def.doc_comment, &code, &comment_config);
683 
684     if (parser_.opts.gen_generated) {
685       code += "@javax.annotation.Generated(value=\"flatc\")\n";
686     }
687     code += "@SuppressWarnings(\"unused\")\n";
688     if (struct_def.attributes.Lookup("private")) {
689       // For Java, we leave the struct unmarked to indicate package-private
690     } else {
691       code += "public ";
692     }
693     const auto struct_class = namer_.Type(struct_def);
694     code += "final class " + struct_class;
695     code += " extends ";
696     code += struct_def.fixed ? "Struct" : "Table";
697     code += " {\n";
698 
699     if (!struct_def.fixed) {
700       // Generate version check method.
701       // Force compile time error if not using the same version runtime.
702       code += "  public static void ValidateVersion() {";
703       code += " Constants.";
704       code += "FLATBUFFERS_25_1_24(); ";
705       code += "}\n";
706 
707       // Generate a special accessor for the table that when used as the root
708       // of a FlatBuffer
709       const std::string method_name =
710           namer_.LegacyJavaMethod2("getRootAs", struct_def, "");
711       const std::string method_signature =
712           "  public static " + struct_class + " " + method_name;
713 
714       // create convenience method that doesn't require an existing object
715       code += method_signature + "(ByteBuffer _bb) ";
716       code +=
717           "{ return " + method_name + "(_bb, new " + struct_class + "()); }\n";
718 
719       // create method that allows object reuse
720       code +=
721           method_signature + "(ByteBuffer _bb, " + struct_class + " obj) { ";
722       code += "_bb.order(ByteOrder.LITTLE_ENDIAN); ";
723       code += "return (obj.__assign(_bb.getInt(_bb.";
724       code += "position()";
725       code += ") + _bb.";
726       code += "position()";
727       code += ", _bb)); }\n";
728       if (parser_.root_struct_def_ == &struct_def) {
729         if (parser_.file_identifier_.length()) {
730           // Check if a buffer has the identifier.
731           code += "  public static ";
732           code += "boolean " +
733                   namer_.LegacyJavaMethod2(
734                       "", struct_def, "BufferHasIdentifier(ByteBuffer _bb)") +
735                   " { return ";
736           code += "__has_identifier(_bb, \"";
737           code += parser_.file_identifier_;
738           code += "\"); }\n";
739         }
740       }
741     }
742     // Generate the __init method that sets the field in a pre-existing
743     // accessor object. This is to allow object reuse.
744     code += "  public void __init(int _i, ByteBuffer _bb) ";
745     code += "{ ";
746     code += "__reset(_i, _bb); ";
747     code += "}\n";
748     code += "  public " + struct_class + " __assign(int _i, ByteBuffer _bb) ";
749     code += "{ __init(_i, _bb); return this; }\n\n";
750     for (auto it = struct_def.fields.vec.begin();
751          it != struct_def.fields.vec.end(); ++it) {
752       auto &field = **it;
753       if (field.deprecated) continue;
754       GenComment(field.doc_comment, &code, &comment_config, "  ");
755       const std::string type_name = GenTypeGet(field.value.type);
756       const std::string type_name_dest = GenTypeNameDest(field.value.type);
757       const std::string dest_mask = DestinationMask(field.value.type, true);
758       const std::string dest_cast = DestinationCast(field.value.type);
759       const std::string src_cast = SourceCast(field.value.type);
760       const std::string method_start =
761           "  public " +
762           (field.IsRequired() ? "" : GenNullableAnnotation(field.value.type)) +
763           GenPureAnnotation(field.value.type) + type_name_dest + " " +
764           namer_.Field(field);
765       const std::string obj = "obj";
766 
767       // Most field accessors need to retrieve and test the field offset first,
768       // this is the prefix code for that:
769       auto offset_prefix =
770           IsArray(field.value.type)
771               ? " { return "
772               : (" { int o = __offset(" + NumToString(field.value.offset) +
773                  "); return o != 0 ? ");
774       // Generate the accessors that don't do object reuse.
775       if (field.value.type.base_type == BASE_TYPE_STRUCT) {
776         // Calls the accessor that takes an accessor object with a new object.
777         code += method_start + "() { return ";
778         code += namer_.Field(field);
779         code += "(new ";
780         code += type_name + "()); }\n";
781       } else if (IsSeries(field.value.type) &&
782                  field.value.type.element == BASE_TYPE_STRUCT) {
783         // Accessors for vectors of structs also take accessor objects, this
784         // generates a variant without that argument.
785         code += method_start + "(int j) { return ";
786         code += namer_.Field(field);
787         code += "(new " + type_name + "(), j); }\n";
788       }
789 
790       if (field.IsScalarOptional()) { code += GenOptionalScalarCheck(field); }
791       std::string getter = dest_cast + GenGetter(field.value.type);
792       code += method_start;
793       std::string member_suffix = "; ";
794       if (IsScalar(field.value.type.base_type)) {
795         code += "()";
796         member_suffix += "";
797         if (struct_def.fixed) {
798           code += " { return " + getter;
799           code += "(bb_pos + ";
800           code += NumToString(field.value.offset) + ")";
801           code += dest_mask;
802         } else {
803           code += offset_prefix + getter;
804           code += "(o + bb_pos)" + dest_mask;
805           code += " : ";
806           code += GenDefaultValue(field);
807         }
808       } else {
809         switch (field.value.type.base_type) {
810           case BASE_TYPE_STRUCT:
811             code += "(" + type_name + " obj)";
812             if (struct_def.fixed) {
813               code += " { return " + obj + ".__assign(";
814               code += "bb_pos + " + NumToString(field.value.offset) + ", ";
815               code += "bb)";
816             } else {
817               code += offset_prefix;
818               code += obj + ".__assign(";
819               code += field.value.type.struct_def->fixed
820                           ? "o + bb_pos"
821                           : "__indirect(o + bb_pos)";
822               code += ", bb) : null";
823             }
824             break;
825           case BASE_TYPE_STRING:
826             code += "()";
827             member_suffix += "";
828             code += offset_prefix + getter + "(o + ";
829             code += "bb_pos) : null";
830             break;
831           case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
832           case BASE_TYPE_VECTOR: {
833             auto vectortype = field.value.type.VectorType();
834             code += "(";
835             if (vectortype.base_type == BASE_TYPE_STRUCT) {
836               code += type_name + " obj, ";
837               getter = obj + ".__assign";
838             } else if (vectortype.base_type == BASE_TYPE_UNION) {
839               code += type_name + " obj, ";
840             }
841             code += "int j)";
842             const auto body = offset_prefix + getter + "(";
843             if (vectortype.base_type == BASE_TYPE_UNION) {
844               code += body + "obj, ";
845             } else {
846               code += body;
847             }
848             std::string index;
849             if (IsArray(field.value.type)) {
850               index += "bb_pos + " + NumToString(field.value.offset) + " + ";
851             } else {
852               index += "__vector(o) + ";
853             }
854             index += "j * " + NumToString(InlineSize(vectortype));
855             if (vectortype.base_type == BASE_TYPE_STRUCT) {
856               code += vectortype.struct_def->fixed
857                           ? index
858                           : "__indirect(" + index + ")";
859               code += ", bb";
860             } else {
861               code += index;
862             }
863             code += ")" + dest_mask;
864             if (!IsArray(field.value.type)) {
865               code += " : ";
866               code += field.value.type.element == BASE_TYPE_BOOL
867                           ? "false"
868                           : (IsScalar(field.value.type.element) ? "0" : "null");
869             }
870 
871             break;
872           }
873           case BASE_TYPE_UNION:
874             code += "(" + type_name + " obj)" + offset_prefix + getter;
875             code += "(obj, o + bb_pos) : null";
876             break;
877           default: FLATBUFFERS_ASSERT(0);
878         }
879       }
880       code += member_suffix;
881       code += "}\n";
882       if (IsVector(field.value.type)) {
883         code += "  public int " + namer_.Field(field);
884         code += "Length";
885         code += "()";
886         code += offset_prefix;
887         code += "__vector_len(o) : 0; ";
888         code += "";
889         code += "}\n";
890         // See if we should generate a by-key accessor.
891         if (field.value.type.element == BASE_TYPE_STRUCT &&
892             !field.value.type.struct_def->fixed) {
893           auto &sd = *field.value.type.struct_def;
894           auto &fields = sd.fields.vec;
895           for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
896             auto &key_field = **kit;
897             if (key_field.key) {
898               auto qualified_name = Prefixed(namer_.NamespacedType(sd));
899               code += "  public " + qualified_name + " ";
900               code += namer_.Method(field) + "ByKey(";
901               code += GenTypeNameDest(key_field.value.type) + " key)";
902               code += offset_prefix;
903               code += qualified_name + ".__lookup_by_key(";
904               code += "null, ";
905               code += "__vector(o), key, ";
906               code += "bb) : null; ";
907               code += "}\n";
908               code += "  public " + qualified_name + " ";
909               code += namer_.Method(field) + "ByKey(";
910               code += qualified_name + " obj, ";
911               code += GenTypeNameDest(key_field.value.type) + " key)";
912               code += offset_prefix;
913               code += qualified_name + ".__lookup_by_key(obj, ";
914               code += "__vector(o), key, ";
915               code += "bb) : null; ";
916               code += "}\n";
917               break;
918             }
919           }
920         }
921       }
922       // Generate the accessors for vector of structs with vector access object
923       if (IsVector(field.value.type)) {
924         std::string vector_type_name;
925         const auto &element_base_type = field.value.type.VectorType().base_type;
926         if (IsScalar(element_base_type)) {
927           vector_type_name =
928               ConvertCase(type_name, Case::kUpperCamel) + "Vector";
929         } else if (element_base_type == BASE_TYPE_STRING) {
930           vector_type_name = "StringVector";
931         } else if (element_base_type == BASE_TYPE_UNION) {
932           vector_type_name = "UnionVector";
933         } else {
934           vector_type_name = type_name + ".Vector";
935         }
936         auto vector_method_start = GenNullableAnnotation(field.value.type) +
937                                    "  public " + vector_type_name + " " +
938                                    namer_.Field(field, "vector");
939         code += vector_method_start + "() { return ";
940         code += namer_.Field(field, "vector");
941         code += "(new " + vector_type_name + "()); }\n";
942         code += vector_method_start + "(" + vector_type_name + " obj)";
943         code += offset_prefix + obj + ".__assign(";
944         code += "__vector(o), ";
945         if (!IsScalar(element_base_type)) {
946           auto vectortype = field.value.type.VectorType();
947           code += NumToString(InlineSize(vectortype)) + ", ";
948         }
949         code += "bb) : null" + member_suffix + "}\n";
950       }
951       // Generate a ByteBuffer accessor for strings & vectors of scalars.
952       if ((IsVector(field.value.type) &&
953            IsScalar(field.value.type.VectorType().base_type)) ||
954           IsString(field.value.type)) {
955         code += "  public ByteBuffer ";
956         code += namer_.Field(field);
957         code += "AsByteBuffer() { return ";
958         code += "__vector_as_bytebuffer(";
959         code += NumToString(field.value.offset) + ", ";
960         code += NumToString(IsString(field.value.type)
961                                 ? 1
962                                 : InlineSize(field.value.type.VectorType()));
963         code += "); }\n";
964         code += "  public ByteBuffer ";
965         code += namer_.Field(field);
966         code += "InByteBuffer(ByteBuffer _bb) { return ";
967         code += "__vector_in_bytebuffer(_bb, ";
968         code += NumToString(field.value.offset) + ", ";
969         code += NumToString(IsString(field.value.type)
970                                 ? 1
971                                 : InlineSize(field.value.type.VectorType()));
972         code += "); }\n";
973       }
974       // generate object accessors if is nested_flatbuffer
975       if (field.nested_flatbuffer) {
976         auto nested_type_name =
977             Prefixed(namer_.NamespacedType(*field.nested_flatbuffer));
978         auto nested_method_name =
979             namer_.Field(field) + "As" + field.nested_flatbuffer->name;
980         auto get_nested_method_name = nested_method_name;
981         code += "  public " + nested_type_name + " ";
982         code += nested_method_name + "() { return ";
983         code +=
984             get_nested_method_name + "(new " + nested_type_name + "()); }\n";
985         code += "  public " + nested_type_name + " ";
986         code += get_nested_method_name + "(";
987         code += nested_type_name + " obj";
988         code += ") { int o = __offset(";
989         code += NumToString(field.value.offset) + "); ";
990         code += "return o != 0 ? " + obj + ".__assign(";
991         code += "";
992         code += "__indirect(__vector(o)), ";
993         code += "bb) : null; }\n";
994       }
995       // Generate mutators for scalar fields or vectors of scalars.
996       if (parser_.opts.mutable_buffer) {
997         auto is_series = (IsSeries(field.value.type));
998         const auto &underlying_type =
999             is_series ? field.value.type.VectorType() : field.value.type;
1000         // Boolean parameters have to be explicitly converted to byte
1001         // representation.
1002         auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
1003                                     ? "(byte)(" + field.name + " ? 1 : 0)"
1004                                     : field.name;
1005         // A vector mutator also needs the index of the vector element it should
1006         // mutate.
1007         auto mutator_params = (is_series ? "(int j, " : "(") +
1008                               GenTypeNameDest(underlying_type) + " " +
1009                               field.name + ") { ";
1010         auto setter_index =
1011             is_series
1012                 ? (IsArray(field.value.type)
1013                        ? "bb_pos + " + NumToString(field.value.offset)
1014                        : "__vector(o)") +
1015                       +" + j * " + NumToString(InlineSize(underlying_type))
1016                 : (struct_def.fixed
1017                        ? "bb_pos + " + NumToString(field.value.offset)
1018                        : "o + bb_pos");
1019         if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) {
1020           code += "  public ";
1021           code += struct_def.fixed ? "void " : "boolean ";
1022           code += namer_.Method("mutate", field);
1023           code += mutator_params;
1024           if (struct_def.fixed) {
1025             code += GenSetter(underlying_type) + "(" + setter_index + ", ";
1026             code += src_cast + setter_parameter + "); }\n";
1027           } else {
1028             code += "int o = __offset(";
1029             code += NumToString(field.value.offset) + ");";
1030             code += " if (o != 0) { " + GenSetter(underlying_type);
1031             code += "(" + setter_index + ", " + src_cast + setter_parameter +
1032                     "); return true; } else { return false; } }\n";
1033           }
1034         }
1035       }
1036       if (parser_.opts.java_primitive_has_method &&
1037           IsScalar(field.value.type.base_type) && !struct_def.fixed) {
1038         auto vt_offset_constant = "  public static final int VT_" +
1039                                   namer_.Constant(field) + " = " +
1040                                   NumToString(field.value.offset) + ";";
1041 
1042         code += vt_offset_constant;
1043         code += "\n";
1044       }
1045     }
1046     code += "\n";
1047     auto struct_has_create = false;
1048     std::set<flatbuffers::FieldDef *> field_has_create_set;
1049     flatbuffers::FieldDef *key_field = nullptr;
1050     if (struct_def.fixed) {
1051       struct_has_create = true;
1052       // create a struct constructor function
1053       code += "  public static " + GenOffsetType() + " ";
1054       code += "create";
1055       code += struct_class + "(FlatBufferBuilder builder";
1056       GenStructArgs(struct_def, code, "");
1057       code += ") {\n";
1058       GenStructBody(struct_def, code, "");
1059       code += "    return ";
1060       code += GenOffsetConstruct("builder." + std::string("offset()"));
1061       code += ";\n  }\n";
1062     } else {
1063       // Generate a method that creates a table in one go. This is only possible
1064       // when the table has no struct fields, since those have to be created
1065       // inline, and there's no way to do so in Java.
1066       bool has_no_struct_fields = true;
1067       int num_fields = 0;
1068       for (auto it = struct_def.fields.vec.begin();
1069            it != struct_def.fields.vec.end(); ++it) {
1070         auto &field = **it;
1071         if (field.deprecated) continue;
1072         if (IsStruct(field.value.type)) {
1073           has_no_struct_fields = false;
1074         } else {
1075           num_fields++;
1076         }
1077       }
1078       // JVM specifications restrict default constructor params to be < 255.
1079       // Longs and doubles take up 2 units, so we set the limit to be < 127.
1080       if (has_no_struct_fields && num_fields && num_fields < 127) {
1081         struct_has_create = true;
1082         // Generate a table constructor of the form:
1083         // public static int createName(FlatBufferBuilder builder, args...)
1084         code += "  public static " + GenOffsetType() + " ";
1085         code += namer_.LegacyJavaMethod2("create", struct_def, "");
1086         code += "(FlatBufferBuilder builder";
1087         for (auto it = struct_def.fields.vec.begin();
1088              it != struct_def.fields.vec.end(); ++it) {
1089           auto &field = **it;
1090           auto field_name = namer_.Field(field);
1091           if (field.deprecated) continue;
1092           code += ",\n      ";
1093           code += GenTypeBasic(DestinationType(field.value.type, false));
1094           code += " ";
1095           code += field_name;
1096           if (!IsScalar(field.value.type.base_type)) code += "Offset";
1097         }
1098         code += ") {\n    builder.";
1099         code += "startTable(";
1100         code += NumToString(struct_def.fields.vec.size()) + ");\n";
1101         for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1;
1102              size; size /= 2) {
1103           for (auto it = struct_def.fields.vec.rbegin();
1104                it != struct_def.fields.vec.rend(); ++it) {
1105             auto &field = **it;
1106             auto field_name = namer_.Field(field);
1107             if (!field.deprecated &&
1108                 (!struct_def.sortbysize ||
1109                  size == SizeOf(field.value.type.base_type))) {
1110               code += "    " + struct_class + ".";
1111               code += namer_.Method("add", field) + "(builder, " + field_name;
1112               if (!IsScalar(field.value.type.base_type)) code += "Offset";
1113               code += ");\n";
1114             }
1115           }
1116         }
1117         code += "    return " + struct_class + ".";
1118         code += namer_.LegacyJavaMethod2("end", struct_def, "");
1119         code += "(builder);\n  }\n\n";
1120       }
1121       // Generate a set of static methods that allow table construction,
1122       // of the form:
1123       // public static void addName(FlatBufferBuilder builder, short name)
1124       // { builder.addShort(id, name, default); }
1125       // Unlike the Create function, these always work.
1126       code += "  public static void start";
1127       code += struct_class;
1128       code += "(FlatBufferBuilder builder) { builder.";
1129       code += "startTable(";
1130       code += NumToString(struct_def.fields.vec.size()) + "); }\n";
1131       for (auto it = struct_def.fields.vec.begin();
1132            it != struct_def.fields.vec.end(); ++it) {
1133         auto &field = **it;
1134         if (field.deprecated) continue;
1135 
1136         code += "  public static void " + namer_.Method("add", field);
1137         code += "(FlatBufferBuilder builder, ";
1138         code += GenTypeBasic(DestinationType(field.value.type, false));
1139         auto argname = namer_.Field(field);
1140         if (!IsScalar(field.value.type.base_type)) argname += "Offset";
1141         code += " " + argname + ") { builder.add";
1142         code += GenMethod(field.value.type) + "(";
1143 
1144         if (field.key) {
1145           // field has key attribute, so always need to exist
1146           // even if its value is equal to default.
1147           // Generated code will bypass default checking
1148           // resulting in { builder.addShort(name); slot(id); }
1149           key_field = &field;
1150           code += SourceCastBasic(field.value.type);
1151           code += argname;
1152           code += "); builder.slot(" +
1153                   NumToString(it - struct_def.fields.vec.begin()) + "); }\n";
1154         } else {
1155           code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
1156           code += SourceCastBasic(field.value.type);
1157           code += argname;
1158           code += ", ";
1159           code += SourceCastBasic(field.value.type);
1160           code += GenDefaultValue(field);
1161           code += "); }\n";
1162         }
1163         if (IsVector(field.value.type)) {
1164           auto vector_type = field.value.type.VectorType();
1165           auto alignment = InlineAlignment(vector_type);
1166           auto elem_size = InlineSize(vector_type);
1167           if (!IsStruct(vector_type)) {
1168             field_has_create_set.insert(&field);
1169             // generate a method to create a vector from a java array.
1170             if ((vector_type.base_type == BASE_TYPE_CHAR ||
1171                  vector_type.base_type == BASE_TYPE_UCHAR)) {
1172               // Handle byte[] and ByteBuffers separately for Java
1173               code += "  public static " + GenVectorOffsetType() + " ";
1174               code += namer_.Method("create", field);
1175               code += "Vector(FlatBufferBuilder builder, byte[] data) ";
1176               code += "{ return builder.createByteVector(data); }\n";
1177 
1178               code += "  public static " + GenVectorOffsetType() + " ";
1179               code += namer_.Method("create", field);
1180               code += "Vector(FlatBufferBuilder builder, ByteBuffer data) ";
1181               code += "{ return builder.createByteVector(data); }\n";
1182             } else {
1183               code += "  public static " + GenVectorOffsetType() + " ";
1184               code += namer_.Method("create", field);
1185               code += "Vector(FlatBufferBuilder builder, ";
1186               code += GenTypeBasic(DestinationType(vector_type, false)) +
1187                       "[] data) ";
1188               code += "{ builder.startVector(";
1189               code += NumToString(elem_size);
1190               code += ", data.length, ";
1191               code += NumToString(alignment);
1192               code += "); for (int i = data.";
1193               code += "length - 1; i >= 0; i--) builder.";
1194               code += "add";
1195               code += GenMethod(vector_type);
1196               code += "(";
1197               code += SourceCastBasic(vector_type);
1198               code += "data[i]";
1199               code += "); return ";
1200               code += "builder.endVector(); }\n";
1201             }
1202           }
1203           // Generate a method to start a vector, data to be added manually
1204           // after.
1205           code += "  public static void " + namer_.Method("start", field);
1206           code += "Vector(FlatBufferBuilder builder, int numElems) ";
1207           code += "{ builder.startVector(";
1208           code += NumToString(elem_size);
1209           code += ", numElems, " + NumToString(alignment);
1210           code += "); }\n";
1211         }
1212       }
1213       code += "  public static " + GenOffsetType() + " ";
1214       code += namer_.LegacyJavaMethod2("end", struct_def, "");
1215       code += "(FlatBufferBuilder builder) {\n    int o = builder.";
1216       code += "endTable();\n";
1217       for (auto it = struct_def.fields.vec.begin();
1218            it != struct_def.fields.vec.end(); ++it) {
1219         auto &field = **it;
1220         if (!field.deprecated && field.IsRequired()) {
1221           code += "    builder.required(o, ";
1222           code += NumToString(field.value.offset);
1223           code += ");  // " + field.name + "\n";
1224         }
1225       }
1226       code += "    return " + GenOffsetConstruct("o") + ";\n  }\n";
1227       if (parser_.root_struct_def_ == &struct_def) {
1228         std::string size_prefix[] = { "", "SizePrefixed" };
1229         for (int i = 0; i < 2; ++i) {
1230           code += "  public static void ";
1231           code += namer_.LegacyJavaMethod2("finish" + size_prefix[i],
1232                                            struct_def, "Buffer");
1233           code += "(FlatBufferBuilder builder, " + GenOffsetType();
1234           code += " offset) {";
1235           code += " builder.finish" + size_prefix[i] + "(offset";
1236 
1237           if (parser_.file_identifier_.length())
1238             code += ", \"" + parser_.file_identifier_ + "\"";
1239           code += "); }\n";
1240         }
1241       }
1242     }
1243     // Only generate key compare function for table,
1244     // because `key_field` is not set for struct
1245     if (struct_def.has_key && !struct_def.fixed) {
1246       FLATBUFFERS_ASSERT(key_field);
1247       code += "\n  @Override\n  protected int keysCompare(";
1248       code += "Integer o1, Integer o2, ByteBuffer _bb) {";
1249       code += GenKeyGetter(key_field);
1250       code += " }\n";
1251 
1252       code += "\n  public static " + struct_class;
1253       code += " __lookup_by_key(";
1254       code += struct_class + " obj, ";
1255       code += "int vectorLocation, ";
1256       code += GenTypeNameDest(key_field->value.type);
1257       code += " key, ByteBuffer bb) {\n";
1258       if (IsString(key_field->value.type)) {
1259         code += "    byte[] byteKey = ";
1260         code += "key.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n";
1261       }
1262       code += "    int span = ";
1263       code += "bb.getInt(vectorLocation - 4);\n";
1264       code += "    int start = 0;\n";
1265       code += "    while (span != 0) {\n";
1266       code += "      int middle = span / 2;\n";
1267       code += GenLookupKeyGetter(key_field);
1268       code += "      if (comp > 0) {\n";
1269       code += "        span = middle;\n";
1270       code += "      } else if (comp < 0) {\n";
1271       code += "        middle++;\n";
1272       code += "        start += middle;\n";
1273       code += "        span -= middle;\n";
1274       code += "      } else {\n";
1275       code += "        return ";
1276       code += "(obj == null ? new " + struct_class + "() : obj)";
1277       code += ".__assign(tableOffset, bb);\n";
1278       code += "      }\n    }\n";
1279       code += "    return null;\n";
1280       code += "  }\n";
1281     }
1282     GenVectorAccessObject(struct_def, code);
1283     if (opts.generate_object_based_api) {
1284       GenPackUnPack_ObjectAPI(struct_def, code, opts, struct_has_create,
1285                               field_has_create_set);
1286     }
1287     code += "}\n\n";
1288   }
1289 
GenOptionalScalarCheck(FieldDef & field) const1290   std::string GenOptionalScalarCheck(FieldDef &field) const {
1291     if (!field.IsScalarOptional()) return "";
1292     return "  public boolean " + namer_.Method("has", field) +
1293            "() { return 0 != __offset(" + NumToString(field.value.offset) +
1294            "); }\n";
1295   }
1296 
GenVectorAccessObject(StructDef & struct_def,std::string & code) const1297   void GenVectorAccessObject(StructDef &struct_def, std::string &code) const {
1298     // Generate a vector of structs accessor class.
1299     code += "\n";
1300     code += "  ";
1301     if (!struct_def.attributes.Lookup("private")) code += "public ";
1302     code += "static ";
1303     code += "final ";
1304     code += "class Vector extends ";
1305     code += "BaseVector {\n";
1306 
1307     // Generate the __assign method that sets the field in a pre-existing
1308     // accessor object. This is to allow object reuse.
1309     std::string method_indent = "    ";
1310     code += method_indent + "public Vector ";
1311     code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { ";
1312     code += "__reset(_vector, _element_size, _bb); return this; }\n\n";
1313 
1314     auto type_name = namer_.Type(struct_def);
1315     auto method_start = method_indent + "public " + type_name + " get";
1316     // Generate the accessors that don't do object reuse.
1317     code += method_start + "(int j) { return get";
1318     code += "(new " + type_name + "(), j); }\n";
1319     code += method_start + "(" + type_name + " obj, int j) { ";
1320     code += " return obj.__assign(";
1321     std::string index = "__element(j)";
1322     code += struct_def.fixed ? index : "__indirect(" + index + ", bb)";
1323     code += ", bb); }\n";
1324     // See if we should generate a by-key accessor.
1325     if (!struct_def.fixed) {
1326       auto &fields = struct_def.fields.vec;
1327       for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
1328         auto &key_field = **kit;
1329         if (key_field.key) {
1330           auto nullable_annotation =
1331               parser_.opts.gen_nullable ? "@Nullable " : "";
1332           code += method_indent + nullable_annotation;
1333           code += "public " + type_name + " ";
1334           code += "getByKey(";
1335           code += GenTypeNameDest(key_field.value.type) + " key) { ";
1336           code += " return __lookup_by_key(null, ";
1337           code += "__vector(), key, ";
1338           code += "bb); ";
1339           code += "}\n";
1340           code += method_indent + nullable_annotation;
1341           code += "public " + type_name + " ";
1342           code += "getByKey(";
1343           code += type_name + " obj, ";
1344           code += GenTypeNameDest(key_field.value.type) + " key) { ";
1345           code += " return __lookup_by_key(obj, ";
1346           code += "__vector(), key, ";
1347           code += "bb); ";
1348           code += "}\n";
1349           break;
1350         }
1351       }
1352     }
1353     code += "  }\n";
1354   }
1355 
GenEnum_ObjectAPI(EnumDef & enum_def,std::string & code) const1356   void GenEnum_ObjectAPI(EnumDef &enum_def, std::string &code) const {
1357     if (enum_def.generated) return;
1358     code += "import com.google.flatbuffers.FlatBufferBuilder;\n\n";
1359 
1360     if (!enum_def.attributes.Lookup("private")) { code += "public "; }
1361     auto union_name = namer_.Type(enum_def) + "Union";
1362     auto union_type =
1363         GenTypeBasic(DestinationType(enum_def.underlying_type, false));
1364     code += "class " + union_name + " {\n";
1365     // Type
1366     code += "  private " + union_type + " type;\n";
1367     // Value
1368     code += "  private Object value;\n";
1369     code += "\n";
1370     // getters and setters
1371     code += "  public " + union_type + " getType() { return type; }\n\n";
1372     code += "  public void setType(" + union_type +
1373             " type) { this.type = type; }\n\n";
1374     code += "  public Object getValue() { return value; }\n\n";
1375     code += "  public void setValue(Object value) { this.value = value; }\n\n";
1376     // Constructor
1377     code += "  public " + union_name + "() {\n";
1378     code +=
1379         "    this.type = " + namer_.EnumVariant(enum_def, *enum_def.Vals()[0]) +
1380         ";\n";
1381     code += "    this.value = null;\n";
1382     code += "  }\n\n";
1383     // As
1384     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1385       auto &ev = **it;
1386       if (ev.union_type.base_type == BASE_TYPE_NONE) continue;
1387       auto type_name = GenTypeGet_ObjectAPI(ev.union_type, false, true);
1388       if (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1389           ev.union_type.struct_def->attributes.Lookup("private")) {
1390         code += "  ";
1391       } else {
1392         code += "  public ";
1393       }
1394       code += type_name + " as" + ev.name + "() { return (" + type_name +
1395               ") value; }\n";
1396     }
1397     code += "\n";
1398     // pack()
1399     code += "  public static int pack(FlatBufferBuilder builder, " +
1400             union_name + " _o) {\n";
1401     code += "    switch (_o.type) {\n";
1402     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1403       auto &ev = **it;
1404       if (ev.union_type.base_type == BASE_TYPE_NONE) {
1405         continue;
1406       } else {
1407         code += "      case " + namer_.EnumVariant(enum_def, ev) + ": return ";
1408         if (IsString(ev.union_type)) {
1409           code += "builder.createString(_o.as" + ev.name + "());\n";
1410         } else {
1411           code += GenTypeGet(ev.union_type) + ".pack(builder, _o.as" + ev.name +
1412                   "());\n";
1413         }
1414       }
1415     }
1416     code += "      default: return 0;\n";
1417     code += "    }\n";
1418     code += "  }\n";
1419     code += "}\n\n";
1420   }
1421 
GenUnionUnPack_ObjectAPI(const EnumDef & enum_def,std::string & code,const std::string & type_name,const std::string & field_name,bool is_vector) const1422   void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string &code,
1423                                 const std::string &type_name,
1424                                 const std::string &field_name,
1425                                 bool is_vector) const {
1426     const std::string variable_type =
1427         is_vector ? type_name.substr(0, type_name.length() - 2) : type_name;
1428     const std::string variable_name =
1429         "_" + namer_.Variable("o", field_name) + (is_vector ? "Element" : "");
1430     const std::string type_params = is_vector ? "_j" : "";
1431     const std::string value_params = is_vector ? ", _j" : "";
1432     const std::string indent = (is_vector ? "      " : "    ");
1433 
1434     code += indent + variable_type + " " + variable_name + " = new " +
1435             variable_type + "();\n";
1436     code += indent +
1437             GenTypeBasic(DestinationType(enum_def.underlying_type, false)) +
1438             " " + variable_name + "Type = " + field_name + "Type(" +
1439             type_params + ");\n";
1440     code += indent + variable_name + ".setType(" + variable_name + "Type);\n";
1441     code += indent + "Table " + variable_name + "Value;\n";
1442     code += indent + "switch (" + variable_name + "Type) {\n";
1443     for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end();
1444          ++eit) {
1445       auto &ev = **eit;
1446       if (ev.union_type.base_type == BASE_TYPE_NONE) {
1447         continue;
1448       } else {
1449         if (ev.union_type.base_type == BASE_TYPE_STRING ||
1450             (ev.union_type.base_type == BASE_TYPE_STRUCT &&
1451              ev.union_type.struct_def->fixed)) {
1452           continue;  // This branch is due to bad implemantation of Unions in
1453                      // Java which doesn't handle non Table types. Should be
1454                      // deleted when issue #6561 is fixed.
1455         }
1456         code += indent + "  case " +
1457                 Prefixed(namer_.NamespacedEnumVariant(enum_def, ev)) + ":\n";
1458         auto actual_type = GenTypeGet(ev.union_type);
1459         code += indent + "    " + variable_name + "Value = " + field_name +
1460                 "(new " + actual_type + "()" + value_params + ");\n";
1461         code += indent + "    " + variable_name + ".setValue(" + variable_name +
1462                 "Value != null ? ((" + actual_type + ") " + variable_name +
1463                 "Value).unpack() : null);\n";
1464         code += indent + "    break;\n";
1465       }
1466     }
1467     code += indent + "  default: break;\n";
1468     code += indent + "}\n";
1469     if (is_vector) {
1470       code += indent + "_" + namer_.Variable("o", field_name) +
1471               "[_j] = " + variable_name + ";\n";
1472     }
1473   }
1474 
GenPackUnPack_ObjectAPI(StructDef & struct_def,std::string & code,const IDLOptions & opts,bool struct_has_create,const std::set<FieldDef * > & field_has_create) const1475   void GenPackUnPack_ObjectAPI(
1476       StructDef &struct_def, std::string &code, const IDLOptions &opts,
1477       bool struct_has_create,
1478       const std::set<FieldDef *> &field_has_create) const {
1479     auto struct_name = namer_.ObjectType(struct_def);
1480     // unpack()
1481     code += "  public " + struct_name + " unpack() {\n";
1482     code += "    " + struct_name + " _o = new " + struct_name + "();\n";
1483     code += "    unpackTo(_o);\n";
1484     code += "    return _o;\n";
1485     code += "  }\n";
1486     // unpackTo()
1487     code += "  public void unpackTo(" + struct_name + " _o) {\n";
1488     for (auto it = struct_def.fields.vec.begin();
1489          it != struct_def.fields.vec.end(); ++it) {
1490       const auto &field = **it;
1491       if (field.deprecated) continue;
1492       if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
1493       if (field.value.type.element == BASE_TYPE_UTYPE) continue;
1494       const auto accessor = namer_.Method(field);
1495       const auto variable = "_" + namer_.Variable("o", field);
1496       const auto get_field = namer_.Method("get", field);
1497       const auto set_field = namer_.Method("set", field);
1498 
1499       auto type_name = GenTypeGet_ObjectAPI(field.value.type, false, true);
1500       if (field.IsScalarOptional())
1501         type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
1502       auto start = "    " + type_name + " " + variable + " = ";
1503       auto call_setter = true;
1504       switch (field.value.type.base_type) {
1505         case BASE_TYPE_STRUCT: {
1506           auto fixed = struct_def.fixed && field.value.type.struct_def->fixed;
1507           if (fixed) {
1508             code +=
1509                 "    " + accessor + "().unpackTo(_o." + get_field + "());\n";
1510           } else {
1511             code += "    if (" + accessor + "() != null) ";
1512             if (field.value.type.struct_def->fixed) {
1513               code += accessor + "().unpackTo(_o." + get_field + "());\n";
1514             } else {
1515               code += "_o." + set_field + "(" + accessor + "().unpack());\n";
1516             }
1517             code += "    else _o." + set_field + "(null);\n";
1518           }
1519           call_setter = false;
1520           break;
1521         }
1522         case BASE_TYPE_ARRAY: {
1523           auto length_str = NumToString(field.value.type.fixed_length);
1524           auto unpack_method =
1525               field.value.type.struct_def == nullptr ? "" : ".unpack()";
1526           code += start + "_o." + get_field + "();\n";
1527           code += "    for (int _j = 0; _j < " + length_str + "; ++_j) { " +
1528                   variable + "[_j] = " + accessor + "(_j)" + unpack_method +
1529                   "; }\n";
1530           call_setter = false;
1531           break;
1532         }
1533         case BASE_TYPE_VECTOR:
1534           if (field.value.type.element == BASE_TYPE_UNION) {
1535             code += start + "new " +
1536                     GenConcreteTypeGet_ObjectAPI(field.value.type)
1537                         .substr(0, type_name.length() - 1) +
1538                     accessor + "Length()];\n";
1539             code +=
1540                 "    for (int _j = 0; _j < " + accessor + "Length(); ++_j) {\n";
1541             GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code,
1542                                      type_name, accessor, true);
1543             code += "    }\n";
1544           } else if (field.value.type.element != BASE_TYPE_UTYPE) {
1545             auto fixed = field.value.type.struct_def == nullptr;
1546             const auto length_accessor = namer_.Method(field, "length");
1547             code += start + "new " +
1548                     GenConcreteTypeGet_ObjectAPI(field.value.type)
1549                         .substr(0, type_name.length() - 1) +
1550                     length_accessor + "()];\n";
1551             code +=
1552                 "    for (int _j = 0; _j < " + length_accessor + "(); ++_j) {";
1553             code += variable + "[_j] = ";
1554             if (fixed) {
1555               code += accessor + "(_j)";
1556             } else {
1557               code += "(" + accessor + "(_j) != null ? " + accessor +
1558                       "(_j).unpack() : null)";
1559             }
1560             code += ";}\n";
1561           }
1562           break;
1563         case BASE_TYPE_UTYPE: break;
1564         case BASE_TYPE_UNION: {
1565           GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code, type_name,
1566                                    accessor, false);
1567           break;
1568         }
1569         default: {
1570           if (field.IsScalarOptional()) {
1571             code += start + namer_.Method("has", field) + "() ? " + accessor +
1572                     "() : null;\n";
1573           } else {
1574             code += start + accessor + "();\n";
1575           }
1576           break;
1577         }
1578       }
1579       if (call_setter) {
1580         code += "    _o." + set_field + "(" + variable + ");\n";
1581       }
1582     }
1583     code += "  }\n";
1584     // pack()
1585     code += "  public static " + GenOffsetType() +
1586             " pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n";
1587     code += "    if (_o == null) return 0;\n";
1588     for (auto it = struct_def.fields.vec.begin();
1589          it != struct_def.fields.vec.end(); ++it) {
1590       auto &field = **it;
1591       if (field.deprecated) continue;
1592       const auto field_name = namer_.Field(field);
1593       const auto variable = "_" + namer_.Variable("o", field);
1594       const auto get_field = namer_.Method("get", field);
1595       // pre
1596       switch (field.value.type.base_type) {
1597         case BASE_TYPE_STRUCT: {
1598           if (!field.value.type.struct_def->fixed) {
1599             code += "    " + GenOffsetType() + " _" + namer_.Variable(field) +
1600                     " = _o." + get_field +
1601                     "() == null ? 0 : " + GenTypeGet(field.value.type) +
1602                     ".pack(builder, _o." + get_field + "());\n";
1603           } else if (struct_def.fixed && struct_has_create) {
1604             std::vector<FieldArrayLength> array_lengths;
1605             FieldArrayLength tmp_array_length = {
1606               field.name,
1607               field.value.type.fixed_length,
1608             };
1609             array_lengths.push_back(tmp_array_length);
1610             GenStructPackDecl_ObjectAPI(*field.value.type.struct_def,
1611                                         array_lengths, code);
1612           }
1613           break;
1614         }
1615         case BASE_TYPE_STRING: {
1616           code += "    int _" + field_name + " = _o." + get_field +
1617                   "() == null ? 0 : "
1618                   "builder.createString(_o." +
1619                   get_field + "());\n";
1620           break;
1621         }
1622         case BASE_TYPE_VECTOR: {
1623           if (field_has_create.find(&field) != field_has_create.end()) {
1624             auto property_name = field_name;
1625             auto gen_for_loop = true;
1626             std::string array_name = "__" + field_name;
1627             std::string array_type = "";
1628             std::string element_type = "";
1629             std::string to_array = "";
1630             switch (field.value.type.element) {
1631               case BASE_TYPE_STRING: {
1632                 array_type = "int";
1633                 element_type = "String";
1634                 to_array = "builder.createString(_e)";
1635                 break;
1636               }
1637               case BASE_TYPE_STRUCT:
1638                 array_type = "int";
1639                 element_type =
1640                     GenTypeGet_ObjectAPI(field.value.type, true, true);
1641                 ;
1642                 to_array = GenTypeGet(field.value.type) + ".pack(builder, _e)";
1643                 break;
1644               case BASE_TYPE_UTYPE:
1645                 property_name = field_name.substr(0, field_name.size() - 4);
1646                 array_type = GenTypeBasic(DestinationType(
1647                     field.value.type.enum_def->underlying_type, false));
1648                 element_type = field.value.type.enum_def->name + "Union";
1649                 to_array = "_o." + namer_.Method("get", property_name) +
1650                            "()[_j].getType()";
1651                 break;
1652               case BASE_TYPE_UNION:
1653                 array_type = "int";
1654                 element_type = Prefixed(namer_.NamespacedType(
1655                                    *field.value.type.enum_def)) +
1656                                "Union";
1657                 to_array = element_type + ".pack(builder,  _o." +
1658                            namer_.Method("get", property_name) + "()[_j])";
1659                 break;
1660               case BASE_TYPE_UCHAR:  // TODO this branch of the switch is due to
1661                                      // inconsistent behavior in unsigned byte.
1662                                      // Read further at Issue #6574.
1663                 array_type = "byte";
1664                 element_type = "int";
1665                 to_array = "(byte) _e";
1666                 break;
1667               default:
1668                 gen_for_loop = false;
1669                 array_name = "_o." + namer_.Method("get", property_name) + "()";
1670                 array_type = GenTypeNameDest(field.value.type);
1671                 element_type = array_type;
1672                 to_array = "_e";
1673                 break;
1674             }
1675             code += "    int _" + field_name + " = 0;\n";
1676             code += "    if (_o." + namer_.Method("get", property_name) +
1677                     "() != null) {\n";
1678             if (gen_for_loop) {
1679               code += "      " + array_type + "[] " + array_name + " = new " +
1680                       array_type + "[_o." +
1681                       namer_.Method("get", property_name) + "().length];\n";
1682               code += "      int _j = 0;\n";
1683               code += "      for (" + element_type + " _e : _o." +
1684                       namer_.Method("get", property_name) + "()) { ";
1685               code += array_name + "[_j] = " + to_array + "; _j++;}\n";
1686             }
1687             code += "      _" + field_name + " = " +
1688                     namer_.Method("create", field) + "Vector(builder, " +
1689                     array_name + ");\n";
1690             code += "    }\n";
1691           } else {
1692             auto type_name = GenTypeGet(field.value.type);
1693             auto element_type_name =
1694                 GenTypeGet_ObjectAPI(field.value.type, true, true);
1695             auto pack_method =
1696                 field.value.type.struct_def == nullptr
1697                     ? "builder.add" + GenMethod(field.value.type.VectorType()) +
1698                           "(" + variable + "[_j]);"
1699                     : "_unused_offset = " + type_name + ".pack(builder, " +
1700                           variable + "[_j]);";
1701             code += "    int _" + field_name + " = 0;\n";
1702             code += "    " + element_type_name + "[] " + variable + " = _o." +
1703                     get_field + "();\n";
1704             code += "    if (" + variable + " != null) {\n";
1705             if (field.value.type.struct_def != nullptr) {
1706               code += "      int _unused_offset = 0;\n";
1707             }
1708             code += "      " + namer_.Method("start", field) +
1709                     "Vector(builder, " + variable + ".length);\n";
1710             code += "      for (int _j = " + variable +
1711                     ".length - 1; _j >=0; _j--) { ";
1712             code += pack_method + "}\n";
1713             code += "      _" + field_name + " = builder.endVector();\n";
1714             code += "    }\n";
1715           }
1716           break;
1717         }
1718         case BASE_TYPE_ARRAY: {
1719           if (field.value.type.struct_def != nullptr) {
1720             std::vector<FieldArrayLength> array_lengths;
1721             FieldArrayLength tmp_array_length = {
1722               field.name,
1723               field.value.type.fixed_length,
1724             };
1725             array_lengths.push_back(tmp_array_length);
1726             GenStructPackDecl_ObjectAPI(*field.value.type.struct_def,
1727                                         array_lengths, code);
1728           } else {
1729             code += "    " +
1730                     GenTypeGet_ObjectAPI(field.value.type, false, true) + " _" +
1731                     field_name + " = _o." + get_field + "();\n";
1732           }
1733           break;
1734         }
1735         case BASE_TYPE_UNION: {
1736           code += "    " +
1737                   GenTypeBasic(DestinationType(
1738                       field.value.type.enum_def->underlying_type, false)) +
1739                   " _" + field_name + "Type = _o." + get_field +
1740                   "() == null ? " +
1741                   Prefixed(namer_.NamespacedType(*field.value.type.enum_def)) +
1742                   ".NONE : " + "_o." + get_field + "().getType();\n";
1743           code += "    " + GenOffsetType() + " _" + field_name + " = _o." +
1744                   get_field + "() == null ? 0 : " +
1745                   Prefixed(namer_.NamespacedType(*field.value.type.enum_def)) +
1746                   "Union.pack(builder, _o." + get_field + "());\n";
1747           break;
1748         }
1749         default: break;
1750       }
1751     }
1752     if (struct_has_create) {
1753       // Create
1754       code += "    return " +
1755               namer_.LegacyJavaMethod2("create", struct_def, "") + "(\n";
1756       code += "      builder";
1757       for (auto it = struct_def.fields.vec.begin();
1758            it != struct_def.fields.vec.end(); ++it) {
1759         auto &field = **it;
1760         if (field.deprecated) continue;
1761         const auto field_name = namer_.Field(field);
1762         const auto get_field = namer_.Method("get", field);
1763         switch (field.value.type.base_type) {
1764           case BASE_TYPE_STRUCT: {
1765             if (struct_def.fixed) {
1766               GenStructPackCall_ObjectAPI(*field.value.type.struct_def, code,
1767                                           "      _" + field_name + "_");
1768             } else {
1769               code += ",\n";
1770               if (field.value.type.struct_def->fixed) {
1771                 if (opts.generate_object_based_api)
1772                   code += "      _o." + field_name;
1773                 else
1774                   // Seems like unreachable code
1775                   code += "      " + GenTypeGet(field.value.type) +
1776                           ".Pack(builder, _o." + field_name + ")";
1777               } else {
1778                 code += "      _" + field_name;
1779               }
1780             }
1781             break;
1782           }
1783           case BASE_TYPE_ARRAY: {
1784             if (field.value.type.struct_def != nullptr) {
1785               GenStructPackCall_ObjectAPI(*field.value.type.struct_def, code,
1786                                           "      _" + field_name + "_");
1787             } else {
1788               code += ",\n";
1789               code += "      _" + field_name;
1790             }
1791             break;
1792           }
1793           case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH();   // fall thru
1794           case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH();   // fall thru
1795           case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH();  // fall thru
1796           case BASE_TYPE_VECTOR: {
1797             code += ",\n";
1798             code += "      _" + field_name;
1799             break;
1800           }
1801           default:  // scalar
1802             code += ",\n";
1803             code += "      _o." + get_field + "()";
1804             break;
1805         }
1806       }
1807       code += ");\n";
1808     } else {
1809       // Start, End
1810       code += "    " + namer_.LegacyJavaMethod2("start", struct_def, "") +
1811               "(builder);\n";
1812       for (auto it = struct_def.fields.vec.begin();
1813            it != struct_def.fields.vec.end(); ++it) {
1814         auto &field = **it;
1815         if (field.deprecated) continue;
1816         const auto arg = "_" + namer_.Variable(field);
1817         const auto get_field = namer_.Method("get", field);
1818         const auto add_field = namer_.Method("add", field);
1819 
1820         switch (field.value.type.base_type) {
1821           case BASE_TYPE_STRUCT: {
1822             if (field.value.type.struct_def->fixed) {
1823               code += "    " + add_field + "(builder, " +
1824                       GenTypeGet(field.value.type) + ".pack(builder, _o." +
1825                       get_field + "()));\n";
1826             } else {
1827               code += "    " + add_field + "(builder, " + arg + ");\n";
1828             }
1829             break;
1830           }
1831           case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH();  // fall thru
1832           case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();   // fall thru
1833           case BASE_TYPE_VECTOR: {
1834             code += "    " + add_field + "(builder, " + arg + ");\n";
1835             break;
1836           }
1837           case BASE_TYPE_UTYPE: break;
1838           case BASE_TYPE_UNION: {
1839             code += "    " + add_field + "Type(builder, " + arg + "Type);\n";
1840             code += "    " + add_field + "(builder, " + arg + ");\n";
1841             break;
1842           }
1843           // scalar
1844           default: {
1845             if (field.IsScalarOptional()) {
1846               code += "    if (_o." + get_field + "() != null) { " + add_field +
1847                       "(builder, _o." + get_field + "()); }\n";
1848             } else {
1849               code +=
1850                   "    " + add_field + "(builder, _o." + get_field + "());\n";
1851             }
1852             break;
1853           }
1854         }
1855       }
1856       code += "    return " + namer_.LegacyJavaMethod2("end", struct_def, "") +
1857               "(builder);\n";
1858     }
1859     code += "  }\n";
1860   }
1861 
GenStructPackDecl_ObjectAPI(const StructDef & struct_def,std::vector<FieldArrayLength> & array_lengths,std::string & code) const1862   void GenStructPackDecl_ObjectAPI(const StructDef &struct_def,
1863                                    std::vector<FieldArrayLength> &array_lengths,
1864                                    std::string &code) const {
1865     for (auto it = struct_def.fields.vec.begin();
1866          it != struct_def.fields.vec.end(); ++it) {
1867       const FieldDef &field = **it;
1868       const bool is_array = IsArray(field.value.type);
1869       const Type &field_type =
1870           is_array ? field.value.type.VectorType() : field.value.type;
1871       FieldArrayLength tmp_array_length = {
1872         field.name,
1873         field_type.fixed_length,
1874       };
1875       array_lengths.push_back(tmp_array_length);
1876       if (field_type.struct_def != nullptr) {
1877         GenStructPackDecl_ObjectAPI(*field_type.struct_def, array_lengths,
1878                                     code);
1879       } else {
1880         std::vector<FieldArrayLength> array_only_lengths;
1881         for (size_t i = 0; i < array_lengths.size(); ++i) {
1882           if (array_lengths[i].length > 0) {
1883             array_only_lengths.push_back(array_lengths[i]);
1884           }
1885         }
1886         std::string name;
1887         for (size_t i = 0; i < array_lengths.size(); ++i) {
1888           name += "_" + namer_.Variable(array_lengths[i].name);
1889         }
1890         code += "    " + GenTypeBasic(field_type);
1891         if (array_only_lengths.size() > 0) {
1892           for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1893             code += "[]";
1894           }
1895           code += " " + name + " = ";
1896           code += "new " + GenTypeBasic(field_type) + "[";
1897           for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1898             if (i != 0) { code += "]["; }
1899             code += NumToString(array_only_lengths[i].length);
1900           }
1901           code += "];\n";
1902           code += "    ";
1903           // initialize array
1904           for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1905             auto idx = "idx" + NumToString(i);
1906             code += "for (int " + idx + " = 0; " + idx + " < " +
1907                     NumToString(array_only_lengths[i].length) + "; ++" + idx +
1908                     ") {";
1909           }
1910           for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1911             auto idx = "idx" + NumToString(i);
1912             if (i == 0) {
1913               code += name + "[" + idx;
1914             } else {
1915               code += "][" + idx;
1916             }
1917           }
1918           code += "] = _o";
1919           for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) {
1920             code += "." + namer_.Method("get", array_lengths[i].name) + "()";
1921             if (array_lengths[i].length <= 0) continue;
1922             code += "[idx" + NumToString(j++) + "]";
1923           }
1924           code += ";";
1925           for (size_t i = 0; i < array_only_lengths.size(); ++i) {
1926             code += "}";
1927           }
1928         } else {
1929           code += " " + name + " = ";
1930           code += SourceCast(field_type);
1931           code += "_o";
1932           for (size_t i = 0; i < array_lengths.size(); ++i) {
1933             code += "." + namer_.Method("get", array_lengths[i].name) + "()";
1934           }
1935           code += ";";
1936         }
1937         code += "\n";
1938       }
1939       array_lengths.pop_back();
1940     }
1941   }
1942 
GenStructPackCall_ObjectAPI(const StructDef & struct_def,std::string & code,std::string prefix) const1943   void GenStructPackCall_ObjectAPI(const StructDef &struct_def,
1944                                    std::string &code,
1945                                    std::string prefix) const {
1946     for (auto it = struct_def.fields.vec.begin();
1947          it != struct_def.fields.vec.end(); ++it) {
1948       auto &field = **it;
1949       const auto &field_type = field.value.type;
1950       if (field_type.struct_def != nullptr) {
1951         GenStructPackCall_ObjectAPI(*field_type.struct_def, code,
1952                                     prefix + namer_.Field(field) + "_");
1953       } else {
1954         code += ",\n";
1955         code += prefix + namer_.Field(field);
1956       }
1957     }
1958   }
1959 
ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(const std::string & type_name) const1960   std::string ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(
1961       const std::string &type_name) const {
1962     if (type_name == "boolean")
1963       return "Boolean";
1964     else if (type_name == "byte")
1965       return "Byte";
1966     else if (type_name == "char")
1967       return "Character";
1968     else if (type_name == "short")
1969       return "Short";
1970     else if (type_name == "int")
1971       return "Integer";
1972     else if (type_name == "long")
1973       return "Long";
1974     else if (type_name == "float")
1975       return "Float";
1976     else if (type_name == "double")
1977       return "Double";
1978     return type_name;
1979   }
1980 
GenTypeGet_ObjectAPI(const flatbuffers::Type & type,bool vectorelem,bool wrap_in_namespace) const1981   std::string GenTypeGet_ObjectAPI(const flatbuffers::Type &type,
1982                                    bool vectorelem,
1983                                    bool wrap_in_namespace) const {
1984     auto type_name = GenTypeNameDest(type);
1985     // Replace to ObjectBaseAPI Type Name
1986     switch (type.base_type) {
1987       case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH();  // fall thru
1988       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();   // fall thru
1989       case BASE_TYPE_VECTOR: {
1990         if (type.struct_def != nullptr) {
1991           auto type_name_length = type.struct_def->name.length();
1992           auto new_type_name = namer_.ObjectType(*type.struct_def);
1993           type_name.replace(type_name.length() - type_name_length,
1994                             type_name_length, new_type_name);
1995         } else if (type.element == BASE_TYPE_UNION) {
1996           if (wrap_in_namespace) {
1997             type_name =
1998                 Prefixed(namer_.NamespacedType(*type.enum_def)) + "Union";
1999           } else {
2000             type_name = namer_.Type(*type.enum_def) + "Union";
2001           }
2002         }
2003         break;
2004       }
2005 
2006       case BASE_TYPE_UNION: {
2007         if (wrap_in_namespace) {
2008           type_name = Prefixed(namer_.NamespacedType(*type.enum_def)) + "Union";
2009         } else {
2010           type_name = namer_.Type(*type.enum_def) + "Union";
2011         }
2012         break;
2013       }
2014       default: break;
2015     }
2016     if (vectorelem) { return type_name; }
2017     switch (type.base_type) {
2018       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
2019       case BASE_TYPE_VECTOR: {
2020         type_name = type_name + "[]";
2021         break;
2022       }
2023       default: break;
2024     }
2025     return type_name;
2026   }
2027 
GenConcreteTypeGet_ObjectAPI(const flatbuffers::Type & type) const2028   std::string GenConcreteTypeGet_ObjectAPI(
2029       const flatbuffers::Type &type) const {
2030     auto type_name = GenTypeNameDest(type);
2031     // Replace to ObjectBaseAPI Type Name
2032     switch (type.base_type) {
2033       case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH();  // fall thru
2034       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();   // fall thru
2035       case BASE_TYPE_VECTOR: {
2036         if (type.struct_def != nullptr) {
2037           auto type_name_length = type.struct_def->name.length();
2038           auto new_type_name = namer_.ObjectType(*type.struct_def);
2039           type_name.replace(type_name.length() - type_name_length,
2040                             type_name_length, new_type_name);
2041         } else if (type.element == BASE_TYPE_UNION) {
2042           type_name = Prefixed(namer_.NamespacedType(*type.enum_def)) + "Union";
2043         }
2044         break;
2045       }
2046 
2047       case BASE_TYPE_UNION: {
2048         type_name = Prefixed(namer_.NamespacedType(*type.enum_def)) + "Union";
2049         break;
2050       }
2051       default: break;
2052     }
2053 
2054     switch (type.base_type) {
2055       case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH();  // fall thru
2056       case BASE_TYPE_VECTOR: {
2057         type_name = type_name + "[]";
2058         break;
2059       }
2060       default: break;
2061     }
2062     return type_name;
2063   }
2064 
GenStruct_ObjectAPI(const StructDef & struct_def,std::string & code) const2065   void GenStruct_ObjectAPI(const StructDef &struct_def,
2066                            std::string &code) const {
2067     if (struct_def.generated) return;
2068     if (struct_def.attributes.Lookup("private")) {
2069       // For Java, we leave the enum unmarked to indicate package-private
2070     } else {
2071       code += "public ";
2072     }
2073 
2074     const auto class_name = namer_.ObjectType(struct_def);
2075     code += "class " + class_name;
2076     code += " {\n";
2077     // Generate Properties
2078     for (auto it = struct_def.fields.vec.begin();
2079          it != struct_def.fields.vec.end(); ++it) {
2080       const auto &field = **it;
2081       if (field.deprecated) continue;
2082       if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2083       if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2084       auto type_name = GenTypeGet_ObjectAPI(field.value.type, false, true);
2085       if (field.IsScalarOptional())
2086         type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
2087       const auto field_name = namer_.Field(field);
2088       code += "  private " + type_name + " " + field_name + ";\n";
2089     }
2090     // Generate Java getters and setters
2091     code += "\n";
2092     for (auto it = struct_def.fields.vec.begin();
2093          it != struct_def.fields.vec.end(); ++it) {
2094       const auto &field = **it;
2095       if (field.deprecated) continue;
2096       if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2097       if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2098       const auto field_name = namer_.Field(field);
2099       const auto get_field = namer_.Method("get", field);
2100       auto type_name = GenTypeGet_ObjectAPI(field.value.type, false, true);
2101       if (field.IsScalarOptional())
2102         type_name = ConvertPrimitiveTypeToObjectWrapper_ObjectAPI(type_name);
2103 
2104       code += "  public " + type_name + " " + get_field + "() { return " +
2105               field_name + "; }\n\n";
2106       std::string array_validation = "";
2107       if (field.value.type.base_type == BASE_TYPE_ARRAY) {
2108         array_validation =
2109             "if (" + field_name + " != null && " + field_name +
2110             ".length == " + NumToString(field.value.type.fixed_length) + ") ";
2111       }
2112       code += "  public void " + namer_.Method("set", field) + "(" + type_name +
2113               " " + field_name + ") { " + array_validation + "this." +
2114               field_name + " = " + field_name + "; }\n\n";
2115     }
2116     // Generate Constructor
2117     code += "\n";
2118     code += "  public " + class_name + "() {\n";
2119     for (auto it = struct_def.fields.vec.begin();
2120          it != struct_def.fields.vec.end(); ++it) {
2121       const auto &field = **it;
2122       if (field.deprecated) continue;
2123       if (field.value.type.base_type == BASE_TYPE_UTYPE) continue;
2124       if (field.value.type.element == BASE_TYPE_UTYPE) continue;
2125       const auto get_field = namer_.Method("get", field);
2126 
2127       code += "    this." + namer_.Field(field) + " = ";
2128       const auto type_name =
2129           GenTypeGet_ObjectAPI(field.value.type, false, true);
2130       if (IsScalar(field.value.type.base_type)) {
2131         if (field.IsScalarOptional()) {
2132           code += "null;\n";
2133         } else {
2134           code += GenDefaultValue(field) + ";\n";
2135         }
2136       } else {
2137         switch (field.value.type.base_type) {
2138           case BASE_TYPE_STRUCT: {
2139             if (IsStruct(field.value.type)) {
2140               code += "new " + type_name + "();\n";
2141             } else {
2142               code += "null;\n";
2143             }
2144             break;
2145           }
2146           case BASE_TYPE_ARRAY: {
2147             code += "new " + type_name.substr(0, type_name.length() - 1) +
2148                     NumToString(field.value.type.fixed_length) + "];\n";
2149             break;
2150           }
2151           default: {
2152             code += "null;\n";
2153             break;
2154           }
2155         }
2156       }
2157     }
2158     code += "  }\n";
2159     if (parser_.root_struct_def_ == &struct_def) {
2160       const std::string struct_type = namer_.Type(struct_def);
2161       code += "  public static " + class_name +
2162               " deserializeFromBinary(byte[] fbBuffer) {\n";
2163       code += "    return " + struct_type + "." +
2164               namer_.LegacyJavaMethod2("getRootAs", struct_def, "") +
2165               "(ByteBuffer.wrap(fbBuffer)).unpack();\n";
2166       code += "  }\n";
2167       code += "  public byte[] serializeToBinary() {\n";
2168       code += "    FlatBufferBuilder fbb = new FlatBufferBuilder();\n";
2169       code += "    " + struct_type + "." +
2170               namer_.LegacyJavaMethod2("finish", struct_def, "Buffer") +
2171               "(fbb, " + struct_type + ".pack(fbb, this));\n";
2172       code += "    return fbb.sizedByteArray();\n";
2173       code += "  }\n";
2174     }
2175     code += "}\n\n";
2176   }
2177 
2178   // This tracks the current namespace used to determine if a type need to be
2179   // prefixed by its namespace
2180   const Namespace *cur_name_space_;
2181   const IdlNamer namer_;
2182 
2183  private:
Prefixed(const std::string & str) const2184   std::string Prefixed(const std::string &str) const {
2185     return package_prefix_ + str;
2186   }
2187 
2188   std::string package_prefix_;
2189   Namespace package_prefix_ns_;
2190 };
2191 }  // namespace java
2192 
GenerateJava(const Parser & parser,const std::string & path,const std::string & file_name)2193 static bool GenerateJava(const Parser &parser, const std::string &path,
2194                          const std::string &file_name) {
2195   java::JavaGenerator generator(parser, path, file_name,
2196                                 parser.opts.java_package_prefix);
2197   return generator.generate();
2198 }
2199 
2200 namespace {
2201 
2202 class JavaCodeGenerator : public CodeGenerator {
2203  public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)2204   Status GenerateCode(const Parser &parser, const std::string &path,
2205                       const std::string &filename) override {
2206     if (!GenerateJava(parser, path, filename)) { return Status::ERROR; }
2207     return Status::OK;
2208   }
2209 
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)2210   Status GenerateCode(const uint8_t *, int64_t,
2211                       const CodeGenOptions &) override {
2212     return Status::NOT_IMPLEMENTED;
2213   }
2214 
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)2215   Status GenerateMakeRule(const Parser &parser, const std::string &path,
2216                           const std::string &filename,
2217                           std::string &output) override {
2218     output = JavaCSharpMakeRule(true, parser, path, filename);
2219     return Status::OK;
2220   }
2221 
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)2222   Status GenerateGrpcCode(const Parser &parser, const std::string &path,
2223                           const std::string &filename) override {
2224     if (!GenerateJavaGRPC(parser, path, filename)) { return Status::ERROR; }
2225     return Status::OK;
2226   }
2227 
GenerateRootFile(const Parser & parser,const std::string & path)2228   Status GenerateRootFile(const Parser &parser,
2229                           const std::string &path) override {
2230     (void)parser;
2231     (void)path;
2232     return Status::NOT_IMPLEMENTED;
2233   }
2234 
IsSchemaOnly() const2235   bool IsSchemaOnly() const override { return true; }
2236 
SupportsBfbsGeneration() const2237   bool SupportsBfbsGeneration() const override { return false; }
2238 
SupportsRootFileGeneration() const2239   bool SupportsRootFileGeneration() const override { return false; }
2240 
Language() const2241   IDLOptions::Language Language() const override { return IDLOptions::kJava; }
2242 
LanguageName() const2243   std::string LanguageName() const override { return "Java"; }
2244 };
2245 }  // namespace
2246 
NewJavaCodeGenerator()2247 std::unique_ptr<CodeGenerator> NewJavaCodeGenerator() {
2248   return std::unique_ptr<JavaCodeGenerator>(new JavaCodeGenerator());
2249 }
2250 
2251 }  // namespace flatbuffers
2252