...

Text file src/github.com/google/flatbuffers/src/idl_gen_java.cpp

Documentation: github.com/google/flatbuffers/src

     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
    27namespace flatbuffers {
    28namespace java {
    29
    30namespace {
    31
    32static 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
    57static 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
    72static const TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.",
    73                                                      "NaN",
    74                                                      "POSITIVE_INFINITY",
    75                                                      "NEGATIVE_INFINITY");
    76
    77static const CommentConfig comment_config = {
    78  "/**",
    79  " *",
    80  " */",
    81};
    82
    83}  // namespace
    84
    85class JavaGenerator : public BaseGenerator {
    86  struct FieldArrayLength {
    87    std::string name;
    88    int length;
    89  };
    90
    91 public:
    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 &);
   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.
   179  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
   231  const Namespace *CurrentNameSpace() const { return cur_name_space_; }
   232
   233  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
   241  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
   248  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
   260  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
   271  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).
   280  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
   295  std::string GenOffsetType() const { return "int"; }
   296
   297  std::string GenOffsetConstruct(const std::string &variable_name) const {
   298    return variable_name;
   299  }
   300
   301  std::string GenVectorOffsetType() const { return "int"; }
   302
   303  // Generate destination type name
   304  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.
   309  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
   322  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.
   336  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
   352  std::string SourceCast(const Type &type) const {
   353    return SourceCast(type, true);
   354  }
   355
   356  std::string SourceCastBasic(const Type &type, bool castFromDest) const {
   357    return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : "";
   358  }
   359
   360  std::string SourceCastBasic(const Type &type) const {
   361    return SourceCastBasic(type, true);
   362  }
   363
   364  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
   374  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
   399  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
   405  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.
   476  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.
   496  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.
   513  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.
   526  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.
   534  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.
   564  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
   615  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
   629  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
   648  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
   672  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_23_5_26(); ";
   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
  1290  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
  1297  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
  1356  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
  1422  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
  1475  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
  1862  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
  1943  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
  1960  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
  1981  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
  2028  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
  2065  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:
  2184  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
  2193static 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
  2200namespace {
  2201
  2202class JavaCodeGenerator : public CodeGenerator {
  2203 public:
  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
  2210  Status GenerateCode(const uint8_t *, int64_t,
  2211                      const CodeGenOptions &) override {
  2212    return Status::NOT_IMPLEMENTED;
  2213  }
  2214
  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
  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
  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
  2235  bool IsSchemaOnly() const override { return true; }
  2236
  2237  bool SupportsBfbsGeneration() const override { return false; }
  2238
  2239  bool SupportsRootFileGeneration() const override { return false; }
  2240
  2241  IDLOptions::Language Language() const override { return IDLOptions::kJava; }
  2242
  2243  std::string LanguageName() const override { return "Java"; }
  2244};
  2245}  // namespace
  2246
  2247std::unique_ptr<CodeGenerator> NewJavaCodeGenerator() {
  2248  return std::unique_ptr<JavaCodeGenerator>(new JavaCodeGenerator());
  2249}
  2250
  2251}  // namespace flatbuffers

View as plain text