Fix nullability of generated Kotlin ByteBuffer accessors (#8844)

* fixes #8691
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
index 2ed89d4..9101a91 100644
--- a/src/idl_gen_kotlin.cpp
+++ b/src/idl_gen_kotlin.cpp
@@ -1201,11 +1201,12 @@
                             : InlineSize(field.value.type.VectorType()));
         // Generate a ByteBuffer accessor for strings & vectors of scalars.
         // e.g.
-        // val inventoryByteBuffer: ByteBuffer
+        // val inventoryByteBuffer: ByteBuffer?
         //     get =  __vector_as_bytebuffer(14, 1)
 
+        auto buffer_type = field.IsRequired() ? "ByteBuffer" : "ByteBuffer?";
         GenerateGetterOneLine(
-            writer, field_name + "AsByteBuffer", "ByteBuffer", [&]() {
+            writer, field_name + "AsByteBuffer", buffer_type, [&]() {
               writer.SetValue("end", end_idx);
               writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
             });
@@ -1213,10 +1214,10 @@
         // Generate a ByteBuffer accessor for strings & vectors of scalars.
         // e.g.
         // fun inventoryInByteBuffer(_bb: Bytebuffer):
-        //     ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+        //     ByteBuffer? = __vector_as_bytebuffer(_bb, 14, 1)
         GenerateFunOneLine(
             writer, field_name + "InByteBuffer", "_bb: ByteBuffer",
-            "ByteBuffer", [&]() {
+            buffer_type, [&]() {
               writer.SetValue("end", end_idx);
               writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
             });
diff --git a/tests/KotlinTest.kt b/tests/KotlinTest.kt
index b9ee393..94e7496 100644
--- a/tests/KotlinTest.kt
+++ b/tests/KotlinTest.kt
@@ -80,6 +80,7 @@
       TestSharedStringPool()
       TestScalarOptional()
       TestDictionaryLookup()
+      TestNullFields()
       println("FlatBuffers test: completed successfully")
     }
 
@@ -142,7 +143,7 @@
       assert(invsum == 10u)
 
       // Alternative way of accessing a vector:
-      val ibb = monster.inventoryAsByteBuffer
+      val ibb = monster.inventoryAsByteBuffer!!
       invsum = 0u
       while (ibb.position() < ibb.limit()) invsum += ibb.get().toUInt()
       assert(invsum == 10u)
@@ -615,5 +616,37 @@
       assert(scalarStuff.maybeEnum == OptionalByte.Two)
       assert(scalarStuff.defaultEnum == OptionalByte.Two)
     }
+
+    fun TestNullFields() {
+      val fbb = FlatBufferBuilder(1)
+      val nameOffset = fbb.createString("name")
+      Monster.startMonster(fbb)
+      Monster.addName(fbb, nameOffset)
+      Monster.finishMonsterBuffer(fbb, Monster.endMonster(fbb))
+
+      val monsterBb = fbb.dataBuffer()
+      val monster = Monster.getRootAsMonster(monsterBb.duplicate())
+      assert(monster.pos == null) // struct
+      assert(monster.enemy == null) // table
+      assert(monster.test(Monster()) == null) // union
+      assert(monster.testType == Any_.NONE)
+      assert(monster.inventoryLength == 0) // vector of scalars
+      assert(monster.inventoryAsByteBuffer == null)
+      assert(monster.inventoryInByteBuffer(monsterBb) == null)
+      assert(monster.testarrayofsortedstructLength == 0) // vector of structs
+      assert(monster.testarrayofstringLength == 0) // vector of strings
+      assert(monster.testarrayoftablesLength == 0) // vector of tables
+
+
+      val fbb2 = FlatBufferBuilder(1)
+      val offset = Stat.createStat(fbb2, 0, 10, 10.toUShort())
+      fbb2.finish(offset)
+
+      val statBb = fbb2.dataBuffer()
+      val stat = Stat.getRootAsStat(statBb.duplicate())
+      assert(stat.id == null) // string
+      assert(stat.idAsByteBuffer == null)
+      assert(stat.idInByteBuffer(statBb) == null)
+    }
   }
 }
diff --git a/tests/MyGame/Example/Monster.kt b/tests/MyGame/Example/Monster.kt
index 9dfdc30..4e10a8a 100644
--- a/tests/MyGame/Example/Monster.kt
+++ b/tests/MyGame/Example/Monster.kt
@@ -91,8 +91,8 @@
         get() {
             val o = __offset(14); return if (o != 0) __vector_len(o) else 0
         }
-    val inventoryAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(14, 1)
-    fun inventoryInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 14, 1)
+    val inventoryAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(14, 1)
+    fun inventoryInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 14, 1)
     fun mutateInventory(j: Int, inventory: UByte) : Boolean {
         val o = __offset(14)
         return if (o != 0) {
@@ -212,8 +212,8 @@
         get() {
             val o = __offset(30); return if (o != 0) __vector_len(o) else 0
         }
-    val testnestedflatbufferAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(30, 1)
-    fun testnestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 30, 1)
+    val testnestedflatbufferAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(30, 1)
+    fun testnestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 30, 1)
     val testnestedflatbufferAsMonster : MyGame.Example.Monster? get() = testnestedflatbufferAsMonster(MyGame.Example.Monster())
     fun testnestedflatbufferAsMonster(obj: MyGame.Example.Monster) : MyGame.Example.Monster? {
         val o = __offset(30)
@@ -379,8 +379,8 @@
         get() {
             val o = __offset(52); return if (o != 0) __vector_len(o) else 0
         }
-    val testarrayofboolsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(52, 1)
-    fun testarrayofboolsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 52, 1)
+    val testarrayofboolsAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(52, 1)
+    fun testarrayofboolsInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 52, 1)
     fun mutateTestarrayofbools(j: Int, testarrayofbools: Boolean) : Boolean {
         val o = __offset(52)
         return if (o != 0) {
@@ -469,8 +469,8 @@
         get() {
             val o = __offset(64); return if (o != 0) __vector_len(o) else 0
         }
-    val flexAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(64, 1)
-    fun flexInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 64, 1)
+    val flexAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(64, 1)
+    fun flexInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 64, 1)
     fun mutateFlex(j: Int, flex: UByte) : Boolean {
         val o = __offset(64)
         return if (o != 0) {
@@ -505,8 +505,8 @@
         get() {
             val o = __offset(68); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfLongsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(68, 8)
-    fun vectorOfLongsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 68, 8)
+    val vectorOfLongsAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(68, 8)
+    fun vectorOfLongsInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 68, 8)
     fun mutateVectorOfLongs(j: Int, vectorOfLongs: Long) : Boolean {
         val o = __offset(68)
         return if (o != 0) {
@@ -528,8 +528,8 @@
         get() {
             val o = __offset(70); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfDoublesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(70, 8)
-    fun vectorOfDoublesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 70, 8)
+    val vectorOfDoublesAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(70, 8)
+    fun vectorOfDoublesInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 70, 8)
     fun mutateVectorOfDoubles(j: Int, vectorOfDoubles: Double) : Boolean {
         val o = __offset(70)
         return if (o != 0) {
@@ -603,8 +603,8 @@
         get() {
             val o = __offset(78); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfWeakReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(78, 8)
-    fun vectorOfWeakReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 78, 8)
+    val vectorOfWeakReferencesAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(78, 8)
+    fun vectorOfWeakReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 78, 8)
     fun mutateVectorOfWeakReferences(j: Int, vectorOfWeakReferences: ULong) : Boolean {
         val o = __offset(78)
         return if (o != 0) {
@@ -669,8 +669,8 @@
         get() {
             val o = __offset(84); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfCoOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(84, 8)
-    fun vectorOfCoOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 84, 8)
+    val vectorOfCoOwningReferencesAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(84, 8)
+    fun vectorOfCoOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 84, 8)
     fun mutateVectorOfCoOwningReferences(j: Int, vectorOfCoOwningReferences: ULong) : Boolean {
         val o = __offset(84)
         return if (o != 0) {
@@ -706,8 +706,8 @@
         get() {
             val o = __offset(88); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfNonOwningReferencesAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(88, 8)
-    fun vectorOfNonOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 88, 8)
+    val vectorOfNonOwningReferencesAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(88, 8)
+    fun vectorOfNonOwningReferencesInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 88, 8)
     fun mutateVectorOfNonOwningReferences(j: Int, vectorOfNonOwningReferences: ULong) : Boolean {
         val o = __offset(88)
         return if (o != 0) {
@@ -763,8 +763,8 @@
         get() {
             val o = __offset(98); return if (o != 0) __vector_len(o) else 0
         }
-    val vectorOfEnumsAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(98, 1)
-    fun vectorOfEnumsInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 98, 1)
+    val vectorOfEnumsAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(98, 1)
+    fun vectorOfEnumsInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 98, 1)
     fun mutateVectorOfEnums(j: Int, vectorOfEnums: UByte) : Boolean {
         val o = __offset(98)
         return if (o != 0) {
@@ -800,8 +800,8 @@
         get() {
             val o = __offset(102); return if (o != 0) __vector_len(o) else 0
         }
-    val testrequirednestedflatbufferAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(102, 1)
-    fun testrequirednestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 102, 1)
+    val testrequirednestedflatbufferAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(102, 1)
+    fun testrequirednestedflatbufferInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 102, 1)
     val testrequirednestedflatbufferAsMonster : MyGame.Example.Monster? get() = testrequirednestedflatbufferAsMonster(MyGame.Example.Monster())
     fun testrequirednestedflatbufferAsMonster(obj: MyGame.Example.Monster) : MyGame.Example.Monster? {
         val o = __offset(102)
diff --git a/tests/MyGame/Example/Stat.kt b/tests/MyGame/Example/Stat.kt
index 26ee253..d7bc296 100644
--- a/tests/MyGame/Example/Stat.kt
+++ b/tests/MyGame/Example/Stat.kt
@@ -37,8 +37,8 @@
                 null
             }
         }
-    val idAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(4, 1)
-    fun idInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 4, 1)
+    val idAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(4, 1)
+    fun idInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 4, 1)
     val val_ : Long
         get() {
             val o = __offset(6)
diff --git a/tests/MyGame/Example/TypeAliases.kt b/tests/MyGame/Example/TypeAliases.kt
index d73f78b..b00eb54 100644
--- a/tests/MyGame/Example/TypeAliases.kt
+++ b/tests/MyGame/Example/TypeAliases.kt
@@ -180,8 +180,8 @@
         get() {
             val o = __offset(24); return if (o != 0) __vector_len(o) else 0
         }
-    val v8AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(24, 1)
-    fun v8InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 24, 1)
+    val v8AsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(24, 1)
+    fun v8InByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 24, 1)
     fun mutateV8(j: Int, v8: Byte) : Boolean {
         val o = __offset(24)
         return if (o != 0) {
@@ -203,8 +203,8 @@
         get() {
             val o = __offset(26); return if (o != 0) __vector_len(o) else 0
         }
-    val vf64AsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(26, 8)
-    fun vf64InByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 26, 8)
+    val vf64AsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(26, 8)
+    fun vf64InByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 26, 8)
     fun mutateVf64(j: Int, vf64: Double) : Boolean {
         val o = __offset(26)
         return if (o != 0) {
diff --git a/tests/MyGame/MonsterExtra.kt b/tests/MyGame/MonsterExtra.kt
index d8c8d15..e38abc2 100644
--- a/tests/MyGame/MonsterExtra.kt
+++ b/tests/MyGame/MonsterExtra.kt
@@ -152,8 +152,8 @@
         get() {
             val o = __offset(20); return if (o != 0) __vector_len(o) else 0
         }
-    val dvecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(20, 8)
-    fun dvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 20, 8)
+    val dvecAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(20, 8)
+    fun dvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 20, 8)
     fun mutateDvec(j: Int, dvec: Double) : Boolean {
         val o = __offset(20)
         return if (o != 0) {
@@ -175,8 +175,8 @@
         get() {
             val o = __offset(22); return if (o != 0) __vector_len(o) else 0
         }
-    val fvecAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(22, 4)
-    fun fvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 22, 4)
+    val fvecAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(22, 4)
+    fun fvecInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 22, 4)
     fun mutateFvec(j: Int, fvec: Float) : Boolean {
         val o = __offset(22)
         return if (o != 0) {
diff --git a/tests/union_vector/Movie.kt b/tests/union_vector/Movie.kt
index 0e8645d..aa04ad5 100644
--- a/tests/union_vector/Movie.kt
+++ b/tests/union_vector/Movie.kt
@@ -55,8 +55,8 @@
         get() {
             val o = __offset(8); return if (o != 0) __vector_len(o) else 0
         }
-    val charactersTypeAsByteBuffer : ByteBuffer get() = __vector_as_bytebuffer(8, 1)
-    fun charactersTypeInByteBuffer(_bb: ByteBuffer) : ByteBuffer = __vector_in_bytebuffer(_bb, 8, 1)
+    val charactersTypeAsByteBuffer : ByteBuffer? get() = __vector_as_bytebuffer(8, 1)
+    fun charactersTypeInByteBuffer(_bb: ByteBuffer) : ByteBuffer? = __vector_in_bytebuffer(_bb, 8, 1)
     fun mutateCharactersType(j: Int, charactersType: UByte) : Boolean {
         val o = __offset(8)
         return if (o != 0) {