Merge "Merge branch 'temp_72223856' of persistent-https://android.git.corp.google.com/platform/external/flatbuffers into merge1"
diff --git a/.gitattributes b/.gitattributes
old mode 100755
new mode 100644
diff --git a/.gitignore b/.gitignore
old mode 100755
new mode 100644
index 9dfabef..9dd3f49
--- a/.gitignore
+++ b/.gitignore
@@ -5,6 +5,7 @@
 *.o.d
 *.class
 *.a
+*.swp
 *~
 *.vcxproj
 *.vcxproj.filters
@@ -43,11 +44,14 @@
 grpctest
 grpctest.exe
 snapshot.sh
+tags
 tests/go_gen
 tests/monsterdata_java_wire.mon
 tests/monsterdata_go_wire.mon
 tests/monsterdata_javascript_wire.mon
 tests/unicode_test.mon
+tests/ts/
+tests/php/
 CMakeLists.txt.user
 CMakeScripts/**
 CTestTestfile.cmake
@@ -66,3 +70,15 @@
 build/VS2010/ipch/**/*.ipch
 *.so
 Testing/Temporary
+.cproject
+.settings/
+.project
+net/**/obj
+node_modules/
+android/.externalNativeBuild/
+android/.gradle/
+android/build/
+samples/android/.externalNativeBuild/
+samples/android/.gradle/
+samples/android/build/
+js/flatbuffers.mjs
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index bee8169..71847f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,31 +1,58 @@
-language: cpp
-
-os:
-- linux
-- osx
-
-compiler:
-  - gcc
-  #- clang
-
 env:
-  matrix:
-    - BUILD_TYPE=Debug BIICODE=false
-    - BUILD_TYPE=Release BIICODE=false
-    # biicode .deb files no longer available.
-    # - BUILD_TYPE=Release BIICODE=true
-    # - BUILD_TYPE=Debug BIICODE=true
   global:
+    # Set at the root level as this is ignored when set under matrix.env.
     - GCC_VERSION="4.9"
+matrix:
+  include:
+    - language: cpp
+      os:
+      - linux
+      - osx
+      
+      compiler:
+        - gcc
+        #- clang
+      
+      env:
+        matrix:
+          - BUILD_TYPE=Debug BIICODE=false
+          - BUILD_TYPE=Release BIICODE=false
+          # biicode .deb files no longer available.
+          # - BUILD_TYPE=Release BIICODE=true
+          # - BUILD_TYPE=Debug BIICODE=true
+      
+      before_install:
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
+      - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
+      
+      script:
+      - if [ "$BIICODE" == "false" ]; then cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test; fi
+      - if [ "$BIICODE" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then ./biicode/support/bii-travis.sh $BUILD_TYPE; fi
 
-before_install:
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
-- if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
-
-script:
-- if [ "$BIICODE" == "false" ]; then cmake -DCMAKE_BUILD_TYPE=$BUILD_TYPE . && make && make test; fi
-- if [ "$BIICODE" == "true" ] && [ "$TRAVIS_OS_NAME" == "linux" ]; then ./biicode/support/bii-travis.sh $BUILD_TYPE; fi
+    - language: android
+      sudo: true
+      android:
+        components:
+          - tools
+          - platform-tools
+          - build-tools-25.0.2
+          - android-25
+          - extra-android-m2repository
+      compiler:
+        - gcc
+      before_install:
+        - git clone https://github.com/urho3d/android-ndk.git $HOME/android-ndk-root
+        - export ANDROID_NDK_HOME=$HOME/android-ndk-root
+        # Setup environment for Linux build which is required to build the sample.
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test; fi
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get update -qq; fi
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq g++-$GCC_VERSION; fi
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo apt-get install -qq gcc-$GCC_VERSION; fi
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which g++-$GCC_VERSION) /usr/bin/g++; fi
+        - if [ "$TRAVIS_OS_NAME" == "linux" ]; then sudo ln -s -v -f $(which gcc-$GCC_VERSION) /usr/bin/gcc; fi
+      script:
+        - failed=0; for build_gradle in $(git ls-files | grep build.gradle); do ( cd "$(dirname "${build_gradle}")" && ./gradlew build ) || failed=1; done; exit $((failed))
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..1fd45d5
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,18 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_headers {
+    name: "flatbuffer_headers",
+    export_include_dirs: ["include"],
+}
\ No newline at end of file
diff --git a/CMake/FlatbuffersConfig.cmake b/CMake/FlatbuffersConfig.cmake
new file mode 100644
index 0000000..107d78e
--- /dev/null
+++ b/CMake/FlatbuffersConfig.cmake
@@ -0,0 +1,4 @@
+include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersTargets.cmake" OPTIONAL)
+include("${CMAKE_CURRENT_LIST_DIR}/FlatcTargets.cmake" OPTIONAL)
+include("${CMAKE_CURRENT_LIST_DIR}/FlatbuffersSharedTargets.cmake" OPTIONAL)
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3670afe..c3974b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,13 +24,17 @@
 
 set(FlatBuffers_Library_SRCS
   include/flatbuffers/code_generators.h
+  include/flatbuffers/base.h
   include/flatbuffers/flatbuffers.h
   include/flatbuffers/hash.h
   include/flatbuffers/idl.h
   include/flatbuffers/util.h
   include/flatbuffers/reflection.h
   include/flatbuffers/reflection_generated.h
+  include/flatbuffers/stl_emulation.h
   include/flatbuffers/flexbuffers.h
+  include/flatbuffers/registry.h
+  include/flatbuffers/minireflect.h
   src/code_generators.cpp
   src/idl_parser.cpp
   src/idl_gen_text.cpp
@@ -48,6 +52,7 @@
   src/idl_gen_python.cpp
   src/idl_gen_fbs.cpp
   src/idl_gen_grpc.cpp
+  src/idl_gen_json_schema.cpp
   src/flatc.cpp
   src/flatc_main.cpp
   grpc/src/compiler/schema_interface.h
@@ -102,7 +107,7 @@
   # is being configured externally
 elseif(APPLE)
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -stdlib=libc++")
-  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
 elseif(CMAKE_COMPILER_IS_GNUCXX)
   if(CYGWIN)
     set(CMAKE_CXX_FLAGS
@@ -126,9 +131,13 @@
 
 elseif(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
   set(CMAKE_CXX_FLAGS
-      "${CMAKE_CXX_FLAGS} -std=c++0x -stdlib=libc++ -Wall -pedantic -Werror \
-                          -Wextra")
-  if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD")
+      "${CMAKE_CXX_FLAGS} -std=c++0x -Wall -pedantic -Werror -Wextra -Wno-unused-parameter")
+  if(NOT "${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
+    set(CMAKE_CXX_FLAGS
+        "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+  endif()
+  if(NOT ("${CMAKE_SYSTEM_NAME}" MATCHES "FreeBSD" OR
+          "${CMAKE_SYSTEM_NAME}" MATCHES "Linux"))
     set(CMAKE_EXE_LINKER_FLAGS
         "${CMAKE_EXE_LINKER_FLAGS} -lc++abi")
   endif()
@@ -138,6 +147,11 @@
   set(CMAKE_CXX_FLAGS
     "${CMAKE_CXX_FLAGS} -fsigned-char")
 
+elseif(MSVC)
+  # Visual Studio pedantic build settings
+  # warning C4512: assignment operator could not be generated
+  # warning C4316: object allocated on the heap may not be aligned
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4 /WX /wd4512 /wd4316")
 endif()
 
 if(FLATBUFFERS_CODE_COVERAGE)
@@ -163,6 +177,10 @@
   if(NOT FLATBUFFERS_FLATC_EXECUTABLE)
     set(FLATBUFFERS_FLATC_EXECUTABLE $<TARGET_FILE:flatc>)
   endif()
+  if(MSVC)
+    # Make flatc.exe not depend on runtime dlls for easy distribution.
+    target_compile_options(flatc PUBLIC $<$<CONFIG:Release>:/MT>)
+  endif()
 endif()
 
 if(FLATBUFFERS_BUILD_FLATHASH)
@@ -171,7 +189,16 @@
 
 if(FLATBUFFERS_BUILD_SHAREDLIB)
   add_library(flatbuffers_shared SHARED ${FlatBuffers_Library_SRCS})
-  set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers)
+
+  # Shared object version: "major.minor.micro"
+  # - micro updated every release when there is no API/ABI changes
+  # - minor updated when there are additions in API/ABI
+  # - major (ABI number) updated when there are changes in ABI (or removals)
+  set(FlatBuffers_Library_SONAME_MAJOR "1")
+  set(FlatBuffers_Library_SONAME_FULL "${FlatBuffers_Library_SONAME_MAJOR}.8.0")
+  set_target_properties(flatbuffers_shared PROPERTIES OUTPUT_NAME flatbuffers
+                        SOVERSION "${FlatBuffers_Library_SONAME_MAJOR}"
+                        VERSION "${FlatBuffers_Library_SONAME_FULL}")
 endif()
 
 function(compile_flatbuffers_schema_to_cpp SRC_FBS)
@@ -181,6 +208,9 @@
     OUTPUT ${GEN_HEADER}
     COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}" -c --no-includes --gen-mutable
             --gen-object-api -o "${SRC_FBS_DIR}"
+            --cpp-ptr-type flatbuffers::unique_ptr # Used to test with C++98 STLs
+            --reflect-names
+            -I "${CMAKE_CURRENT_SOURCE_DIR}/tests/include_test"
             "${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
     DEPENDS flatc)
 endfunction()
@@ -211,22 +241,85 @@
 
 if(FLATBUFFERS_BUILD_GRPCTEST)
   if(CMAKE_COMPILER_IS_GNUCXX)
-    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter -Wno-shadow")
   endif()
   add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
-  target_link_libraries(grpctest grpc++_unsecure grpc pthread dl)
+  target_link_libraries(grpctest grpc++_unsecure grpc_unsecure pthread dl)
 endif()
 
 if(FLATBUFFERS_INSTALL)
-  install(DIRECTORY include/flatbuffers DESTINATION include)
+  include(GNUInstallDirs)
+
+  install(DIRECTORY include/flatbuffers DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
+
+  set(FB_CMAKE_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/flatbuffers")
+
+  install(
+      FILES "CMake/FlatbuffersConfig.cmake"
+      DESTINATION ${FB_CMAKE_DIR}
+  )
+
   if(FLATBUFFERS_BUILD_FLATLIB)
-    install(TARGETS flatbuffers DESTINATION lib)
+    if(CMAKE_VERSION VERSION_LESS 3.0)
+      install(
+        TARGETS flatbuffers EXPORT FlatbuffersTargets
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      )
+    else()
+      install(
+        TARGETS flatbuffers EXPORT FlatbuffersTargets
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+      )
+    endif()
+
+    install(EXPORT FlatbuffersTargets
+      FILE FlatbuffersTargets.cmake
+      NAMESPACE flatbuffers::
+      DESTINATION ${FB_CMAKE_DIR}
+    )
   endif()
+
   if(FLATBUFFERS_BUILD_FLATC)
-    install(TARGETS flatc DESTINATION bin)
+    install(
+      TARGETS flatc EXPORT FlatcTargets
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+      CONFIGURATIONS Release
+    )
+
+    install(
+      EXPORT FlatcTargets
+      FILE FlatcTargets.cmake
+      NAMESPACE flatbuffers::
+      DESTINATION ${FB_CMAKE_DIR}
+      CONFIGURATIONS Release
+    )
   endif()
+
   if(FLATBUFFERS_BUILD_SHAREDLIB)
-    install(TARGETS flatbuffers_shared DESTINATION lib)
+    if(CMAKE_VERSION VERSION_LESS 3.0)
+      install(
+        TARGETS flatbuffers_shared EXPORT FlatbuffersSharedTargets
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      )
+    else()
+      install(
+        TARGETS flatbuffers_shared EXPORT FlatbuffersSharedTargets
+        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        RUNTIME DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
+      )
+    endif()
+
+  install(
+      EXPORT FlatbuffersSharedTargets
+      FILE FlatbuffersSharedTargets.cmake
+      NAMESPACE flatbuffers::
+      DESTINATION ${FB_CMAKE_DIR}
+    )
   endif()
 endif()
 
diff --git a/android/.project b/android/.project
old mode 100755
new mode 100644
diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
old mode 100755
new mode 100644
index a15f547..846fd13
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -17,17 +17,14 @@
  -->
 <!-- BEGIN_INCLUDE(manifest) -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.example.FlatBufferTest"
-        android:versionCode="1"
-        android:versionName="1.0">
+          package="com.example.FlatBufferTest">
 
     <uses-feature android:glEsVersion="0x00020000"></uses-feature>
-    <!-- This is the platform API where NativeActivity was introduced. -->
-    <uses-sdk android:minSdkVersion="9" />
 
     <!-- This .apk has no Java code itself, so set hasCode to false. -->
-    <application android:label="@string/app_name" android:hasCode="false">
-
+    <application android:label="@string/app_name"
+                 android:hasCode="false"
+                 android:allowBackup="false">
         <!-- Our activity is the built-in NativeActivity framework class.
              This will take care of integrating with our NDK code. -->
         <activity android:name="android.app.NativeActivity"
diff --git a/android/build.gradle b/android/build.gradle
new file mode 100644
index 0000000..73e4188
--- /dev/null
+++ b/android/build.gradle
@@ -0,0 +1,108 @@
+// Copyright (c) 2017 Google, Inc.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty.  In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+buildscript {
+  repositories {
+    jcenter()
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:2.3.0'
+  }
+}
+
+allprojects {
+  repositories {
+    jcenter()
+  }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+  compileSdkVersion 25
+  buildToolsVersion '25.0.2'
+
+  sourceSets {
+    main {
+      manifest.srcFile 'AndroidManifest.xml'
+      res.srcDirs = ['res']
+    }
+  }
+
+  externalNativeBuild {
+    ndkBuild {
+      path "jni/Android.mk"
+    }
+  }
+
+  defaultConfig {
+    applicationId 'com.example.FlatBufferTest'
+    // This is the platform API where NativeActivity was introduced.
+    minSdkVersion 9
+    targetSdkVersion 25
+    versionCode 1
+    versionName "1.0"
+
+    buildTypes {
+      release {
+        minifyEnabled false
+      }
+    }
+
+    externalNativeBuild {
+      ndkBuild {
+        targets "FlatBufferTest"
+        arguments "-j" + Runtime.getRuntime().availableProcessors()
+        abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+      }
+    }
+  }
+
+  lintOptions {
+    abortOnError false
+  }
+
+  // Build with each STL variant.
+  productFlavors {
+    stlport {
+      applicationIdSuffix ".stlport"
+      versionNameSuffix "-stlport"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=stlport_static"
+        }
+      }
+    }
+    gnustl {
+      applicationIdSuffix ".gnustl"
+      versionNameSuffix "-gnustl"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=gnustl_static"
+        }
+      }
+    }
+    libcpp {
+      applicationIdSuffix ".libcpp"
+      versionNameSuffix "-libcpp"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=c++_static"
+        }
+      }
+    }
+  }
+}
diff --git a/android/build_apk.sh b/android/build_apk.sh
deleted file mode 100755
index 1b9f4a4..0000000
--- a/android/build_apk.sh
+++ /dev/null
@@ -1,511 +0,0 @@
-#!/bin/bash -eu
-#
-# Copyright (c) 2013 Google, Inc.
-#
-# This software is provided 'as-is', without any express or implied
-# warranty.  In no event will the authors be held liable for any damages
-# arising from the use of this software.
-# Permission is granted to anyone to use this software for any purpose,
-# including commercial applications, and to alter it and redistribute it
-# freely, subject to the following restrictions:
-# 1. The origin of this software must not be misrepresented; you must not
-# claim that you wrote the original software. If you use this software
-# in a product, an acknowledgment in the product documentation would be
-# appreciated but is not required.
-# 2. Altered source versions must be plainly marked as such, and must not be
-# misrepresented as being the original software.
-# 3. This notice may not be removed or altered from any source distribution.
-#
-# Build, deploy, debug / execute a native Android package based upon
-# NativeActivity.
-
-declare -r script_directory=$(dirname $0)
-declare -r android_root=${script_directory}/../../../../../../
-declare -r script_name=$(basename $0)
-declare -r android_manifest=AndroidManifest.xml
-declare -r os_name=$(uname -s)
-
-# Minimum Android target version supported by this project.
-: ${BUILDAPK_ANDROID_TARGET_MINVERSION:=10}
-# Directory containing the Android SDK
-# (http://developer.android.com/sdk/index.html).
-: ${ANDROID_SDK_HOME:=}
-# Directory containing the Android NDK
-# (http://developer.android.com/tools/sdk/ndk/index.html).
-: ${NDK_HOME:=}
-
-# Display script help and exit.
-usage() {
-  echo "
-Build the Android package in the current directory and deploy it to a
-connected device.
-
-Usage: ${script_name} \\
-         [ADB_DEVICE=serial_number] [BUILD=0] [DEPLOY=0] [RUN_DEBUGGER=1] \
-         [LAUNCH=0] [SWIG_BIN=swig_binary_directory] [SWIG_LIB=swig_include_directory] [ndk-build arguments ...]
-
-ADB_DEVICE=serial_number:
-  serial_number specifies the device to deploy the built apk to if multiple
-  Android devices are connected to the host.
-BUILD=0:
-  Disables the build of the package.
-DEPLOY=0:
-  Disables the deployment of the built apk to the Android device.
-RUN_DEBUGGER=1:
-  Launches the application in gdb after it has been deployed.  To debug in
-  gdb, NDK_DEBUG=1 must also be specified on the command line to build a
-  debug apk.
-LAUNCH=0:
-  Disable the launch of the apk on the Android device.
-SWIG_BIN=swig_binary_directory:
-  The directory where the SWIG binary lives. No need to set this if SWIG is
-  installed and point to from your PATH variable.
-SWIG_LIB=swig_include_directory:
-  The directory where SWIG shared include files are, usually obtainable from
-  commandline with \"swig -swiglib\". No need to set this if SWIG is installed
-  and point to from your PATH variable.
-ndk-build arguments...:
-  Additional arguments for ndk-build.  See ndk-build -h for more information.
-" >&2
-  exit 1
-}
-
-# Get the number of CPU cores present on the host.
-get_number_of_cores() {
-  case ${os_name} in
-    Darwin)
-      sysctl hw.ncpu | awk '{ print $2 }'
-      ;;
-    CYGWIN*|Linux)
-      awk '/^processor/ { n=$3 } END { print n + 1 }' /proc/cpuinfo
-      ;;
-    *)
-      echo 1
-      ;;
-  esac
-}
-
-# Get the package name from an AndroidManifest.xml file.
-get_package_name_from_manifest() {
-  xmllint --xpath 'string(/manifest/@package)' "${1}"
-}
-
-# Get the library name from an AndroidManifest.xml file.
-get_library_name_from_manifest() {
-  echo "\
-setns android=http://schemas.android.com/apk/res/android
-xpath string(/manifest/application/activity\
-[@android:name=\"android.app.NativeActivity\"]/meta-data\
-[@android:name=\"android.app.lib_name\"]/@android:value)" |
-  xmllint --shell "${1}" | awk '/Object is a string/ { print $NF }'
-}
-
-# Get the number of Android devices connected to the system.
-get_number_of_devices_connected() {
-  adb devices -l | \
-    awk '/^..*$/ { if (p) { print $0 } }
-         /List of devices attached/ { p = 1 }' | \
-    wc -l
-  return ${PIPESTATUS[0]}
-}
-
-# Kill a process and its' children.  This is provided for cygwin which
-# doesn't ship with pkill.
-kill_process_group() {
-  local parent_pid="${1}"
-  local child_pid=
-  for child_pid in $(ps -f | \
-                     awk '{ if ($3 == '"${parent_pid}"') { print $2 } }'); do
-    kill_process_group "${child_pid}"
-  done
-  kill "${parent_pid}" 2>/dev/null
-}
-
-# Find and run "adb".
-adb() {
-  local adb_path=
-  for path in "$(which adb 2>/dev/null)" \
-              "${ANDROID_SDK_HOME}/sdk/platform-tools/adb" \
-              "${android_root}/prebuilts/sdk/platform-tools/adb"; do
-    if [[ -e "${path}" ]]; then
-      adb_path="${path}"
-      break
-    fi
-  done
-  if [[ "${adb_path}" == "" ]]; then
-    echo -e "Unable to find adb." \
-           "\nAdd the Android ADT sdk/platform-tools directory to the" \
-           "PATH." >&2
-    exit 1
-  fi
-  "${adb_path}" "$@"
-}
-
-# Find and run "android".
-android() {
-  local android_executable=android
-  if echo "${os_name}" | grep -q CYGWIN; then
-    android_executable=android.bat
-  fi
-  local android_path=
-  for path in "$(which ${android_executable})" \
-              "${ANDROID_SDK_HOME}/sdk/tools/${android_executable}" \
-              "${android_root}/prebuilts/sdk/tools/${android_executable}"; do
-    if [[ -e "${path}" ]]; then
-      android_path="${path}"
-      break
-    fi
-  done
-  if [[ "${android_path}" == "" ]]; then
-    echo -e "Unable to find android tool." \
-           "\nAdd the Android ADT sdk/tools directory to the PATH." >&2
-    exit 1
-  fi
-  # Make sure ant is installed.
-  if [[ "$(which ant)" == "" ]]; then
-    echo -e "Unable to find ant." \
-            "\nPlease install ant and add to the PATH." >&2
-    exit 1
-  fi
-
-  "${android_path}" "$@"
-}
-
-# Find and run "ndk-build"
-ndkbuild() {
-  local ndkbuild_path=
-  for path in "$(which ndk-build 2>/dev/null)" \
-              "${NDK_HOME}/ndk-build" \
-              "${android_root}/prebuilts/ndk/current/ndk-build"; do
-    if [[ -e "${path}" ]]; then
-      ndkbuild_path="${path}"
-      break
-    fi
-  done
-  if [[ "${ndkbuild_path}" == "" ]]; then
-    echo -e "Unable to find ndk-build." \
-            "\nAdd the Android NDK directory to the PATH." >&2
-    exit 1
-  fi
-  "${ndkbuild_path}" "$@"
-}
-
-# Get file modification time of $1 in seconds since the epoch.
-stat_mtime() {
-  local filename="${1}"
-  case ${os_name} in
-    Darwin) stat -f%m "${filename}" 2>/dev/null || echo 0 ;;
-    *) stat -c%Y "${filename}" 2>/dev/null || echo 0 ;;
-  esac
-}
-
-# Build the native (C/C++) build targets in the current directory.
-build_native_targets() {
-  # Save the list of output modules in the install directory so that it's
-  # possible to restore their timestamps after the build is complete.  This
-  # works around a bug in ndk/build/core/setup-app.mk which results in the
-  # unconditional execution of the clean-installed-binaries rule.
-  restore_libraries="$(find libs -type f 2>/dev/null | \
-                       sed -E 's@^libs/(.*)@\1@')"
-
-  # Build native code.
-  ndkbuild -j$(get_number_of_cores) "$@"
-
-  # Restore installed libraries.
-  # Obviously this is a nasty hack (along with ${restore_libraries} above) as
-  # it assumes it knows where the NDK will be placing output files.
-  (
-    IFS=$'\n'
-    for libpath in ${restore_libraries}; do
-      source_library="obj/local/${libpath}"
-      target_library="libs/${libpath}"
-      if [[ -e "${source_library}" ]]; then
-        cp -a "${source_library}" "${target_library}"
-      fi
-    done
-  )
-}
-
-# Select the oldest installed android build target that is at least as new as
-# BUILDAPK_ANDROID_TARGET_MINVERSION.  If a suitable build target isn't found,
-# this function prints an error message and exits with an error.
-select_android_build_target() {
-  local -r android_targets_installed=$( \
-    android list targets | \
-    awk -F'"' '/^id:.*android/ { print $2 }')
-  local android_build_target=
-  for android_target in $(echo "${android_targets_installed}" | \
-                          awk -F- '{ print $2 }' | sort -n); do
-    local isNumber='^[0-9]+$'
-    # skip preview API releases e.g. 'android-L'
-    if [[ $android_target =~ $isNumber ]]; then
-      if [[ $((android_target)) -ge \
-          $((BUILDAPK_ANDROID_TARGET_MINVERSION)) ]]; then
-        android_build_target="android-${android_target}"
-        break
-      fi
-    # else
-      # The API version is a letter, so skip it.
-    fi
-  done
-  if [[ "${android_build_target}" == "" ]]; then
-    echo -e \
-      "Found installed Android targets:" \
-      "$(echo ${android_targets_installed} | sed 's/ /\n  /g;s/^/\n  /;')" \
-      "\nAndroid SDK platform" \
-      "android-$((BUILDAPK_ANDROID_TARGET_MINVERSION))" \
-      "must be installed to build this project." \
-      "\nUse the \"android\" application to install API" \
-      "$((BUILDAPK_ANDROID_TARGET_MINVERSION)) or newer." >&2
-    exit 1
-  fi
-  echo "${android_build_target}"
-}
-
-# Sign unsigned apk $1 and write the result to $2 with key store file $3 and
-# password $4.
-# If a key store file $3 and password $4 aren't specified, a temporary
-# (60 day) key is generated and used to sign the package.
-sign_apk() {
-  local unsigned_apk="${1}"
-  local signed_apk="${2}"
-  if [[ $(stat_mtime "${unsigned_apk}") -gt \
-          $(stat_mtime "${signed_apk}") ]]; then
-    local -r key_alias=$(basename ${signed_apk} .apk)
-    local keystore="${3}"
-    local key_password="${4}"
-    [[ "${keystore}" == "" ]] && keystore="${unsigned_apk}.keystore"
-    [[ "${key_password}" == "" ]] && \
-      key_password="${key_alias}123456"
-    if [[ ! -e ${keystore} ]]; then
-      keytool -genkey -v -dname "cn=, ou=${key_alias}, o=fpl" \
-        -storepass ${key_password} \
-        -keypass ${key_password} -keystore ${keystore} \
-        -alias ${key_alias} -keyalg RSA -keysize 2048 -validity 60
-    fi
-    cp "${unsigned_apk}" "${signed_apk}"
-    jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
-      -keystore ${keystore} -storepass ${key_password} \
-      -keypass ${key_password} "${signed_apk}" ${key_alias}
-  fi
-}
-
-# Build the apk $1 for package filename $2 in the current directory using the
-# ant build target $3.
-build_apk() {
-  local -r output_apk="${1}"
-  local -r package_filename="${2}"
-  local -r ant_target="${3}"
-  # Get the list of installed android targets and select the oldest target
-  # that is at least as new as BUILDAPK_ANDROID_TARGET_MINVERSION.
-  local -r android_build_target=$(select_android_build_target)
-  [[ "${android_build_target}" == "" ]] && exit 1
-  echo "Building ${output_apk} for target ${android_build_target}" >&2
-
-  # Create / update build.xml and local.properties files.
-  if [[ $(stat_mtime "${android_manifest}") -gt \
-          $(stat_mtime build.xml) ]]; then
-    android update project --target "${android_build_target}" \
-                           -n ${package_filename} --path .
-  fi
-
-  # Use ant to build the apk.
-  ant -quiet ${ant_target}
-
-  # Sign release apks with a temporary key as these packages will not be
-  # redistributed.
-  local unsigned_apk="bin/${package_filename}-${ant_target}-unsigned.apk"
-  if [[ "${ant_target}" == "release" ]]; then
-    sign_apk "${unsigned_apk}" "${output_apk}" "" ""
-  fi
-}
-
-# Uninstall package $1 and install apk $2 on device $3 where $3 is "-s device"
-# or an empty string.  If $3 is an empty string adb will fail when multiple
-# devices are connected to the host system.
-install_apk() {
-  local -r uninstall_package_name="${1}"
-  local -r install_apk="${2}"
-  local -r adb_device="${3}"
-  # Uninstall the package if it's already installed.
-  adb ${adb_device} uninstall "${uninstall_package_name}" 1>&2 > /dev/null || \
-    true # no error check
-
-  # Install the apk.
-  # NOTE: The following works around adb not returning an error code when
-  # it fails to install an apk.
-  echo "Install ${install_apk}" >&2
-  local -r adb_install_result=$(adb ${adb_device} install "${install_apk}")
-  echo "${adb_install_result}"
-  if echo "${adb_install_result}" | grep -qF 'Failure ['; then
-    exit 1
-  fi
-}
-
-# Launch previously installed package $1 on device $2.
-# If $2 is an empty string adb will fail when multiple devices are connected
-# to the host system.
-launch_package() {
-  (
-    # Determine the SDK version of Android on the device.
-    local -r android_sdk_version=$(
-      adb ${adb_device} shell cat system/build.prop | \
-      awk -F= '/ro.build.version.sdk/ {
-                 v=$2; sub(/[ \r\n]/, "", v); print v
-               }')
-
-    # Clear logs from previous runs.
-    # Note that logcat does not just 'tail' the logs, it dumps the entire log
-    # history.
-    adb ${adb_device} logcat -c
-
-    local finished_msg='Displayed '"${package_name}"
-    local timeout_msg='Activity destroy timeout.*'"${package_name}"
-    # Maximum time to wait before stopping log monitoring.  0 = infinity.
-    local launch_timeout=0
-    # If this is a Gingerbread device, kill log monitoring after 10 seconds.
-    if [[ $((android_sdk_version)) -le 10 ]]; then
-      launch_timeout=10
-    fi
-    # Display logcat in the background.
-    # Stop displaying the log when the app launch / execution completes or the
-    # logcat
-    (
-      adb ${adb_device} logcat | \
-        awk "
-          {
-            print \$0
-          }
-
-          /ActivityManager.*: ${finished_msg}/ {
-            exit 0
-          }
-
-          /ActivityManager.*: ${timeout_msg}/ {
-            exit 0
-          }" &
-      adb_logcat_pid=$!;
-      if [[ $((launch_timeout)) -gt 0 ]]; then
-        sleep $((launch_timeout));
-        kill ${adb_logcat_pid};
-      else
-        wait ${adb_logcat_pid};
-      fi
-    ) &
-    logcat_pid=$!
-    # Kill adb logcat if this shell exits.
-    trap "kill_process_group ${logcat_pid}" SIGINT SIGTERM EXIT
-
-    # If the SDK is newer than 10, "am" supports stopping an activity.
-    adb_stop_activity=
-    if [[ $((android_sdk_version)) -gt 10 ]]; then
-      adb_stop_activity=-S
-    fi
-
-    # Launch the activity and wait for it to complete.
-    adb ${adb_device} shell am start ${adb_stop_activity} -n \
-      ${package_name}/android.app.NativeActivity
-
-    wait "${logcat_pid}"
-  )
-}
-
-# See usage().
-main() {
-  # Parse arguments for this script.
-  local adb_device=
-  local ant_target=release
-  local disable_deploy=0
-  local disable_build=0
-  local run_debugger=0
-  local launch=1
-  local build_package=1
-  for opt; do
-    case ${opt} in
-      # NDK_DEBUG=0 tells ndk-build to build this as debuggable but to not
-      # modify the underlying code whereas NDK_DEBUG=1 also builds as debuggable
-      # but does modify the code
-      NDK_DEBUG=1) ant_target=debug ;;
-      NDK_DEBUG=0) ant_target=debug ;;
-      ADB_DEVICE*) adb_device="$(\
-        echo "${opt}" | sed -E 's/^ADB_DEVICE=([^ ]+)$/-s \1/;t;s/.*//')" ;;
-      BUILD=0) disable_build=1 ;;
-      DEPLOY=0) disable_deploy=1 ;;
-      RUN_DEBUGGER=1) run_debugger=1 ;;
-      LAUNCH=0) launch=0 ;;
-      clean) build_package=0 disable_deploy=1 launch=0 ;;
-      -h|--help|help) usage ;;
-    esac
-  done
-
-  # If a target device hasn't been specified and multiple devices are connected
-  # to the host machine, display an error.
-  local -r devices_connected=$(get_number_of_devices_connected)
-  if [[ "${adb_device}" == "" && $((devices_connected)) -gt 1 && \
-        ($((disable_deploy)) -eq 0 || $((launch)) -ne 0 || \
-         $((run_debugger)) -ne 0) ]]; then
-    if [[ $((disable_deploy)) -ne 0 ]]; then
-      echo "Deployment enabled, disable using DEPLOY=0" >&2
-    fi
-    if [[ $((launch)) -ne 0 ]]; then
-     echo "Launch enabled." >&2
-    fi
-    if [[ $((disable_deploy)) -eq 0 ]]; then
-      echo "Deployment enabled." >&2
-    fi
-    if [[ $((run_debugger)) -ne 0 ]]; then
-      echo "Debugger launch enabled." >&2
-    fi
-    echo "
-Multiple Android devices are connected to this host.  Either disable deployment
-and execution of the built .apk using:
-  \"${script_name} DEPLOY=0 LAUNCH=0\"
-
-or specify a device to deploy to using:
-  \"${script_name} ADB_DEVICE=\${device_serial}\".
-
-The Android devices connected to this machine are:
-$(adb devices -l)
-" >&2
-    exit 1
-  fi
-
-  if [[ $((disable_build)) -eq 0 ]]; then
-    # Build the native target.
-    build_native_targets "$@"
-  fi
-
-  # Get the package name from the manifest.
-  local -r package_name=$(get_package_name_from_manifest "${android_manifest}")
-  if [[ "${package_name}" == "" ]]; then
-    echo -e "No package name specified in ${android_manifest},"\
-            "skipping apk build, deploy"
-            "\nand launch steps." >&2
-    exit 0
-  fi
-  local -r package_basename=${package_name/*./}
-  local package_filename=$(get_library_name_from_manifest ${android_manifest})
-  [[ "${package_filename}" == "" ]] && package_filename="${package_basename}"
-
-  # Output apk name.
-  local -r output_apk="bin/${package_filename}-${ant_target}.apk"
-
-  if [[ $((disable_build)) -eq 0 && $((build_package)) -eq 1 ]]; then
-    # Build the apk.
-    build_apk "${output_apk}" "${package_filename}" "${ant_target}"
-  fi
-
-  # Deploy to the device.
-  if [[ $((disable_deploy)) -eq 0 ]]; then
-    install_apk "${package_name}" "${output_apk}" "${adb_device}"
-  fi
-
-  if [[ "${ant_target}" == "debug" && $((run_debugger)) -eq 1 ]]; then
-    # Start debugging.
-    ndk-gdb ${adb_device} --start
-  elif [[ $((launch)) -eq 1 ]]; then
-    launch_package "${package_name}" "${adb_device}"
-  fi
-}
-
-main "$@"
diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..b4163b8
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1e1168c
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 19 11:54:59 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/android/gradlew b/android/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/android/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/android/gradlew.bat b/android/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/android/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
old mode 100755
new mode 100644
index 0269dd3..aec561a
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -39,6 +39,7 @@
                    src/util.cpp \
                    src/code_generators.cpp
 LOCAL_STATIC_LIBRARIES := flatbuffers
+LOCAL_ARM_MODE := arm
 include $(BUILD_STATIC_LIBRARY)
 
 # FlatBuffers test
@@ -48,7 +49,7 @@
                    tests/test.cpp \
                    src/idl_gen_fbs.cpp \
                    src/idl_gen_general.cpp
-LOCAL_LDLIBS := -llog -landroid
+LOCAL_LDLIBS := -llog -landroid -latomic
 LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers_extra
 LOCAL_ARM_MODE := arm
 include $(BUILD_SHARED_LIBRARY)
diff --git a/android/jni/Application.mk b/android/jni/Application.mk
old mode 100755
new mode 100644
index 2fc9c73..ca9e800
--- a/android/jni/Application.mk
+++ b/android/jni/Application.mk
@@ -13,10 +13,8 @@
 # 2. Altered source versions must be plainly marked as such, and must not be
 # misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
-APP_PLATFORM := android-10
+APP_PLATFORM := android-9
 APP_PROJECT_PATH := $(call my-dir)/..
-APP_STL := gnustl_static
-
+APP_STL ?= stlport_static
 APP_ABI := armeabi-v7a
-
 APP_CPPFLAGS += -std=c++11
diff --git a/android/jni/build_flatc.bat b/android/jni/build_flatc.bat
old mode 100755
new mode 100644
diff --git a/android/res/values/strings.xml b/android/res/values/strings.xml
old mode 100755
new mode 100644
diff --git a/appveyor.yml b/appveyor.yml
index 57f65e3..d9dd5f1 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -4,6 +4,17 @@
 
 os: Visual Studio 2015
 
+environment:
+
+  global:
+    # Workaround for https://github.com/conda/conda-build/issues/636
+    PYTHONIOENCODING: UTF-8
+    CONDA_INSTALL_LOCN: "C:\\Miniconda35-x64"
+
+  matrix:
+    - CMAKE_VS_VERSION: "10 2010"
+    - CMAKE_VS_VERSION: "14 2015"
+
 platform:
   - x86
   - x64
@@ -13,7 +24,7 @@
   - Release
 
 before_build:
-  - cmake -G"Visual Studio 10 2010"
+  - cmake -G"Visual Studio %CMAKE_VS_VERSION%"
   # This cuts down on a lot of noise generated by xamarin warnings.
   - del "C:\Program Files (x86)\MSBuild\14.0\Microsoft.Common.targets\ImportAfter\Xamarin.Common.targets"
 
@@ -21,17 +32,41 @@
   project: ALL_BUILD.vcxproj
   verbosity: minimal
 
+install:
+  - set PATH=%CONDA_INSTALL_LOCN%;%CONDA_INSTALL_LOCN%\scripts;%PATH%;
+
 test_script:
-  - rem "---------------- C++ -----------------"
-  - "%CONFIGURATION%\\flattests.exe"
-  - rem "---------------- Java -----------------"
   - "cd tests"
+  - rem "Building all code"
+  - generate_code.bat -b %CONFIGURATION%
+  - 7z a GeneratedMyGameCode.zip MyGame\
+  - rem "---------------- C++ -----------------"
+  - "cd .."
+  - "%CONFIGURATION%\\flattests.exe"
+  - "cd tests"
+  - rem "---------------- Java -----------------"
   - "java -version"
   - "JavaTest.bat"
   - rem "---------------- JS -----------------"
   - "node --version"
-  - "..\\%CONFIGURATION%\\flatc -b monster_test.fbs unicode_test.json"
-  - "node JavaScriptTest"
+  - "..\\%CONFIGURATION%\\flatc -b -I include_test monster_test.fbs unicode_test.json"
+  - "node JavaScriptTest ./monster_test_generated"
+  - rem "-------------- Python ---------------"
+  - where python
+  - python --version
+  - where pip
+  - pip --version
+  - where conda
+  - conda --version
+  - rem "installing flatbuffers python library"
+  - pip install ../python
+  - rem "testing without installing Numpy"
+  - python py_test.py 0 0 0
+  - rem "testing after installing Numpy - disabled"
+  # FIXME: This has a LOT of unnecessary dependencies and makes the tests fail
+  # with timeouts.
+  # - conda install --yes numpy
+  # - python py_test.py 0 0 0
   - rem "---------------- C# -----------------"
   # Have to compile this here rather than in "build" above because AppVeyor only
   # supports building one project??
@@ -42,5 +77,7 @@
   - "cd ..\\.."
 
 artifacts:
-  - path: $(CONFIGURATION)\\flatc.exe
+  - path: $(CONFIGURATION)\flatc.exe
     name: flatc.exe
+  - path: tests\GeneratedMyGameCode.zip
+    name: GeneratedMyGameCode.zip
diff --git a/docs/footer.html b/docs/footer.html
old mode 100755
new mode 100644
diff --git a/docs/source/Benchmarks.md b/docs/source/Benchmarks.md
old mode 100755
new mode 100644
index e5e5847..848f4e3
--- a/docs/source/Benchmarks.md
+++ b/docs/source/Benchmarks.md
@@ -1,4 +1,4 @@
-Benchmarks    {#flatbuffers_benchmarks}
+C++ Benchmarks    {#flatbuffers_benchmarks}
 ==========
 
 Comparing against other serialization solutions, running on Windows 7
diff --git a/docs/source/Building.md b/docs/source/Building.md
old mode 100755
new mode 100644
diff --git a/docs/source/CONTRIBUTING.md b/docs/source/CONTRIBUTING.md
index 433b7d3..f939e75 120000
--- a/docs/source/CONTRIBUTING.md
+++ b/docs/source/CONTRIBUTING.md
@@ -1 +1 @@
-../../CONTRIBUTING
\ No newline at end of file
+../../CONTRIBUTING.md
\ No newline at end of file
diff --git a/docs/source/Compiler.md b/docs/source/Compiler.md
old mode 100755
new mode 100644
index a155df4..aaa274c
--- a/docs/source/Compiler.md
+++ b/docs/source/Compiler.md
@@ -29,7 +29,7 @@
 
 -   `--python`, `-p`: Generate Python code.
 
--   `--javascript`, `-s`: Generate JavaScript code.
+-   `--js`, `-s`: Generate JavaScript code.
 
 -   `--php`: Generate PHP code.
 
@@ -123,5 +123,10 @@
 -   `--include-prefix PATH` : Prefix this path to any generated include
     statements.
 
+-   `--keep-prefix` : Keep original prefix of schema include statement.
+
+-   `--reflect-types` : Add minimal type reflection to code generation.
+-   `--reflect-names` : Add minimal type/name reflection.
+
 NOTE: short-form options for generators are deprecated, use the long form
 whenever possible.
diff --git a/docs/source/CppUsage.md b/docs/source/CppUsage.md
old mode 100755
new mode 100644
index 8b82338..e858e0a
--- a/docs/source/CppUsage.md
+++ b/docs/source/CppUsage.md
@@ -126,6 +126,45 @@
     "native_inline", the value specified with this attribute will be included
     verbatim in the class constructor initializer list for this member.
 
+-   `native_custom_alloc`:"custom_allocator" (on a table or struct): When using the
+    object-based API all generated NativeTables that  are allocated when unpacking 
+    your  flatbuffer will use "custom allocator". The allocator is also used by 
+    any std::vector that appears in a table defined with `native_custom_alloc`. 
+    This can be  used to provide allocation from a pool for example, for faster 
+    unpacking when using the object-based API.
+
+    Minimal Example:
+
+    schema:
+
+    table mytable(native_custom_alloc:"custom_allocator") {
+      ...
+    }
+
+    with custom_allocator defined before flatbuffers.h is included, as:
+
+    template <typename T> struct custom_allocator : public std::allocator<T> {
+
+      typedef T *pointer;
+
+      template <class U>
+      struct rebind { 
+        typedef custom_allocator<U> other; 
+      };
+
+      pointer allocate(const std::size_t n) {
+        return std::allocator<T>::allocate(n);
+      }
+
+      void deallocate(T* ptr, std::size_t n) {
+        return std::allocator<T>::deallocate(ptr,n);
+      }
+
+      custom_allocator() throw() {}
+      template <class U> 
+      custom_allocator(const custom_allocator<U>&) throw() {}
+    };
+
 -   `native_type`' "type" (on a struct): In some cases, a more optimal C++ data
     type exists for a given struct.  For example, the following schema:
 
@@ -200,6 +239,15 @@
 pointers. Unlike the smart pointers, naked pointers do not manage memory for
 you, so you'll have to manage their lifecycles manually.
 
+
+# Using different string type.
+
+By default the object tree is built out of `std::string`, but you can
+influence this either globally (using the `--cpp-str-type` argument to
+`flatc`) or per field using the `cpp_str_type` attribute.
+
+The type must support T::c_str() and T::length() as member functions.
+
 ## Reflection (& Resizing)
 
 There is experimental support for reflection in FlatBuffers, allowing you to
@@ -222,6 +270,30 @@
 And example of usage, for the time being, can be found in
 `test.cpp/ReflectionTest()`.
 
+## Mini Reflection
+
+A more limited form of reflection is available for direct inclusion in
+generated code, which doesn't any (binary) schema access at all. It was designed
+to keep the overhead of reflection as low as possible (on the order of 2-6
+bytes per field added to your executable), but doesn't contain all the
+information the (binary) schema contains.
+
+You add this information to your generated code by specifying `--reflect-types`
+(or instead `--reflect-names` if you also want field / enum names).
+
+You can now use this information, for example to print a FlatBuffer to text:
+
+    auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
+
+`MonsterTypeTable()` is declared in the generated code for each type. The
+string produced is very similar to the JSON produced by the `Parser` based
+text generator.
+
+You'll need `flatbuffers/minireflect.h` for this functionality. In there is also
+a convenient visitor/iterator so you can write your own output / functionality
+based on the mini reflection tables without having to know the FlatBuffers or
+reflection encoding.
+
 ## Storing maps / dictionaries in a FlatBuffer
 
 FlatBuffers doesn't support maps natively, but there is support to
@@ -402,4 +474,22 @@
 accomplish this, by design, as we feel multithreaded construction
 of a single buffer will be rare, and synchronisation overhead would be costly.
 
+## Advanced union features
+
+The C++ implementation currently supports vectors of unions (i.e. you can
+declare a field as `[T]` where `T` is a union type instead of a table type). It
+also supports structs and strings in unions, besides tables.
+
+For an example of these features, see `tests/union_vector`, and
+`UnionVectorTest` in `test.cpp`.
+
+Since these features haven't been ported to other languages yet, if you
+choose to use them, you won't be able to use these buffers in other languages
+(`flatc` will refuse to compile a schema that uses these features).
+
+These features reduce the amount of "table wrapping" that was previously
+needed to use unions.
+
+To use scalars, simply wrap them in a struct.
+
 <br>
diff --git a/docs/source/FlexBuffers.md b/docs/source/FlexBuffers.md
index 67c9b27..a089df3 100644
--- a/docs/source/FlexBuffers.md
+++ b/docs/source/FlexBuffers.md
@@ -128,6 +128,16 @@
 [internals](@ref flatbuffers_internals) document.
 
 
+# Nesting inside a FlatBuffer
+
+You can mark a field as containing a FlexBuffer, e.g.
+
+    a:[ubyte] (flexbuffer);
+
+A special accessor will be generated that allows you to access the root value
+directly, e.g. `a_flexbuffer_root().AsInt64()`.
+
+
 # Efficiency tips
 
 * Vectors generally are a lot more efficient than maps, so prefer them over maps
diff --git a/docs/source/Grammar.md b/docs/source/Grammar.md
old mode 100755
new mode 100644
index b6b48c0..84e762c
--- a/docs/source/Grammar.md
+++ b/docs/source/Grammar.md
@@ -4,7 +4,7 @@
 schema = include*
          ( namespace\_decl | type\_decl | enum\_decl | root\_decl |
            file_extension_decl | file_identifier_decl |
-           attribute\_decl | object )*
+           attribute\_decl | rpc\_decl | object )*
 
 include = `include` string\_constant `;`
 
@@ -14,16 +14,22 @@
 
 type\_decl = ( `table` | `struct` ) ident metadata `{` field\_decl+ `}`
 
-enum\_decl = ( `enum` | `union` ) ident [ `:` type ] metadata `{` commasep(
-enumval\_decl ) `}`
+enum\_decl = ( `enum` ident [ `:` type ] | `union` ident )  metadata `{`
+commasep( enumval\_decl ) `}`
 
 root\_decl = `root_type` ident `;`
 
 field\_decl = ident `:` type [ `=` scalar ] metadata `;`
 
+rpc\_decl = `rpc_service` ident `{` rpc\_method+ `}`
+
+rpc\_method = ident `(` ident `)` `:` ident metadata `;`
+
 type = `bool` | `byte` | `ubyte` | `short` | `ushort` | `int` | `uint` |
-`float` | `long` | `ulong` | `double`
- | `string` | `[` type `]` | ident
+`float` | `long` | `ulong` | `double` |
+`int8` | `uint8` | `int16` | `uint16` | `int32` | `uint32`| `int64` | `uint64` |
+`float32` | `float64` |
+`string` | `[` type `]` | ident
 
 enumval\_decl = ident [ `=` integer\_constant ]
 
@@ -43,6 +49,11 @@
 
 file_identifier_decl = `file_identifier` string\_constant `;`
 
-integer\_constant = -?[0-9]+ | `true` | `false`
+integer\_constant = `-?[0-9]+` | `true` | `false`
 
-float\_constant = -?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?
+float\_constant = `-?[0-9]+.[0-9]+((e|E)(+|-)?[0-9]+)?`
+
+string\_constant = `\".*?\"`
+
+ident = `[a-zA-Z_][a-zA-Z0-9_]*`
+
diff --git a/docs/source/Internals.md b/docs/source/Internals.md
old mode 100755
new mode 100644
index de7a07e..60b8130
--- a/docs/source/Internals.md
+++ b/docs/source/Internals.md
@@ -292,6 +292,12 @@
 this case there's only one string), and what order to write the fields in.
 Different orders may also cause different alignments to happen.
 
+### Additional reading.
+
+The author of the C language implementation has made a similar
+[document](https://github.com/dvidelabs/flatcc/blob/master/doc/binary-format.md#flatbuffers-binary-format)
+that may further help clarify the format.
+
 # FlexBuffers
 
 The [schema-less](@ref flexbuffers) version of FlatBuffers have their
@@ -368,6 +374,10 @@
 into vectors / maps of smaller sizes, and to share / repeat a value multiple
 times.
 
+### Booleans and Nulls
+
+Booleans (`TYPE_BOOL`) and nulls (`TYPE_NULL`) are encoded as inlined unsigned integers.
+
 ### Blobs, Strings and Keys.
 
 A blob (`TYPE_BLOB`) is encoded similar to a vector, with one difference: the
@@ -408,19 +418,19 @@
 
 The reason the key vector is a seperate structure from the value vector is
 such that it can be shared between multiple value vectors, and also to
-allow it to be treated as its own indivual vector in code.
+allow it to be treated as its own individual vector in code.
 
 An example map { foo: 13, bar: 14 } would be encoded as:
 
-    0 : uint8_t 'f', 'o', 'o', 0
-    4 : uint8_t 'b', 'a', 'r', 0
+    0 : uint8_t 'b', 'a', 'r', 0
+    4 : uint8_t 'f', 'o', 'o', 0
     8 : uint8_t 2      // key vector of size 2
     // key vector offset points here
-    9 : uint8_t 9, 6   // offsets to foo_key and bar_key
-    11: uint8_t 3, 1   // offset to key vector, and its byte width
+    9 : uint8_t 9, 6   // offsets to bar_key and foo_key
+    11: uint8_t 2, 1   // offset to key vector, and its byte width
     13: uint8_t 2      // value vector of size
     // value vector offset points here
-    14: uint8_t 13, 14 // values
+    14: uint8_t 14, 13 // values
     16: uint8_t 4, 4   // types
 
 ### The root
diff --git a/docs/source/JavaCsharpUsage.md b/docs/source/JavaCsharpUsage.md
old mode 100755
new mode 100644
index cc58f85..102ce37
--- a/docs/source/JavaCsharpUsage.md
+++ b/docs/source/JavaCsharpUsage.md
@@ -139,7 +139,7 @@
 your data into a `Dictionary` or similar.
 
 To use it:
--   Designate one of the fields in a table as they "key" field. You do this
+-   Designate one of the fields in a table as the "key" field. You do this
     by setting the `key` attribute on this field, e.g.
     `name:string (key)`.
     You may only have one key field, and it must be of string or scalar type.
@@ -147,19 +147,20 @@
     array.
 -   Instead of calling standard generated method,
     e.g.: `Monster.createTestarrayoftablesVector`,
-    call `CreateMySortedVectorOfTables` in C# or
+    call `CreateSortedVectorOfMonster` in C# or
     `createSortedVectorOfTables` (from the `FlatBufferBuilder` object) in Java,
     which will first sort all offsets such that the tables they refer to
     are sorted by the key field, then serialize it.
--   Now when you're accessing the FlatBuffer, you can use `LookupByKey`
-    to access elements of the vector, e.g.:
-    `Monster.lookupByKey(tablesVectorOffset, "Frodo", dataBuffer)`,
+-   Now when you're accessing the FlatBuffer, you can use
+    the `ByKey` accessor to access elements of the vector, e.g.:
+    `monster.testarrayoftablesByKey("Frodo")` in Java or
+    `monster.TestarrayoftablesByKey("Frodo")` in C#,
     which returns an object of the corresponding table type,
     or `null` if not found.
-    `LookupByKey` performs a binary search, so should have a similar speed to
-    `Dictionary`, though may be faster because of better caching. `LookupByKey`
-    only works if the vector has been sorted, it will likely not find elements
-    if it hasn't been sorted.
+    `ByKey` performs a binary search, so should have a similar
+    speed to `Dictionary`, though may be faster because of better caching.
+    `ByKey` only works if the vector has been sorted, it will
+    likely not find elements if it hasn't been sorted.
 
 ## Text parsing
 
diff --git a/docs/source/JavaScriptUsage.md b/docs/source/JavaScriptUsage.md
old mode 100755
new mode 100644
diff --git a/docs/source/PythonUsage.md b/docs/source/PythonUsage.md
old mode 100755
new mode 100644
index 2a0cdde..f338cda
--- a/docs/source/PythonUsage.md
+++ b/docs/source/PythonUsage.md
@@ -64,6 +64,33 @@
     pos = monster.Pos()
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
+## Support for Numpy arrays
+
+The Flatbuffers python library also has support for accessing scalar
+vectors as numpy arrays. This can be orders of magnitude faster than
+iterating over the vector one element at a time, and is particularly
+useful when unpacking large nested flatbuffers. The generated code for
+a scalar vector will have a method `<vector name>AsNumpy()`. In the
+case of the Monster example, you could access the inventory vector
+like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+    inventory = monster.InventoryAsNumpy()
+    # inventory is a numpy array of type np.dtype('uint8')
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+instead of
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.py}
+    inventory = []
+    for i in range(monster.InventoryLength()):
+        inventory.append(int(monster.Inventory(i)))
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Numpy is not a requirement. If numpy is not installed on your system,
+then attempting to access one of the `*asNumpy()` methods will result
+in a `NumpyRequiredForThisFeature` exception.
+
 ## Text Parsing
 
 There currently is no support for parsing text (Schema's and JSON) directly
diff --git a/docs/source/Schemas.md b/docs/source/Schemas.md
old mode 100755
new mode 100644
index c4a9421..a05b002
--- a/docs/source/Schemas.md
+++ b/docs/source/Schemas.md
@@ -84,15 +84,19 @@
 
 ### Types
 
-Built-in scalar types are:
+Built-in scalar types are 
 
--   8 bit: `byte`, `ubyte`, `bool`
+-   8 bit: `byte` (`int8`), `ubyte` (`uint8`), `bool`
 
--   16 bit: `short`, `ushort`
+-   16 bit: `short` (`int16`), `ushort` (`uint16`)
 
--   32 bit: `int`, `uint`, `float`
+-   32 bit: `int` (`int32`), `uint` (`uint32`), `float` (`float32`)
 
--   64 bit: `long`, `ulong`, `double`
+-   64 bit: `long` (`int64`), `ulong` (`uint64`), `double` (`float64`)
+
+The type names in parentheses are alias names such that for example
+`uint8` can be used in place of `ubyte`, and `int32` can be used in
+place of `int` without affecting code generation.
 
 Built-in non-scalar types:
 
@@ -278,7 +282,10 @@
     IDs allow the fields to be placed in any order in the schema.
     When a new field is added to the schema it must use the next available ID.
 -   `deprecated` (on a field): do not generate accessors for this field
-    anymore, code should stop using this data.
+    anymore, code should stop using this data. Old data may still contain this
+    field, but it won't be accessible anymore by newer code. Note that if you
+    deprecate a field that was previous required, old code may fail to validate
+    new data (when using the optional verifier).
 -   `required` (on a non-scalar table field): this field must always be set.
     By default, all fields are optional, i.e. may be left out. This is
     desirable, as it helps with forwards/backwards compatibility, and
@@ -288,7 +295,10 @@
     constructs FlatBuffers to ensure this field is initialized, so the reading
     code may access it directly, without checking for NULL. If the constructing
     code does not initialize this field, they will get an assert, and also
-    the verifier will fail on buffers that have missing required fields.
+    the verifier will fail on buffers that have missing required fields. Note
+    that if you add this attribute to an existing field, this will only be
+    valid if existing data always contains this field / existing code always
+    writes this field.
 -   `force_align: size` (on a struct): force the alignment of this struct
     to be something higher than what it is naturally aligned to. Causes
     these structs to be aligned to that amount inside a buffer, IF that
@@ -302,6 +312,9 @@
     (which must be a vector of ubyte) contains flatbuffer data, for which the
     root type is given by `table_name`. The generated code will then produce
     a convenient accessor for the nested FlatBuffer.
+-   `flexbuffer` (on a field): this indicates that the field
+    (which must be a vector of ubyte) contains flexbuffer data. The generated
+    code will then produce a convenient accessor for the FlexBuffer root.
 -   `key` (on a field): this field is meant to be used as a key when sorting
     a vector of the type of table it sits in. Can be used for in-place
     binary search.
diff --git a/docs/source/Support.md b/docs/source/Support.md
old mode 100755
new mode 100644
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 7d9c6d9..daa8ee1 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -160,6 +160,7 @@
     color:Color = Blue; // Enum.
     weapons:[Weapon];   // Vector of tables.
     equipped:Equipment; // Union.
+    path:[Vec3];        // Vector of structs.
   }
 
   table Weapon {
@@ -209,12 +210,21 @@
 used twice: once within the `Monster` table and once within the `Equipment`
 enum. For our `Monster`, it is used to populate a `vector of tables` via the
 `weapons` field within our `Monster`. It is also the only table referenced by
-the `Equipment` enum.
+the `Equipment` union.
 
 The last part of the `schema` is the `root_type`. The root type declares what
 will be the root table for the serialized data. In our case, the root type is
 our `Monster` table.
 
+The scalar types can also use alias type names such as `int16` instead
+of `short` and `float32` instead of `float`. Thus we could also write
+the `Weapon` table as:
+
+  table Weapon {
+    name:string;
+    damage:int16;
+  }
+
 #### More Information About Schemas
 
 You can find a complete guide to writing `schema` files in the
@@ -603,7 +613,7 @@
 
   // Create a `vector` representing the inventory of the Orc. Each number
   // could correspond to an item that can be claimed after he is slain.
-  unsigned char treasure = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
+  unsigned char treasure[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
   auto inventory = builder.CreateVector(treasure, 10);
 ~~~
 </div>
@@ -709,6 +719,10 @@
 other `vector`s), collect their offsets into a temporary data structure, and
 then create an additional `vector` containing their offsets.*
 
+If instead of creating a vector from an existing array you serialize elements
+individually one by one, take care to note that this happens in reverse order,
+as buffers are built back to front.
+
 For example, take a look at the two `Weapon`s that we created earlier (`Sword`
 and `Axe`). These are both FlatBuffer `table`s, whose offsets we now store in
 memory. Therefore we can create a FlatBuffer `vector` to contain these
@@ -799,6 +813,70 @@
 there's also `CreateVectorOfStrings`.
 </div>
 
+Note that vectors of structs are serialized differently from tables, since
+structs are stored in-line in the vector. For example, to create a vector
+for the `path` field above:
+
+<div class="language-cpp">
+~~~{.cpp}
+  Vec3 points[] = { Vec3(1.0f, 2.0f, 3.0f), Vec3(4.0f, 5.0f, 6.0f) };
+  auto path = builder.CreateVectorOfStructs(points, 2);
+~~~
+</div>
+<div class="language-java">
+~~~{.java}
+  Monster.startPathVector(fbb, 2);
+  Vec3.createVec3(builder, 1.0f, 2.0f, 3.0f);
+  Vec3.createVec3(builder, 4.0f, 5.0f, 6.0f);
+  int path = fbb.endVector();
+~~~
+</div>
+<div class="language-csharp">
+~~~{.cs}
+  Monster.StartPathVector(fbb, 2);
+  Vec3.CreateVec3(builder, 1.0f, 2.0f, 3.0f);
+  Vec3.CreateVec3(builder, 4.0f, 5.0f, 6.0f);
+  var path = fbb.EndVector();
+~~~
+</div>
+<div class="language-go">
+~~~{.go}
+  sample.MonsterStartPathVector(builder, 2)
+  sample.CreateVec3(builder, 1.0, 2.0, 3.0)
+  sample.CreateVec3(builder, 4.0, 5.0, 6.0)
+  path := builder.EndVector(2)
+~~~
+</div>
+<div class="language-python">
+~~~{.py}
+  MyGame.Sample.Monster.MonsterStartPathVector(builder, 2)
+  MyGame.Sample.Vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+  MyGame.Sample.Vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
+  path = builder.EndVector(2)
+~~~
+</div>
+<div class="language-javascript">
+~~~{.js}
+  MyGame.Sample.Monster.startPathVector(builder, 2);
+  MyGame.Sample.Vec3.createVec3(builder, 1.0, 2.0, 3.0);
+  MyGame.Sample.Vec3.createVec3(builder, 4.0, 5.0, 6.0);
+  var path = builder.endVector();
+~~~
+</div>
+<div class="language-php">
+~~~{.php}
+  \MyGame\Example\Monster::StartPathVector($builder, 2);
+  \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+  \MyGame\Sample\Vec3::CreateVec3($builder, 1.0, 2.0, 3.0);
+  $path = $builder->endVector();
+~~~
+</div>
+<div class="language-c">
+~~~{.c}
+  // TBD
+~~~
+</div>
+
 We have now serialized the non-scalar components of the orc, so we
 can serialize the monster itself:
 
@@ -812,7 +890,7 @@
   // to set all fields.
   auto orc = CreateMonster(builder, Vec3(1.0f, 2.0f, 3.0f), mana, hp, name,
                            inventory, Color_Red, weapons, Equipment_Weapon,
-                           axe.Union());
+                           axe.Union(), path);
 ~~~
 </div>
 <div class="language-java">
@@ -827,6 +905,7 @@
   Monster.addWeapons(builder, weapons);
   Monster.addEquippedType(builder, Equipment.Weapon);
   Monster.addEquipped(builder, axe);
+  Monster.addPath(builder, path);
   int orc = Monster.endMonster(builder);
 ~~~
 </div>
@@ -842,6 +921,7 @@
   Monster.AddWeapons(builder, weapons);
   Monster.AddEquippedType(builder, Equipment.Weapon);
   Monster.AddEquipped(builder, axe.Value); // Axe
+  Monster.AddPath(builder, path);
   var orc = Monster.EndMonster(builder);
 ~~~
 </div>
@@ -857,6 +937,7 @@
   sample.MonsterAddWeapons(builder, weapons)
   sample.MonsterAddEquippedType(builder, sample.EquipmentWeapon)
   sample.MonsterAddEquipped(builder, axe)
+  sample.MonsterAddPath(builder, path)
   orc := sample.MonsterEnd(builder)
 ~~~
 </div>
@@ -875,6 +956,7 @@
   MyGame.Sample.Monster.MonsterAddEquippedType(
       builder, MyGame.Sample.Equipment.Equipment().Weapon)
   MyGame.Sample.Monster.MonsterAddEquipped(builder, axe)
+  MyGame.Sample.Monster.MonsterAddPath(builder, path)
   orc = MyGame.Sample.Monster.MonsterEnd(builder)
 ~~~
 </div>
@@ -891,6 +973,7 @@
   MyGame.Sample.Monster.addWeapons(builder, weapons);
   MyGame.Sample.Monster.addEquippedType(builder, MyGame.Sample.Equipment.Weapon);
   MyGame.Sample.Monster.addEquipped(builder, axe);
+  MyGame.Sample.Monster.addPath(builder, path);
   var orc = MyGame.Sample.Monster.endMonster(builder);
 ~~~
 </div>
@@ -907,6 +990,7 @@
   \MyGame\Sample\Monster::AddWeapons($builder, $weapons);
   \MyGame\Sample\Monster::AddEquippedType($builder, \MyGame\Sample\Equipment::Weapon);
   \MyGame\Sample\Monster::AddEquipped($builder, $axe);
+  \MyGame\Sample\Monster::AddPath($builder, $path);
   $orc = \MyGame\Sample\Monster::EndMonster($builder);
 ~~~
 </div>
@@ -921,7 +1005,7 @@
   ns(Equipment_union_ref_t) equipped = ns(Equipment_as_Weapon(axe));
   ns(Vec3_t) pos = { 1.0f, 2.0f, 3.0f };
   ns(Monster_create_as_root(B, &pos, mana, hp, name, inventory, ns(Color_Red),
-          weapons, equipped));
+          weapons, equipped, path));
 ~~~
 </div>
 
@@ -929,10 +1013,10 @@
 are simple combinations of scalars that are always stored inline, just like
 scalars themselves.
 
-**Important**: you should not nest tables or any other objects, which is why
-we created all the strings/vectors/tables that this monster refers to before
-`start`. If you try to create any of them between `start` and `end`, you
-will get an assert/exception/panic depending on your language.
+**Important**: Unlike structs, you should not nest tables or other objects,
+which is why we created all the strings/vectors/tables that this monster refers
+to before `start`. If you try to create any of them between `start` and `end`,
+you will get an assert/exception/panic depending on your language.
 
 *Note: Since we are passing `150` as the `mana` field, which happens to be the
 default value, the field will not actually be written to the buffer, since the
@@ -953,13 +1037,14 @@
   // manually.
   MonsterBuilder monster_builder(builder);
   monster_builder.add_pos(&pos);
+  auto pos = Vec3(1.0f, 2.0f, 3.0f);
   monster_builder.add_hp(hp);
   monster_builder.add_name(name);
   monster_builder.add_inventory(inventory);
   monster_builder.add_color(Color_Red);
   monster_builder.add_weapons(weapons);
   monster_builder.add_equipped_type(Equipment_Weapon);
-  monster_builder.add_equpped(axe);
+  monster_builder.add_equpped(axe.Union());
   auto orc = monster_builder.Finish();
 ~~~
 </div>
@@ -1091,7 +1176,7 @@
 <div class="language-javascript">
 ~~~{.js}
   // Call `finish()` to instruct the builder that this monster is complete.
-  builder.finish(orc); // You could also call `MyGame.Example.Monster.finishMonsterBuffer(builder,
+  builder.finish(orc); // You could also call `MyGame.Sample.Monster.finishMonsterBuffer(builder,
                        //                                                                 orc);`.
 ~~~
 </div>
@@ -1309,6 +1394,8 @@
 
   // `monster` is of type `Monster *`.
   // Note: root object pointers are NOT the same as `buffer_pointer`.
+  // `GetMonster` is a convenience function that calls `GetRoot<Monster>`,
+  // the latter is also available for non-root types.
 ~~~
 </div>
 <div class="language-java">
@@ -1470,10 +1557,10 @@
 </div>
 <div class="language-csharp">
 ~~~{.cs}
-  var pos = monster.Pos
-  var x = pos.X
-  var y = pos.Y
-  var z = pos.Z
+  var pos = monster.Pos.Value;
+  var x = pos.X;
+  var y = pos.Y;
+  var z = pos.Z;
 ~~~
 </div>
 <div class="language-go">
@@ -1547,7 +1634,7 @@
 <div class="language-csharp">
 ~~~{.cs}
   int invLength = monster.InventoryLength;
-  var thirdItem = monster.GetInventory(2);
+  var thirdItem = monster.Inventory(2);
 ~~~
 </div>
 <div class="language-go">
@@ -1604,8 +1691,8 @@
 <div class="language-csharp">
 ~~~{.cs}
   int weaponsLength = monster.WeaponsLength;
-  var secondWeaponName = monster.GetWeapons(1).Name;
-  var secondWeaponDamage = monster.GetWeapons(1).Damage;
+  var secondWeaponName = monster.Weapons(1).Name;
+  var secondWeaponDamage = monster.Weapons(1).Damage;
 ~~~
 </div>
 <div class="language-go">
@@ -1687,8 +1774,7 @@
   var unionType = monster.EquippedType;
 
   if (unionType == Equipment.Weapon) {
-    var weapon = (Weapon)monster.GetEquipped(new Weapon()); // Requires explicit cast
-                                                            // to `Weapon`.
+    var weapon = monster.Equipped<Weapon>().Value;
 
     var weaponName = weapon.Name;     // "Axe"
     var weaponDamage = weapon.Damage; // 5
diff --git a/docs/source/WhitePaper.md b/docs/source/WhitePaper.md
old mode 100755
new mode 100644
diff --git a/docs/source/doxyfile b/docs/source/doxyfile
old mode 100755
new mode 100644
index 770da9f..64af671
--- a/docs/source/doxyfile
+++ b/docs/source/doxyfile
@@ -765,6 +765,7 @@
         "../../CONTRIBUTING.md" \
         "Tutorial.md" \
         "GoApi.md" \
+        "gRPC/CppUsage.md" \
         "groups" \
         "../../java/com/google/flatbuffers" \
         "../../python/flatbuffers/builder.py" \
@@ -883,21 +884,21 @@
 # that contain example code fragments that are included (see the \include
 # command).
 
-EXAMPLE_PATH           = "GoApi_generated.txt"
+EXAMPLE_PATH           = "GoApi_generated.txt" "../../grpc/samples"
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
 # *.h) to filter out the source-files in the directories. If left blank all
 # files are included.
 
-EXAMPLE_PATTERNS       = *
+EXAMPLE_PATTERNS       = *.cpp *.h *.txt *.fbs
 
 # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
 # searched for input files to be used with the \include or \dontinclude commands
 # irrespective of the value of the RECURSIVE tag.
 # The default value is: NO.
 
-EXAMPLE_RECURSIVE      = NO
+EXAMPLE_RECURSIVE      = YES
 
 # The IMAGE_PATH tag can be used to specify one or more files or directories
 # that contain images that are to be included in the documentation (see the
diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml
index 77866df..504d15c 100644
--- a/docs/source/doxygen_layout.xml
+++ b/docs/source/doxygen_layout.xml
@@ -39,6 +39,10 @@
           title="Use in Python"/>
       <tab type="user" url="@ref flexbuffers"
           title="Schema-less version"/>
+      <tab type="usergroup" url="" title="gRPC">
+        <tab type="user" url="@ref flatbuffers_grpc_guide_use_cpp"
+            title="Use in C++"/>
+      </tab>
     </tab>
     <tab type="user" url="@ref flatbuffers_support"
         title="Platform / Language / Feature support"/>
diff --git a/docs/source/gRPC/CppUsage.md b/docs/source/gRPC/CppUsage.md
new file mode 100644
index 0000000..93dbb29
--- /dev/null
+++ b/docs/source/gRPC/CppUsage.md
@@ -0,0 +1,29 @@
+Use in C++    {#flatbuffers_grpc_guide_use_cpp}
+==========
+
+## Before you get started
+
+Before diving into the FlatBuffers gRPC usage in C++, you should already be
+familiar with the following:
+
+- FlatBuffers as a serialization format
+- [gRPC](http://www.grpc.io/docs/) usage
+
+## Using the FlatBuffers gRPC C++ library
+
+NOTE: The examples below are also in the `grpc/samples/greeter` directory.
+
+We will illustrate usage with the following schema:
+
+@include grpc/samples/greeter/greeter.fbs
+
+When we run `flatc`, we pass in the `--grpc` option and generage an additional
+`greeter.grpc.fb.h` and `greeter.grpc.fb.cc`.
+
+Example server code looks like this:
+
+@include grpc/samples/greeter/server.cpp
+
+Example client code looks like this:
+
+@include grpc/samples/greeter/client.cpp
diff --git a/go/builder.go b/go/builder.go
index cf21dd5..a7bf4a1 100644
--- a/go/builder.go
+++ b/go/builder.go
@@ -110,6 +110,11 @@
 	objectOffset := b.Offset()
 	existingVtable := UOffsetT(0)
 
+	// Trim vtable of trailing zeroes.
+	i := len(b.vtable) - 1;
+	for ; i >= 0 && b.vtable[i] == 0; i-- {}
+	b.vtable = b.vtable[:i + 1];
+
 	// Search backwards through existing vtables, because similar vtables
 	// are likely to have been recently appended. See
 	// BenchmarkVtableDeduplication for a case in which this heuristic
diff --git a/grpc/samples/greeter/Makefile b/grpc/samples/greeter/Makefile
new file mode 100644
index 0000000..3746705
--- /dev/null
+++ b/grpc/samples/greeter/Makefile
@@ -0,0 +1,14 @@
+CXXFLAGS ?= -I../../../include
+LDFLAGS ?=
+
+.PHONY: all
+all: server client
+
+greeter_generated.h: greeter.fbs
+	flatc --grpc --cpp $<
+
+server: server.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
+	g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ server.cpp greeter.grpc.fb.cc -o $@
+
+client: client.cpp greeter.grpc.fb.cc greeter_generated.h greeter.grpc.fb.h
+	g++ -std=c++11 -O2 $(CXXFLAGS) $(LDFLAGS) -lgpr -lgrpc -lgrpc++ client.cpp greeter.grpc.fb.cc -o $@
diff --git a/grpc/samples/greeter/client.cpp b/grpc/samples/greeter/client.cpp
new file mode 100644
index 0000000..2e42f8f
--- /dev/null
+++ b/grpc/samples/greeter/client.cpp
@@ -0,0 +1,85 @@
+#include "greeter.grpc.fb.h"
+#include "greeter_generated.h"
+
+#include <grpc++/grpc++.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class GreeterClient {
+ public:
+  GreeterClient(std::shared_ptr<grpc::Channel> channel)
+    : stub_(Greeter::NewStub(channel)) {}
+
+  std::string SayHello(const std::string &name) {
+    flatbuffers::grpc::MessageBuilder mb;
+    auto name_offset = mb.CreateString(name);
+    auto request_offset = CreateHelloRequest(mb, name_offset);
+    mb.Finish(request_offset);
+    auto request_msg = mb.ReleaseMessage<HelloRequest>();
+
+    flatbuffers::grpc::Message<HelloReply> response_msg;
+
+    grpc::ClientContext context;
+
+    auto status = stub_->SayHello(&context, request_msg, &response_msg);
+    if (status.ok()) {
+      const HelloReply *response = response_msg.GetRoot();
+      return response->message()->str();
+    } else {
+      std::cerr << status.error_code() << ": " << status.error_message()
+                << std::endl;
+      return "RPC failed";
+    }
+  }
+
+  void SayManyHellos(const std::string &name, int num_greetings,
+                     std::function<void(const std::string &)> callback) {
+    flatbuffers::grpc::MessageBuilder mb;
+    auto name_offset = mb.CreateString(name);
+    auto request_offset =
+        CreateManyHellosRequest(mb, name_offset, num_greetings);
+    mb.Finish(request_offset);
+    auto request_msg = mb.ReleaseMessage<ManyHellosRequest>();
+
+    flatbuffers::grpc::Message<HelloReply> response_msg;
+
+    grpc::ClientContext context;
+
+    auto stream = stub_->SayManyHellos(&context, request_msg);
+    while (stream->Read(&response_msg)) {
+      const HelloReply *response = response_msg.GetRoot();
+      callback(response->message()->str());
+    }
+    auto status = stream->Finish();
+    if (!status.ok()) {
+      std::cerr << status.error_code() << ": " << status.error_message()
+                << std::endl;
+      callback("RPC failed");
+    }
+  }
+
+ private:
+  std::unique_ptr<Greeter::Stub> stub_;
+};
+
+int main(int argc, char **argv) {
+  std::string server_address("localhost:50051");
+
+  auto channel =
+      grpc::CreateChannel(server_address, grpc::InsecureChannelCredentials());
+  GreeterClient greeter(channel);
+
+  std::string name("world");
+
+  std::string message = greeter.SayHello(name);
+  std::cerr << "Greeter received: " << message << std::endl;
+
+  int num_greetings = 10;
+  greeter.SayManyHellos(name, num_greetings, [](const std::string &message) {
+    std::cerr << "Greeter received: " << message << std::endl;
+  });
+
+  return 0;
+}
diff --git a/grpc/samples/greeter/greeter.fbs b/grpc/samples/greeter/greeter.fbs
new file mode 100644
index 0000000..811303c
--- /dev/null
+++ b/grpc/samples/greeter/greeter.fbs
@@ -0,0 +1,17 @@
+table HelloReply {
+  message:string;
+}
+
+table HelloRequest {
+  name:string;
+}
+
+table ManyHellosRequest {
+  name:string;
+  num_greetings:int;
+}
+
+rpc_service Greeter {
+  SayHello(HelloRequest):HelloReply;
+  SayManyHellos(ManyHellosRequest):HelloReply (streaming: "server");
+}
diff --git a/grpc/samples/greeter/server.cpp b/grpc/samples/greeter/server.cpp
new file mode 100644
index 0000000..82c97dc
--- /dev/null
+++ b/grpc/samples/greeter/server.cpp
@@ -0,0 +1,80 @@
+#include "greeter.grpc.fb.h"
+#include "greeter_generated.h"
+
+#include <grpc++/grpc++.h>
+
+#include <iostream>
+#include <memory>
+#include <string>
+
+class GreeterServiceImpl final : public Greeter::Service {
+  virtual grpc::Status SayHello(
+      grpc::ServerContext *context,
+      const flatbuffers::grpc::Message<HelloRequest> *request_msg,
+      flatbuffers::grpc::Message<HelloReply> *response_msg) override {
+    // flatbuffers::grpc::MessageBuilder mb_;
+    // We call GetRoot to "parse" the message. Verification is already
+    // performed by default. See the notes below for more details.
+    const HelloRequest *request = request_msg->GetRoot();
+
+    // Fields are retrieved as usual with FlatBuffers
+    const std::string &name = request->name()->str();
+
+    // `flatbuffers::grpc::MessageBuilder` is a `FlatBufferBuilder` with a
+    // special allocator for efficient gRPC buffer transfer, but otherwise
+    // usage is the same as usual.
+    auto msg_offset = mb_.CreateString("Hello, " + name);
+    auto hello_offset = CreateHelloReply(mb_, msg_offset);
+    mb_.Finish(hello_offset);
+
+    // The `ReleaseMessage<T>()` function detaches the message from the
+    // builder, so we can transfer the resopnse to gRPC while simultaneously
+    // detaching that memory buffer from the builer.
+    *response_msg = mb_.ReleaseMessage<HelloReply>();
+    assert(response_msg->Verify());
+
+    // Return an OK status.
+    return grpc::Status::OK;
+  }
+
+  virtual grpc::Status SayManyHellos(
+      grpc::ServerContext *context,
+      const flatbuffers::grpc::Message<ManyHellosRequest> *request_msg,
+      grpc::ServerWriter<flatbuffers::grpc::Message<HelloReply>> *writer)
+      override {
+    // The streaming usage below is simply a combination of standard gRPC
+    // streaming with the FlatBuffers usage shown above.
+    const ManyHellosRequest *request = request_msg->GetRoot();
+    const std::string &name = request->name()->str();
+    int num_greetings = request->num_greetings();
+
+    for (int i = 0; i < num_greetings; i++) {
+      auto msg_offset = mb_.CreateString("Many hellos, " + name);
+      auto hello_offset = CreateHelloReply(mb_, msg_offset);
+      mb_.Finish(hello_offset);
+      writer->Write(mb_.ReleaseMessage<HelloReply>());
+    }
+
+    return grpc::Status::OK;
+  }
+
+  flatbuffers::grpc::MessageBuilder mb_;
+};
+
+void RunServer() {
+  std::string server_address("0.0.0.0:50051");
+  GreeterServiceImpl service;
+
+  grpc::ServerBuilder builder;
+  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+  builder.RegisterService(&service);
+  std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
+  std::cerr << "Server listening on " << server_address << std::endl;
+
+  server->Wait();
+}
+
+int main(int argc, const char *argv[]) {
+  RunServer();
+  return 0;
+}
diff --git a/grpc/src/compiler/config.h b/grpc/src/compiler/config.h
new file mode 100644
index 0000000..4adc594
--- /dev/null
+++ b/grpc/src/compiler/config.h
@@ -0,0 +1,40 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef SRC_COMPILER_CONFIG_H
+#define SRC_COMPILER_CONFIG_H
+
+// This file is here only because schema_interface.h, which is copied from gRPC,
+// includes it. There is nothing for Flatbuffers to configure.
+
+#endif  // SRC_COMPILER_CONFIG_H
diff --git a/grpc/src/compiler/cpp_generator.cc b/grpc/src/compiler/cpp_generator.cc
index da58ee0..0f7ed5d 100644
--- a/grpc/src/compiler/cpp_generator.cc
+++ b/grpc/src/compiler/cpp_generator.cc
@@ -40,6 +40,9 @@
 namespace grpc_cpp_generator {
 namespace {
 
+grpc::string message_header_ext() { return "_generated.h"; }
+grpc::string service_header_ext() { return ".grpc.fb.h"; }
+
 template <class T>
 grpc::string as_string(T x) {
   std::ostringstream out;
@@ -47,6 +50,14 @@
   return out.str();
 }
 
+inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
+  return method->ClientStreaming() && !method->ServerStreaming();
+}
+
+inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
+  return !method->ClientStreaming() && method->ServerStreaming();
+}
+
 grpc::string FilenameIdentifier(const grpc::string &filename) {
   grpc::string result;
   for (unsigned i = 0; i < filename.size(); i++) {
@@ -64,19 +75,23 @@
 }
 }  // namespace
 
-template<class T, size_t N>
-T *array_end(T (&array)[N]) { return array + N; }
+template <class T, size_t N>
+T *array_end(T (&array)[N]) {
+  return array + N;
+}
 
-void PrintIncludes(grpc_generator::Printer *printer, 
-                   const std::vector<grpc::string>& headers, const Parameters &params) {
+void PrintIncludes(grpc_generator::Printer *printer,
+                   const std::vector<grpc::string> &headers,
+                   const Parameters &params) {
   std::map<grpc::string, grpc::string> vars;
 
   vars["l"] = params.use_system_headers ? '<' : '"';
   vars["r"] = params.use_system_headers ? '>' : '"';
 
-  if (!params.grpc_search_path.empty()) {
-    vars["l"] += params.grpc_search_path;
-    if (params.grpc_search_path.back() != '/') {
+  auto &s = params.grpc_search_path;
+  if (!s.empty()) {
+    vars["l"] += s;
+    if (s[s.size() - 1] != '/') {
       vars["l"] += '/';
     }
   }
@@ -87,7 +102,8 @@
   }
 }
 
-grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -97,17 +113,22 @@
     vars["filename"] = file->filename();
     vars["filename_identifier"] = FilenameIdentifier(file->filename());
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = file->message_header_ext();
+    vars["message_header_ext"] = message_header_ext();
 
-    printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+    printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
-                  "// If you make any local change, they will be lost.\n");
+                   "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n");
+    grpc::string leading_comments = file->GetLeadingComments("//");
+    if (!leading_comments.empty()) {
+      printer->Print(vars, "// Original file comments:\n");
+      printer->Print(leading_comments.c_str());
+    }
     printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n");
     printer->Print(vars, "\n");
-    printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
     printer->Print(vars, file->additional_headers().c_str());
+    printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
     printer->Print(vars, "\n");
   }
   return output;
@@ -122,14 +143,15 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
-      "grpc++/impl/codegen/async_stream.h",
-      "grpc++/impl/codegen/async_unary_call.h",
-      "grpc++/impl/codegen/rpc_method.h",
-      "grpc++/impl/codegen/service_type.h",
-      "grpc++/impl/codegen/status.h",
-      "grpc++/impl/codegen/stub_options.h",
-      "grpc++/impl/codegen/sync_stream.h"
-    };
+        "grpc++/impl/codegen/async_stream.h",
+        "grpc++/impl/codegen/async_unary_call.h",
+        "grpc++/impl/codegen/method_handler_impl.h",
+        "grpc++/impl/codegen/proto_utils.h",
+        "grpc++/impl/codegen/rpc_method.h",
+        "grpc++/impl/codegen/service_type.h",
+        "grpc++/impl/codegen/status.h",
+        "grpc++/impl/codegen/stub_options.h",
+        "grpc++/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
     PrintIncludes(printer.get(), headers, params);
     printer->Print(vars, "\n");
@@ -180,7 +202,7 @@
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>"
@@ -206,7 +228,7 @@
                      "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>"
@@ -268,7 +290,7 @@
           "Async$Method$Raw(::grpc::ClientContext* context, "
           "const $Request$& request, "
           "::grpc::CompletionQueue* cq) = 0;\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientWriterInterface< $Request$>*"
@@ -279,7 +301,7 @@
                      " Async$Method$Raw(::grpc::ClientContext* context, "
                      "$Response$* response, "
                      "::grpc::CompletionQueue* cq, void* tag) = 0;\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "virtual ::grpc::ClientReaderInterface< $Response$>* $Method$Raw("
@@ -316,7 +338,7 @@
       printer->Print(
           *vars,
           "::grpc::Status $Method$(::grpc::ClientContext* context, "
-          "const $Request$& request, $Response$* response) GRPC_OVERRIDE;\n");
+          "const $Request$& request, $Response$* response) override;\n");
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> "
@@ -330,7 +352,7 @@
                      "Async$Method$Raw(context, request, cq));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientWriter< $Request$>>"
@@ -354,7 +376,7 @@
           "Async$Method$Raw(context, response, cq, tag));\n");
       printer->Outdent();
       printer->Print("}\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(
           *vars,
           "std::unique_ptr< ::grpc::ClientReader< $Response$>>"
@@ -411,64 +433,64 @@
                      "::grpc::ClientAsyncResponseReader< $Response$>* "
                      "Async$Method$Raw(::grpc::ClientContext* context, "
                      "const $Request$& request, "
-                     "::grpc::CompletionQueue* cq) GRPC_OVERRIDE;\n");
-    } else if (method->ClientOnlyStreaming()) {
+                     "::grpc::CompletionQueue* cq) override;\n");
+    } else if (ClientOnlyStreaming(method)) {
       printer->Print(*vars,
                      "::grpc::ClientWriter< $Request$>* $Method$Raw("
                      "::grpc::ClientContext* context, $Response$* response) "
-                     "GRPC_OVERRIDE;\n");
-      printer->Print(
-          *vars,
-          "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
-          "::grpc::ClientContext* context, $Response$* response, "
-          "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
-    } else if (method->ServerOnlyStreaming()) {
+                     "override;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientAsyncWriter< $Request$>* Async$Method$Raw("
+                     "::grpc::ClientContext* context, $Response$* response, "
+                     "::grpc::CompletionQueue* cq, void* tag) override;\n");
+    } else if (ServerOnlyStreaming(method)) {
       printer->Print(*vars,
                      "::grpc::ClientReader< $Response$>* $Method$Raw("
                      "::grpc::ClientContext* context, const $Request$& request)"
-                     " GRPC_OVERRIDE;\n");
+                     " override;\n");
       printer->Print(
           *vars,
           "::grpc::ClientAsyncReader< $Response$>* Async$Method$Raw("
           "::grpc::ClientContext* context, const $Request$& request, "
-          "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
+          "::grpc::CompletionQueue* cq, void* tag) override;\n");
     } else if (method->BidiStreaming()) {
-      printer->Print(
-          *vars,
-          "::grpc::ClientReaderWriter< $Request$, $Response$>* "
-          "$Method$Raw(::grpc::ClientContext* context) GRPC_OVERRIDE;\n");
-      printer->Print(
-          *vars,
-          "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
-          "Async$Method$Raw(::grpc::ClientContext* context, "
-          "::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientReaderWriter< $Request$, $Response$>* "
+                     "$Method$Raw(::grpc::ClientContext* context) override;\n");
+      printer->Print(*vars,
+                     "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
+                     "Async$Method$Raw(::grpc::ClientContext* context, "
+                     "::grpc::CompletionQueue* cq, void* tag) override;\n");
     }
   }
 }
 
-void PrintHeaderClientMethodData(grpc_generator::Printer *printer, const grpc_generator::Method *method,
+void PrintHeaderClientMethodData(grpc_generator::Printer *printer,
+                                 const grpc_generator::Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   printer->Print(*vars, "const ::grpc::RpcMethod rpcmethod_$Method$_;\n");
 }
 
-void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, const grpc_generator::Method *method,
+void PrintHeaderServerMethodSync(grpc_generator::Printer *printer,
+                                 const grpc_generator::Method *method,
                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
   (*vars)["Response"] = method->output_type_name();
+  printer->Print(method->GetLeadingComments("//").c_str());
   if (method->NoStreaming()) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
                    "$Response$* response);\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, "
                    "::grpc::ServerReader< $Request$>* reader, "
                    "$Response$* response);\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
                    "virtual ::grpc::Status $Method$("
                    "::grpc::ServerContext* context, const $Request$* request, "
@@ -481,12 +503,12 @@
         "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);"
         "\n");
   }
+  printer->Print(method->GetTrailingComments("//").c_str());
 }
 
-void PrintHeaderServerMethodAsync(
-    grpc_generator::Printer *printer,
-    const grpc_generator::Method *method,
-    std::map<grpc::string, grpc::string> *vars) {
+void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer,
+                                  const grpc_generator::Method *method,
+                                  std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
   (*vars)["Response"] = method->output_type_name();
@@ -503,7 +525,7 @@
                  "  ::grpc::Service::MarkMethodAsync($Idx$);\n"
                  "}\n");
   printer->Print(*vars,
-                 "~WithAsyncMethod_$Method$() GRPC_OVERRIDE {\n"
+                 "~WithAsyncMethod_$Method$() override {\n"
                  "  BaseClassMustBeDerivedFromService(this);\n"
                  "}\n");
   if (method->NoStreaming()) {
@@ -512,7 +534,7 @@
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, const $Request$* request, "
-        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "$Response$* response) final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
@@ -527,14 +549,14 @@
                    "  ::grpc::Service::RequestAsyncUnary($Idx$, context, "
                    "request, response, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerReader< $Request$>* reader, "
-        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "$Response$* response) final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
@@ -549,13 +571,13 @@
                    "  ::grpc::Service::RequestAsyncClientStreaming($Idx$, "
                    "context, reader, new_call_cq, notification_cq, tag);\n");
     printer->Print("}\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, const $Request$* request, "
-        "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+        "::grpc::ServerWriter< $Response$>* writer) final override "
         "{\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
@@ -579,7 +601,7 @@
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
-        "GRPC_FINAL GRPC_OVERRIDE {\n"
+        "final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
@@ -599,9 +621,111 @@
   printer->Print(*vars, "};\n");
 }
 
+void PrintHeaderServerMethodStreamedUnary(
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
+    std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["Method"] = method->name();
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+  if (method->NoStreaming()) {
+    printer->Print(*vars, "template <class BaseClass>\n");
+    printer->Print(*vars,
+                   "class WithStreamedUnaryMethod_$Method$ : "
+                   "public BaseClass {\n");
+    printer->Print(
+        " private:\n"
+        "  void BaseClassMustBeDerivedFromService(const Service *service) "
+        "{}\n");
+    printer->Print(" public:\n");
+    printer->Indent();
+    printer->Print(*vars,
+                   "WithStreamedUnaryMethod_$Method$() {\n"
+                   "  ::grpc::Service::MarkMethodStreamed($Idx$,\n"
+                   "    new ::grpc::StreamedUnaryHandler< $Request$, "
+                   "$Response$>(std::bind"
+                   "(&WithStreamedUnaryMethod_$Method$<BaseClass>::"
+                   "Streamed$Method$, this, std::placeholders::_1, "
+                   "std::placeholders::_2)));\n"
+                   "}\n");
+    printer->Print(*vars,
+                   "~WithStreamedUnaryMethod_$Method$() override {\n"
+                   "  BaseClassMustBeDerivedFromService(this);\n"
+                   "}\n");
+    printer->Print(
+        *vars,
+        "// disable regular version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "$Response$* response) final override {\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(*vars,
+                   "// replace default version of method with streamed unary\n"
+                   "virtual ::grpc::Status Streamed$Method$("
+                   "::grpc::ServerContext* context, "
+                   "::grpc::ServerUnaryStreamer< "
+                   "$Request$,$Response$>* server_unary_streamer)"
+                   " = 0;\n");
+    printer->Outdent();
+    printer->Print(*vars, "};\n");
+  }
+}
+
+void PrintHeaderServerMethodSplitStreaming(
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
+    std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["Method"] = method->name();
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+  if (ServerOnlyStreaming(method)) {
+    printer->Print(*vars, "template <class BaseClass>\n");
+    printer->Print(*vars,
+                   "class WithSplitStreamingMethod_$Method$ : "
+                   "public BaseClass {\n");
+    printer->Print(
+        " private:\n"
+        "  void BaseClassMustBeDerivedFromService(const Service *service) "
+        "{}\n");
+    printer->Print(" public:\n");
+    printer->Indent();
+    printer->Print(*vars,
+                   "WithSplitStreamingMethod_$Method$() {\n"
+                   "  ::grpc::Service::MarkMethodStreamed($Idx$,\n"
+                   "    new ::grpc::SplitServerStreamingHandler< $Request$, "
+                   "$Response$>(std::bind"
+                   "(&WithSplitStreamingMethod_$Method$<BaseClass>::"
+                   "Streamed$Method$, this, std::placeholders::_1, "
+                   "std::placeholders::_2)));\n"
+                   "}\n");
+    printer->Print(*vars,
+                   "~WithSplitStreamingMethod_$Method$() override {\n"
+                   "  BaseClassMustBeDerivedFromService(this);\n"
+                   "}\n");
+    printer->Print(
+        *vars,
+        "// disable regular version of this method\n"
+        "::grpc::Status $Method$("
+        "::grpc::ServerContext* context, const $Request$* request, "
+        "::grpc::ServerWriter< $Response$>* writer) final override "
+        "{\n"
+        "  abort();\n"
+        "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
+        "}\n");
+    printer->Print(*vars,
+                   "// replace default version of method with split streamed\n"
+                   "virtual ::grpc::Status Streamed$Method$("
+                   "::grpc::ServerContext* context, "
+                   "::grpc::ServerSplitStreamer< "
+                   "$Request$,$Response$>* server_split_streamer)"
+                   " = 0;\n");
+    printer->Outdent();
+    printer->Print(*vars, "};\n");
+  }
+}
+
 void PrintHeaderServerMethodGeneric(
-    grpc_generator::Printer *printer,
-    const grpc_generator::Method *method,
+    grpc_generator::Printer *printer, const grpc_generator::Method *method,
     std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Method"] = method->name();
   (*vars)["Request"] = method->input_type_name();
@@ -619,7 +743,7 @@
                  "  ::grpc::Service::MarkMethodGeneric($Idx$);\n"
                  "}\n");
   printer->Print(*vars,
-                 "~WithGenericMethod_$Method$() GRPC_OVERRIDE {\n"
+                 "~WithGenericMethod_$Method$() override {\n"
                  "  BaseClassMustBeDerivedFromService(this);\n"
                  "}\n");
   if (method->NoStreaming()) {
@@ -628,28 +752,28 @@
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, const $Request$* request, "
-        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "$Response$* response) final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerReader< $Request$>* reader, "
-        "$Response$* response) GRPC_FINAL GRPC_OVERRIDE {\n"
+        "$Response$* response) final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "// disable synchronous version of this method\n"
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, const $Request$* request, "
-        "::grpc::ServerWriter< $Response$>* writer) GRPC_FINAL GRPC_OVERRIDE "
+        "::grpc::ServerWriter< $Response$>* writer) final override "
         "{\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
@@ -661,7 +785,7 @@
         "::grpc::Status $Method$("
         "::grpc::ServerContext* context, "
         "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) "
-        "GRPC_FINAL GRPC_OVERRIDE {\n"
+        "final override {\n"
         "  abort();\n"
         "  return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"
         "}\n");
@@ -675,11 +799,18 @@
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
+  printer->Print(service->GetLeadingComments("//").c_str());
   printer->Print(*vars,
-                 "class $Service$ GRPC_FINAL {\n"
+                 "class $Service$ final {\n"
                  " public:\n");
   printer->Indent();
 
+  // Service metadata
+  printer->Print(*vars,
+                 "static constexpr char const* service_full_name() {\n"
+                 "  return \"$Package$$Service$\";\n"
+                 "}\n");
+
   // Client side
   printer->Print(
       "class StubInterface {\n"
@@ -687,21 +818,26 @@
   printer->Indent();
   printer->Print("virtual ~StubInterface() {}\n");
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, true);
+    printer->Print(service->method(i)->GetLeadingComments("//").c_str());
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+                                      true);
+    printer->Print(service->method(i)->GetTrailingComments("//").c_str());
   }
   printer->Outdent();
   printer->Print("private:\n");
   printer->Indent();
   for (int i = 0; i < service->method_count(); ++i) {
-    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, false);
+    PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars,
+                                      false);
   }
   printer->Outdent();
   printer->Print("};\n");
   printer->Print(
-      "class Stub GRPC_FINAL : public StubInterface"
+      "class Stub final : public StubInterface"
       " {\n public:\n");
   printer->Indent();
-  printer->Print("Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
+  printer->Print(
+      "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);\n");
   for (int i = 0; i < service->method_count(); ++i) {
     PrintHeaderClientMethod(printer, service->method(i).get(), vars, true);
   }
@@ -761,8 +897,77 @@
     PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars);
   }
 
+  // Server side - Streamed Unary
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["Idx"] = as_string(i);
+    PrintHeaderServerMethodStreamedUnary(printer, service->method(i).get(),
+                                         vars);
+  }
+
+  printer->Print("typedef ");
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["method_name"] = service->method(i).get()->name();
+    if (service->method(i)->NoStreaming()) {
+      printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<");
+    }
+  }
+  printer->Print("Service");
+  for (int i = 0; i < service->method_count(); ++i) {
+    if (service->method(i)->NoStreaming()) {
+      printer->Print(" >");
+    }
+  }
+  printer->Print(" StreamedUnaryService;\n");
+
+  // Server side - controlled server-side streaming
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["Idx"] = as_string(i);
+    PrintHeaderServerMethodSplitStreaming(printer, service->method(i).get(),
+                                          vars);
+  }
+
+  printer->Print("typedef ");
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["method_name"] = service->method(i).get()->name();
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
+      printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
+    }
+  }
+  printer->Print("Service");
+  for (int i = 0; i < service->method_count(); ++i) {
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
+      printer->Print(" >");
+    }
+  }
+  printer->Print(" SplitStreamedService;\n");
+
+  // Server side - typedef for controlled both unary and server-side streaming
+  printer->Print("typedef ");
+  for (int i = 0; i < service->method_count(); ++i) {
+    (*vars)["method_name"] = service->method(i).get()->name();
+    auto method = service->method(i);
+    if (ServerOnlyStreaming(method.get())) {
+      printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<");
+    }
+    if (service->method(i)->NoStreaming()) {
+      printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<");
+    }
+  }
+  printer->Print("Service");
+  for (int i = 0; i < service->method_count(); ++i) {
+    auto method = service->method(i);
+    if (service->method(i)->NoStreaming() ||
+        ServerOnlyStreaming(method.get())) {
+      printer->Print(" >");
+    }
+  }
+  printer->Print(" StreamedService;\n");
+
   printer->Outdent();
   printer->Print("};\n");
+  printer->Print(service->GetTrailingComments("//").c_str());
 }
 
 grpc::string GetHeaderServices(grpc_generator::File *file,
@@ -796,7 +1001,8 @@
   return output;
 }
 
-grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters & /*params*/) {
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -818,11 +1024,14 @@
 
     printer->Print(vars, "\n");
     printer->Print(vars, "#endif  // GRPC_$filename_identifier$__INCLUDED\n");
+
+    printer->Print(file->GetTrailingComments("//").c_str());
   }
   return output;
 }
 
-grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters & /*params*/) {
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string output;
   {
     // Scope the output stream so it closes and finalizes output to the string.
@@ -831,16 +1040,17 @@
 
     vars["filename"] = file->filename();
     vars["filename_base"] = file->filename_without_ext();
-    vars["message_header_ext"] = file->message_header_ext();
-    vars["service_header_ext"] = file->service_header_ext();
+    vars["message_header_ext"] = message_header_ext();
+    vars["service_header_ext"] = service_header_ext();
 
-    printer->Print(vars, "// Generated by the gRPC protobuf plugin.\n");
+    printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
     printer->Print(vars,
-                  "// If you make any local change, they will be lost.\n");
+                   "// If you make any local change, they will be lost.\n");
     printer->Print(vars, "// source: $filename$\n\n");
+
     printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
     printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
-    printer->Print("\n");
+    printer->Print(vars, "\n");
   }
   return output;
 }
@@ -854,20 +1064,18 @@
     std::map<grpc::string, grpc::string> vars;
 
     static const char *headers_strs[] = {
-      "grpc++/impl/codegen/async_stream.h",
-      "grpc++/impl/codegen/async_unary_call.h",
-      "grpc++/impl/codegen/channel_interface.h",
-      "grpc++/impl/codegen/client_unary_call.h",
-      "grpc++/impl/codegen/method_handler_impl.h",
-      "grpc++/impl/codegen/rpc_service_method.h",
-      "grpc++/impl/codegen/service_type.h",
-      "grpc++/impl/codegen/sync_stream.h"
-    };
+        "grpc++/impl/codegen/async_stream.h",
+        "grpc++/impl/codegen/async_unary_call.h",
+        "grpc++/impl/codegen/channel_interface.h",
+        "grpc++/impl/codegen/client_unary_call.h",
+        "grpc++/impl/codegen/method_handler_impl.h",
+        "grpc++/impl/codegen/rpc_service_method.h",
+        "grpc++/impl/codegen/service_type.h",
+        "grpc++/impl/codegen/sync_stream.h"};
     std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
     PrintIncludes(printer.get(), headers, params);
 
     if (!file->package().empty()) {
-      printer->Print("\n");
       std::vector<grpc::string> parts = file->package_parts();
 
       for (auto part = parts.begin(); part != parts.end(); part++) {
@@ -904,13 +1112,13 @@
         "const $Request$& request, "
         "::grpc::CompletionQueue* cq) {\n");
     printer->Print(*vars,
-                   "  return new "
-                   "::grpc::ClientAsyncResponseReader< $Response$>("
+                   "  return "
+                   "::grpc::ClientAsyncResponseReader< $Response$>::Create("
                    "channel_.get(), cq, "
                    "rpcmethod_$Method$_, "
                    "context, request);\n"
                    "}\n\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::ClientWriter< $Request$>* "
                    "$ns$$Service$::Stub::$Method$Raw("
@@ -927,12 +1135,12 @@
                    "::grpc::ClientContext* context, $Response$* response, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
-                   "  return new ::grpc::ClientAsyncWriter< $Request$>("
+                   "  return ::grpc::ClientAsyncWriter< $Request$>::Create("
                    "channel_.get(), cq, "
                    "rpcmethod_$Method$_, "
                    "context, response, tag);\n"
                    "}\n\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(
         *vars,
         "::grpc::ClientReader< $Response$>* "
@@ -950,7 +1158,7 @@
                    "::grpc::ClientContext* context, const $Request$& request, "
                    "::grpc::CompletionQueue* cq, void* tag) {\n");
     printer->Print(*vars,
-                   "  return new ::grpc::ClientAsyncReader< $Response$>("
+                   "  return ::grpc::ClientAsyncReader< $Response$>::Create("
                    "channel_.get(), cq, "
                    "rpcmethod_$Method$_, "
                    "context, request, tag);\n"
@@ -972,13 +1180,14 @@
         "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* "
         "$ns$$Service$::Stub::Async$Method$Raw(::grpc::ClientContext* context, "
         "::grpc::CompletionQueue* cq, void* tag) {\n");
-    printer->Print(*vars,
-                   "  return new "
-                   "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>("
-                   "channel_.get(), cq, "
-                   "rpcmethod_$Method$_, "
-                   "context, tag);\n"
-                   "}\n\n");
+    printer->Print(
+        *vars,
+        "  return "
+        "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>::Create("
+        "channel_.get(), cq, "
+        "rpcmethod_$Method$_, "
+        "context, tag);\n"
+        "}\n\n");
   }
 }
 
@@ -1000,7 +1209,7 @@
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (method->ClientOnlyStreaming()) {
+  } else if (ClientOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1013,7 +1222,7 @@
         "  return ::grpc::Status("
         "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n");
     printer->Print("}\n\n");
-  } else if (method->ServerOnlyStreaming()) {
+  } else if (ServerOnlyStreaming(method)) {
     printer->Print(*vars,
                    "::grpc::Status $ns$$Service$::Service::$Method$("
                    "::grpc::ServerContext* context, "
@@ -1046,13 +1255,15 @@
                         std::map<grpc::string, grpc::string> *vars) {
   (*vars)["Service"] = service->name();
 
-  printer->Print(*vars,
-                 "static const char* $prefix$$Service$_method_names[] = {\n");
-  for (int i = 0; i < service->method_count(); ++i) {
-    (*vars)["Method"] = service->method(i).get()->name();
-    printer->Print(*vars, "  \"/$Package$$Service$/$Method$\",\n");
+  if (service->method_count() > 0) {
+    printer->Print(*vars,
+                   "static const char* $prefix$$Service$_method_names[] = {\n");
+    for (int i = 0; i < service->method_count(); ++i) {
+      (*vars)["Method"] = service->method(i).get()->name();
+      printer->Print(*vars, "  \"/$Package$$Service$/$Method$\",\n");
+    }
+    printer->Print(*vars, "};\n\n");
   }
-  printer->Print(*vars, "};\n\n");
 
   printer->Print(*vars,
                  "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub("
@@ -1073,9 +1284,12 @@
     (*vars)["Idx"] = as_string(i);
     if (method->NoStreaming()) {
       (*vars)["StreamingType"] = "NORMAL_RPC";
-    } else if (method->ClientOnlyStreaming()) {
+      // NOTE: There is no reason to consider streamed-unary as a separate
+      // category here since this part is setting up the client-side stub
+      // and this appears as a NORMAL_RPC from the client-side.
+    } else if (ClientOnlyStreaming(method.get())) {
       (*vars)["StreamingType"] = "CLIENT_STREAMING";
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method.get())) {
       (*vars)["StreamingType"] = "SERVER_STREAMING";
     } else {
       (*vars)["StreamingType"] = "BIDI_STREAMING";
@@ -1097,7 +1311,6 @@
 
   printer->Print(*vars, "$ns$$Service$::Service::Service() {\n");
   printer->Indent();
-  printer->Print(*vars, "(void)$prefix$$Service$_method_names;\n");
   for (int i = 0; i < service->method_count(); ++i) {
     auto method = service->method(i);
     (*vars)["Idx"] = as_string(i);
@@ -1114,7 +1327,7 @@
           "$Request$, "
           "$Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (method->ClientOnlyStreaming()) {
+    } else if (ClientOnlyStreaming(method.get())) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1123,7 +1336,7 @@
           "    new ::grpc::ClientStreamingHandler< "
           "$ns$$Service$::Service, $Request$, $Response$>(\n"
           "        std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n");
-    } else if (method->ServerOnlyStreaming()) {
+    } else if (ServerOnlyStreaming(method.get())) {
       printer->Print(
           *vars,
           "AddMethod(new ::grpc::RpcServiceMethod(\n"
@@ -1183,7 +1396,8 @@
   return output;
 }
 
-grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters & /*params*/) {
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+                               const Parameters & /*params*/) {
   grpc::string temp;
 
   if (!file->package().empty()) {
@@ -1200,4 +1414,180 @@
   return temp;
 }
 
+// TODO(mmukhi): Make sure we need parameters or not.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+                             const Parameters & /*params*/) {
+  grpc::string output;
+  {
+    // Scope the output stream so it closes and finalizes output to the string.
+    auto printer = file->CreatePrinter(&output);
+    std::map<grpc::string, grpc::string> vars;
+
+    vars["filename"] = file->filename();
+    vars["filename_base"] = file->filename_without_ext();
+    vars["message_header_ext"] = message_header_ext();
+    vars["service_header_ext"] = service_header_ext();
+
+    printer->Print(vars, "// Generated by the gRPC C++ plugin.\n");
+    printer->Print(vars,
+                   "// If you make any local change, they will be lost.\n");
+    printer->Print(vars, "// source: $filename$\n\n");
+
+    printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n");
+    printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n");
+    printer->Print(vars, file->additional_headers().c_str());
+    printer->Print(vars, "\n");
+  }
+  return output;
+}
+
+// TODO(mmukhi): Add client-stream and completion-queue headers.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+                             const Parameters &params) {
+  grpc::string output;
+  {
+    // Scope the output stream so it closes and finalizes output to the string.
+    auto printer = file->CreatePrinter(&output);
+    std::map<grpc::string, grpc::string> vars;
+
+    static const char *headers_strs[] = {
+        "grpc++/impl/codegen/async_stream.h",
+        "grpc++/impl/codegen/sync_stream.h", "gmock/gmock.h",
+    };
+    std::vector<grpc::string> headers(headers_strs, array_end(headers_strs));
+    PrintIncludes(printer.get(), headers, params);
+
+    if (!file->package().empty()) {
+      std::vector<grpc::string> parts = file->package_parts();
+
+      for (auto part = parts.begin(); part != parts.end(); part++) {
+        vars["part"] = *part;
+        printer->Print(vars, "namespace $part$ {\n");
+      }
+    }
+
+    printer->Print(vars, "\n");
+  }
+  return output;
+}
+
+void PrintMockClientMethods(grpc_generator::Printer *printer,
+                            const grpc_generator::Method *method,
+                            std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["Method"] = method->name();
+  (*vars)["Request"] = method->input_type_name();
+  (*vars)["Response"] = method->output_type_name();
+
+  if (method->NoStreaming()) {
+    printer->Print(
+        *vars,
+        "MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, "
+        "const $Request$& request, $Response$* response));\n");
+    printer->Print(*vars,
+                   "MOCK_METHOD3(Async$Method$Raw, "
+                   "::grpc::ClientAsyncResponseReaderInterface< $Response$>*"
+                   "(::grpc::ClientContext* context, const $Request$& request, "
+                   "::grpc::CompletionQueue* cq));\n");
+  } else if (ClientOnlyStreaming(method)) {
+    printer->Print(
+        *vars,
+        "MOCK_METHOD2($Method$Raw, "
+        "::grpc::ClientWriterInterface< $Request$>*"
+        "(::grpc::ClientContext* context, $Response$* response));\n");
+    printer->Print(*vars,
+                   "MOCK_METHOD4(Async$Method$Raw, "
+                   "::grpc::ClientAsyncWriterInterface< $Request$>*"
+                   "(::grpc::ClientContext* context, $Response$* response, "
+                   "::grpc::CompletionQueue* cq, void* tag));\n");
+  } else if (ServerOnlyStreaming(method)) {
+    printer->Print(
+        *vars,
+        "MOCK_METHOD2($Method$Raw, "
+        "::grpc::ClientReaderInterface< $Response$>*"
+        "(::grpc::ClientContext* context, const $Request$& request));\n");
+    printer->Print(*vars,
+                   "MOCK_METHOD4(Async$Method$Raw, "
+                   "::grpc::ClientAsyncReaderInterface< $Response$>*"
+                   "(::grpc::ClientContext* context, const $Request$& request, "
+                   "::grpc::CompletionQueue* cq, void* tag));\n");
+  } else if (method->BidiStreaming()) {
+    printer->Print(
+        *vars,
+        "MOCK_METHOD1($Method$Raw, "
+        "::grpc::ClientReaderWriterInterface< $Request$, $Response$>*"
+        "(::grpc::ClientContext* context));\n");
+    printer->Print(
+        *vars,
+        "MOCK_METHOD3(Async$Method$Raw, "
+        "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*"
+        "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq, "
+        "void* tag));\n");
+  }
+}
+
+void PrintMockService(grpc_generator::Printer *printer,
+                      const grpc_generator::Service *service,
+                      std::map<grpc::string, grpc::string> *vars) {
+  (*vars)["Service"] = service->name();
+
+  printer->Print(*vars,
+                 "class Mock$Service$Stub : public $Service$::StubInterface {\n"
+                 " public:\n");
+  printer->Indent();
+  for (int i = 0; i < service->method_count(); ++i) {
+    PrintMockClientMethods(printer, service->method(i).get(), vars);
+  }
+  printer->Outdent();
+  printer->Print("};\n");
+}
+
+grpc::string GetMockServices(grpc_generator::File *file,
+                             const Parameters &params) {
+  grpc::string output;
+  {
+    // Scope the output stream so it closes and finalizes output to the string.
+    auto printer = file->CreatePrinter(&output);
+    std::map<grpc::string, grpc::string> vars;
+    // Package string is empty or ends with a dot. It is used to fully qualify
+    // method names.
+    vars["Package"] = file->package();
+    if (!file->package().empty()) {
+      vars["Package"].append(".");
+    }
+
+    if (!params.services_namespace.empty()) {
+      vars["services_namespace"] = params.services_namespace;
+      printer->Print(vars, "\nnamespace $services_namespace$ {\n\n");
+    }
+
+    for (int i = 0; i < file->service_count(); i++) {
+      PrintMockService(printer.get(), file->service(i).get(), &vars);
+      printer->Print("\n");
+    }
+
+    if (!params.services_namespace.empty()) {
+      printer->Print(vars, "} // namespace $services_namespace$\n\n");
+    }
+  }
+  return output;
+}
+
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+                             const Parameters & /*params*/) {
+  grpc::string temp;
+
+  if (!file->package().empty()) {
+    std::vector<grpc::string> parts = file->package_parts();
+
+    for (auto part = parts.begin(); part != parts.end(); part++) {
+      temp.append("} // namespace ");
+      temp.append(*part);
+      temp.append("\n");
+    }
+    temp.append("\n");
+  }
+
+  return temp;
+}
+
 }  // namespace grpc_cpp_generator
diff --git a/grpc/src/compiler/cpp_generator.h b/grpc/src/compiler/cpp_generator.h
index a4adee7..6119ebe 100644
--- a/grpc/src/compiler/cpp_generator.h
+++ b/grpc/src/compiler/cpp_generator.h
@@ -41,8 +41,20 @@
 #include <memory>
 #include <vector>
 
+#include "src/compiler/config.h"
 #include "src/compiler/schema_interface.h"
 
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
+
+namespace grpc {
+
+typedef GRPC_CUSTOM_STRING string;
+
+}  // namespace grpc
+
 namespace grpc_cpp_generator {
 
 // Contains all the parameters that are parsed from the command line.
@@ -53,31 +65,73 @@
   bool use_system_headers;
   // Prefix to any grpc include
   grpc::string grpc_search_path;
+  // Generate GMOCK code to facilitate unit testing.
+  bool generate_mock_code;
 };
 
 // Return the prologue of the generated header file.
-grpc::string GetHeaderPrologue(grpc_generator::File *file, const Parameters &params);
+grpc::string GetHeaderPrologue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the includes needed for generated header file.
-grpc::string GetHeaderIncludes(grpc_generator::File *file, const Parameters &params);
+grpc::string GetHeaderIncludes(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the includes needed for generated source file.
-grpc::string GetSourceIncludes(grpc_generator::File *file, const Parameters &params);
+grpc::string GetSourceIncludes(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the epilogue of the generated header file.
-grpc::string GetHeaderEpilogue(grpc_generator::File *file, const Parameters &params);
+grpc::string GetHeaderEpilogue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the prologue of the generated source file.
-grpc::string GetSourcePrologue(grpc_generator::File *file, const Parameters &params);
+grpc::string GetSourcePrologue(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the services for generated header file.
-grpc::string GetHeaderServices(grpc_generator::File *file, const Parameters &params);
+grpc::string GetHeaderServices(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the services for generated source file.
-grpc::string GetSourceServices(grpc_generator::File *file, const Parameters &params);
+grpc::string GetSourceServices(grpc_generator::File *file,
+                               const Parameters &params);
 
 // Return the epilogue of the generated source file.
-grpc::string GetSourceEpilogue(grpc_generator::File *file, const Parameters &params);
+grpc::string GetSourceEpilogue(grpc_generator::File *file,
+                               const Parameters &params);
+
+// Return the prologue of the generated mock file.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the includes needed for generated mock file.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the services for generated mock file.
+grpc::string GetMockServices(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the epilogue of generated mock file.
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the prologue of the generated mock file.
+grpc::string GetMockPrologue(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the includes needed for generated mock file.
+grpc::string GetMockIncludes(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the services for generated mock file.
+grpc::string GetMockServices(grpc_generator::File *file,
+                             const Parameters &params);
+
+// Return the epilogue of generated mock file.
+grpc::string GetMockEpilogue(grpc_generator::File *file,
+                             const Parameters &params);
 
 }  // namespace grpc_cpp_generator
 
diff --git a/grpc/src/compiler/go_generator.cc b/grpc/src/compiler/go_generator.cc
index ce4223d..0ed10cf 100644
--- a/grpc/src/compiler/go_generator.cc
+++ b/grpc/src/compiler/go_generator.cc
@@ -44,6 +44,14 @@
 	return out.str();
 }
 
+inline bool ClientOnlyStreaming(const grpc_generator::Method *method) {
+  return method->ClientStreaming() && !method->ServerStreaming();
+}
+
+inline bool ServerOnlyStreaming(const grpc_generator::Method *method) {
+  return !method->ClientStreaming() && method->ServerStreaming();
+}
+
 namespace grpc_go_generator {
 
 // Returns string with first letter to lowerCase
@@ -70,8 +78,8 @@
 	printer->Print("//If you make any local changes, they will be lost\n");
 	printer->Print(vars, "//source: $filename$\n\n");
 	printer->Print(vars, "package $Package$\n\n");
-	if (file->additional_imports() != "") {
-		printer->Print(file->additional_imports().c_str());
+	if (file->additional_headers() != "") {
+		printer->Print(file->additional_headers().c_str());
 		printer->Print("\n\n");
 	}
 	printer->Print("import (\n");
@@ -86,11 +94,11 @@
 void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
                                    std::map<grpc::string, grpc::string> vars) {
 	vars["Method"] = exportName(method->name());
-	vars["Request"] = method->input_name();
-	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
+	vars["Request"] = method->get_input_type_name();
+	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
 	if (method->NoStreaming()) {
 		printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)");
-	} else if (method->ServerOnlyStreaming()) {
+	} else if (ServerOnlyStreaming(method)) {
 		printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error");
 	} else {
 		printer->Print(vars, "$Method$($Service$_$Method$Server) error");
@@ -100,8 +108,8 @@
 void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer,
                           std::map<grpc::string, grpc::string> vars) {
 	vars["Method"] = exportName(method->name());
-	vars["Request"] = method->input_name();
-	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->output_name() : vars["CustomMethodIO"];
+	vars["Request"] = method->get_input_type_name();
+	vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"];
 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
 	vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler";
 	if (method->NoStreaming()) {
@@ -129,7 +137,7 @@
 	vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server";
 	printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n");
 	printer->Indent();
-	if (method->ServerOnlyStreaming()) {
+	if (ServerOnlyStreaming(method)) {
 		printer->Print(vars, "m := new($Request$)\n");
 		printer->Print(vars, "if err := stream.RecvMsg(m); err != nil { return err }\n");
 		printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n");
@@ -139,9 +147,9 @@
 	printer->Outdent();
 	printer->Print("}\n\n");
 
-	bool genSend = method->BidiStreaming() || method->ServerOnlyStreaming();
-	bool genRecv = method->BidiStreaming() || method->ClientOnlyStreaming();
-	bool genSendAndClose = method->ClientOnlyStreaming();
+	bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method);
+	bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method);
+	bool genSendAndClose = ClientOnlyStreaming(method);
 
 	printer->Print(vars, "type $Service$_$Method$Server interface { \n");
 	printer->Indent();
@@ -194,12 +202,12 @@
 void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer,
                                    std::map<grpc::string, grpc::string> vars) {
 	vars["Method"] = exportName(method->name());
-	vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"]);
-	if (method->ClientOnlyStreaming() || method->BidiStreaming()) {
+	vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]);
+	if (ClientOnlyStreaming(method) || method->BidiStreaming()) {
 		vars["Request"] = "";
 	}
-	vars["Response"] = "* " + method->output_name();
-	if (method->ClientOnlyStreaming() || method->BidiStreaming() || method->ServerOnlyStreaming()) {
+	vars["Response"] = "* " + method->get_output_type_name();
+	if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) {
 		vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ;
 	}
 	printer->Print(vars, "$Method$(ctx $context$.Context$Request$, \n\topts... $grpc$.CallOption) ($Response$, error)");
@@ -213,8 +221,8 @@
 	printer->Print(" {\n");
 	printer->Indent();
 	vars["Method"] = exportName(method->name());
-	vars["Request"] = (vars["CustomMethodIO"] == "") ? method->input_name() : vars["CustomMethodIO"];
-	vars["Response"] = method->output_name();
+	vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"];
+	vars["Response"] = method->get_output_type_name();
 	vars["FullMethodName"] = "/" + vars["Package"] + "." + vars["Service"] + "/" + vars["Method"];
 	if (method->NoStreaming()) {
 		printer->Print(vars, "out := new($Response$)\n");
@@ -230,7 +238,7 @@
 	printer->Print("if err != nil { return nil, err }\n");
 
 	printer->Print(vars, "x := &$StreamType${stream}\n");
-	if (method->ServerOnlyStreaming()) {
+	if (ServerOnlyStreaming(method)) {
 		printer->Print("if err := x.ClientStream.SendMsg(in); err != nil { return nil, err }\n");
 		printer->Print("if err := x.ClientStream.CloseSend(); err != nil { return nil, err }\n");
 	}
@@ -238,9 +246,9 @@
 	printer->Outdent();
 	printer->Print("}\n\n");
 
-	bool genSend = method->BidiStreaming() || method->ClientOnlyStreaming();
-	bool genRecv = method->BidiStreaming() || method->ServerOnlyStreaming();
-	bool genCloseAndRecv = method->ClientOnlyStreaming();
+	bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method);
+	bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method);
+	bool genCloseAndRecv = ClientOnlyStreaming(method);
 
 	//Stream interface
 	printer->Print(vars, "type $Service$_$Method$Client interface {\n");
@@ -396,9 +404,9 @@
 			printer->Indent();
 			printer->Print(vars, "StreamName: \"$Method$\",\n");
 			printer->Print(vars, "Handler: $Handler$, \n");
-			if (method->ClientOnlyStreaming()) {
+			if (ClientOnlyStreaming(method.get())) {
 				printer->Print("ClientStreams: true,\n");
-			} else if (method->ServerOnlyStreaming()) {
+			} else if (ServerOnlyStreaming(method.get())) {
 				printer->Print("ServerStreams: true,\n");
 			} else {
 				printer->Print("ServerStreams: true,\n");
diff --git a/grpc/src/compiler/go_generator.h b/grpc/src/compiler/go_generator.h
index a8f7a3d..e377024 100644
--- a/grpc/src/compiler/go_generator.h
+++ b/grpc/src/compiler/go_generator.h
@@ -43,12 +43,12 @@
 namespace grpc_go_generator {
 
 struct Parameters {
-	//Defines the custom parameter types for methods
-	//eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
-	grpc::string custom_method_io_type;
+  //Defines the custom parameter types for methods
+  //eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server
+  grpc::string custom_method_io_type;
 
-	//Package name for the service
-	grpc::string package_name;
+  //Package name for the service
+  grpc::string package_name;
 };
 
 // Return the source of the generated service file.
diff --git a/grpc/src/compiler/schema_interface.h b/grpc/src/compiler/schema_interface.h
index c9b7f46..25bbdb5 100644
--- a/grpc/src/compiler/schema_interface.h
+++ b/grpc/src/compiler/schema_interface.h
@@ -34,79 +34,93 @@
 #ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
 #define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
 
-#include <map>
+#include "src/compiler/config.h"
+
 #include <memory>
 #include <vector>
 
- #ifndef GRPC_CUSTOM_STRING
- #include <string>
- #define GRPC_CUSTOM_STRING std::string
- #endif
+#ifndef GRPC_CUSTOM_STRING
+#include <string>
+#define GRPC_CUSTOM_STRING std::string
+#endif
 
 namespace grpc {
 
-  typedef GRPC_CUSTOM_STRING string;
+typedef GRPC_CUSTOM_STRING string;
 
 }  // namespace grpc
 
 namespace grpc_generator {
 
-  // An abstract interface representing a method.
-  struct Method {
-    virtual ~Method() {}
+// A common interface for objects having comments in the source.
+// Return formatted comments to be inserted in generated code.
+struct CommentHolder {
+  virtual ~CommentHolder() {}
+  virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0;
+  virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0;
+  virtual std::vector<grpc::string> GetAllComments() const = 0;
+};
 
-    virtual grpc::string name() const = 0;
+// An abstract interface representing a method.
+struct Method : public CommentHolder {
+  virtual ~Method() {}
 
-    virtual grpc::string input_type_name() const = 0;
-    virtual grpc::string output_type_name() const = 0;
-    virtual grpc::string input_name() const = 0;
-    virtual grpc::string output_name() const = 0;
+  virtual grpc::string name() const = 0;
 
-    virtual bool NoStreaming() const = 0;
-    virtual bool ClientOnlyStreaming() const = 0;
-    virtual bool ServerOnlyStreaming() const = 0;
-    virtual bool BidiStreaming() const = 0;
-  };
+  virtual grpc::string input_type_name() const = 0;
+  virtual grpc::string output_type_name() const = 0;
 
-  // An abstract interface representing a service.
-  struct Service {
-    virtual ~Service() {}
+  virtual bool get_module_and_message_path_input(
+      grpc::string *str, grpc::string generator_file_name,
+      bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
+  virtual bool get_module_and_message_path_output(
+      grpc::string *str, grpc::string generator_file_name,
+      bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0;
 
-    virtual grpc::string name() const = 0;
+  virtual grpc::string get_input_type_name() const = 0;
+  virtual grpc::string get_output_type_name() const = 0;
+  virtual bool NoStreaming() const = 0;
+  virtual bool ClientStreaming() const = 0;
+  virtual bool ServerStreaming() const = 0;
+  virtual bool BidiStreaming() const = 0;
+};
 
-    virtual int method_count() const = 0;
-    virtual std::unique_ptr<const Method> method(int i) const = 0;
-  };
+// An abstract interface representing a service.
+struct Service : public CommentHolder {
+  virtual ~Service() {}
 
-  struct Printer {
-    virtual ~Printer() {}
+  virtual grpc::string name() const = 0;
 
-    virtual void Print(const std::map<grpc::string, grpc::string> &vars,
-                       const char *template_string) = 0;
-    virtual void Print(const char *string) = 0;
-    virtual void Indent() = 0;
-    virtual void Outdent() = 0;
-  };
+  virtual int method_count() const = 0;
+  virtual std::unique_ptr<const Method> method(int i) const = 0;
+};
 
-  // An interface that allows the source generated to be output using various
-  // libraries/idls/serializers.
-  struct File {
-    virtual ~File() {}
+struct Printer {
+  virtual ~Printer() {}
 
-    virtual grpc::string filename() const = 0;
-    virtual grpc::string filename_without_ext() const = 0;
-    virtual grpc::string message_header_ext() const = 0;
-    virtual grpc::string service_header_ext() const = 0;
-    virtual grpc::string package() const = 0;
-    virtual std::vector<grpc::string> package_parts() const = 0;
-    virtual grpc::string additional_headers() const = 0;
-    virtual grpc::string additional_imports() const = 0;
+  virtual void Print(const std::map<grpc::string, grpc::string> &vars,
+                     const char *template_string) = 0;
+  virtual void Print(const char *string) = 0;
+  virtual void Indent() = 0;
+  virtual void Outdent() = 0;
+};
 
-    virtual int service_count() const = 0;
-    virtual std::unique_ptr<const Service> service(int i) const = 0;
+// An interface that allows the source generated to be output using various
+// libraries/idls/serializers.
+struct File : public CommentHolder {
+  virtual ~File() {}
 
-    virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
-  };
-} // namespace grpc_generator
+  virtual grpc::string filename() const = 0;
+  virtual grpc::string filename_without_ext() const = 0;
+  virtual grpc::string package() const = 0;
+  virtual std::vector<grpc::string> package_parts() const = 0;
+  virtual grpc::string additional_headers() const = 0;
+
+  virtual int service_count() const = 0;
+  virtual std::unique_ptr<const Service> service(int i) const = 0;
+
+  virtual std::unique_ptr<Printer> CreatePrinter(grpc::string *str) const = 0;
+};
+}  // namespace grpc_generator
 
 #endif  // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H
diff --git a/grpc/tests/grpctest.cpp b/grpc/tests/grpctest.cpp
index 77b79fc..83b288a 100644
--- a/grpc/tests/grpctest.cpp
+++ b/grpc/tests/grpctest.cpp
@@ -27,31 +27,41 @@
 // code. It implements all rpcs specified in the FlatBuffers schema.
 class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
   virtual ::grpc::Status Store(::grpc::ServerContext* context,
-                               const flatbuffers::BufferRef<Monster> *request,
-                               flatbuffers::BufferRef<Stat> *response)
+                               const flatbuffers::grpc::Message<Monster> *request,
+                               flatbuffers::grpc::Message<Stat> *response)
                                override {
     // Create a response from the incoming request name.
     fbb_.Clear();
     auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
                                         request->GetRoot()->name()->str()));
     fbb_.Finish(stat_offset);
-    // Since we keep reusing the same FlatBufferBuilder, the memory it owns
-    // remains valid until the next call (this BufferRef doesn't own the
-    // memory it points to).
-    *response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
-                                             fbb_.GetSize());
+    // Transfer ownership of the message to gRPC
+    *response = fbb_.ReleaseMessage<Stat>();
     return grpc::Status::OK;
   }
   virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
-                                  const flatbuffers::BufferRef<Stat> *request,
-                                   ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer)
-                                  override {
-    assert(false);  // We're not actually using this RPC.
-    return grpc::Status::CANCELLED;
+                               const flatbuffers::grpc::Message<Stat> *request,
+                               ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer)
+                               override {
+
+    for (int i=0; i<10; i++) {
+       fbb_.Clear();
+       // Create 10 monsters for resposne.
+       auto monster_offset =
+       CreateMonster(fbb_, 0, 0, 0, fbb_.CreateString(
+         request->GetRoot()->id()->str() + " No." + std::to_string(i)));
+       fbb_.Finish(monster_offset);
+
+       flatbuffers::grpc::Message<Monster> monster = fbb_.ReleaseMessage<Monster>();
+
+       // Send monster to client using streaming.
+       writer->Write(monster);
+     }
+     return grpc::Status::OK;
   }
 
  private:
-  flatbuffers::FlatBufferBuilder fbb_;
+  flatbuffers::grpc::MessageBuilder fbb_;
 };
 
 // Track the server instance, so we can terminate it later.
@@ -93,25 +103,55 @@
                                      grpc::InsecureChannelCredentials());
   auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
 
-  grpc::ClientContext context;
 
-  // Build a request with the name set.
-  flatbuffers::FlatBufferBuilder fbb;
-  auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
-  fbb.Finish(monster_offset);
-  auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
-                                                 fbb.GetSize());
-  flatbuffers::BufferRef<Stat> response;
+  flatbuffers::grpc::MessageBuilder fbb;
+  {
+    grpc::ClientContext context;
+    // Build a request with the name set.
+    auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
+    fbb.Finish(monster_offset);
+    auto request = fbb.ReleaseMessage<Monster>();
+    flatbuffers::grpc::Message<Stat> response;
 
-  // The actual RPC.
-  auto status = stub->Store(&context, request, &response);
+    // The actual RPC.
+    auto status = stub->Store(&context, request, &response);
 
-  if (status.ok()) {
-    auto resp = response.GetRoot()->id();
-    std::cout << "RPC response: " << resp->str() << std::endl;
-  } else {
-    std::cout << "RPC failed" << std::endl;
+    if (status.ok()) {
+      auto resp = response.GetRoot()->id();
+      std::cout << "RPC response: " << resp->str() << std::endl;
+    } else {
+      std::cout << "RPC failed" << std::endl;
+    }
   }
+  {
+    grpc::ClientContext context;
+    fbb.Clear();
+    auto stat_offset = CreateStat(fbb, fbb.CreateString("Fred"));
+    fbb.Finish(stat_offset);
+    auto request = fbb.ReleaseMessage<Stat>();
+
+    flatbuffers::grpc::Message<Monster> response;
+    auto stream = stub->Retrieve(&context, request);
+    while (stream->Read(&response)) {
+      auto resp = response.GetRoot()->name();
+      std::cout << "RPC Streaming response: " << resp->str() << std::endl;
+    }
+  }
+
+  #if !FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
+  {
+    // Test that an invalid request errors out correctly
+    grpc::ClientContext context;
+    flatbuffers::grpc::Message<Monster> request;  // simulate invalid message
+    flatbuffers::grpc::Message<Stat> response;
+    auto status = stub->Store(&context, request, &response);
+    // The rpc status should be INTERNAL to indicate a verification error. This
+    // matches the protobuf gRPC status code for an unparseable message.
+    assert(!status.ok());
+    assert(status.error_code() == ::grpc::StatusCode::INTERNAL);
+    assert(strcmp(status.error_message().c_str(), "Message verification failed") == 0);
+  }
+  #endif
 
   server_instance->Shutdown();
 
@@ -121,4 +161,3 @@
 
   return 0;
 }
-
diff --git a/include/flatbuffers/base.h b/include/flatbuffers/base.h
new file mode 100644
index 0000000..2f03e42
--- /dev/null
+++ b/include/flatbuffers/base.h
@@ -0,0 +1,233 @@
+#ifndef FLATBUFFERS_BASE_H_
+#define FLATBUFFERS_BASE_H_
+
+#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
+    defined(_MSC_VER) && defined(_DEBUG)
+  #define _CRTDBG_MAP_ALLOC
+#endif
+
+#include <assert.h>
+
+#ifndef ARDUINO
+#include <cstdint>
+#endif
+
+#include <cstddef>
+#include <cstdlib>
+#include <cstring>
+
+#if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
+    defined(_MSC_VER) && defined(_DEBUG)
+  #include <crtdbg.h>
+  #define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
+  #define new DEBUG_NEW
+#endif
+
+#if defined(ARDUINO) && !defined(ARDUINOSTL_M_H)
+  #include <utility.h>
+#else
+  #include <utility>
+#endif
+
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <set>
+#include <algorithm>
+#include <iterator>
+#include <memory>
+
+#ifdef _STLPORT_VERSION
+  #define FLATBUFFERS_CPP98_STL
+#endif
+#ifndef FLATBUFFERS_CPP98_STL
+  #include <functional>
+#endif
+
+#include "flatbuffers/stl_emulation.h"
+
+/// @cond FLATBUFFERS_INTERNAL
+#if __cplusplus <= 199711L && \
+    (!defined(_MSC_VER) || _MSC_VER < 1600) && \
+    (!defined(__GNUC__) || \
+      (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
+  #error A C++11 compatible compiler with support for the auto typing is \
+         required for FlatBuffers.
+  #error __cplusplus _MSC_VER __GNUC__  __GNUC_MINOR__  __GNUC_PATCHLEVEL__
+#endif
+
+#if !defined(__clang__) && \
+    defined(__GNUC__) && \
+    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
+  // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
+  // and constexpr keywords. Note the __clang__ check is needed, because clang
+  // presents itself as an older GNUC compiler.
+  #ifndef nullptr_t
+    const class nullptr_t {
+    public:
+      template<class T> inline operator T*() const { return 0; }
+    private:
+      void operator&() const;
+    } nullptr = {};
+  #endif
+  #ifndef constexpr
+    #define constexpr const
+  #endif
+#endif
+
+// The wire format uses a little endian encoding (since that's efficient for
+// the common platforms).
+#if defined(__s390x__)
+  #define FLATBUFFERS_LITTLEENDIAN 0
+#endif // __s390x__
+#if !defined(FLATBUFFERS_LITTLEENDIAN)
+  #if defined(__GNUC__) || defined(__clang__)
+    #ifdef __BIG_ENDIAN__
+      #define FLATBUFFERS_LITTLEENDIAN 0
+    #else
+      #define FLATBUFFERS_LITTLEENDIAN 1
+    #endif // __BIG_ENDIAN__
+  #elif defined(_MSC_VER)
+    #if defined(_M_PPC)
+      #define FLATBUFFERS_LITTLEENDIAN 0
+    #else
+      #define FLATBUFFERS_LITTLEENDIAN 1
+    #endif
+  #else
+    #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
+  #endif
+#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
+
+#define FLATBUFFERS_VERSION_MAJOR 1
+#define FLATBUFFERS_VERSION_MINOR 8
+#define FLATBUFFERS_VERSION_REVISION 0
+#define FLATBUFFERS_STRING_EXPAND(X) #X
+#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
+
+#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
+    (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
+  #define FLATBUFFERS_FINAL_CLASS final
+  #define FLATBUFFERS_OVERRIDE override
+#else
+  #define FLATBUFFERS_FINAL_CLASS
+  #define FLATBUFFERS_OVERRIDE
+#endif
+
+#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
+    (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
+  #define FLATBUFFERS_CONSTEXPR constexpr
+#else
+  #define FLATBUFFERS_CONSTEXPR
+#endif
+
+#if defined(__GXX_EXPERIMENTAL_CXX0X__) && __GNUC__ * 10 + __GNUC_MINOR__ >= 46 || \
+    defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023026
+  #define FLATBUFFERS_NOEXCEPT noexcept
+#else
+  #define FLATBUFFERS_NOEXCEPT
+#endif
+
+// NOTE: the FLATBUFFERS_DELETE_FUNC macro may change the access mode to
+// private, so be sure to put it at the end or reset access mode explicitly.
+#if (!defined(_MSC_VER) || _MSC_FULL_VER >= 180020827) && \
+    (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 404))
+  #define FLATBUFFERS_DELETE_FUNC(func) func = delete;
+#else
+  #define FLATBUFFERS_DELETE_FUNC(func) private: func;
+#endif
+
+#if defined(_MSC_VER)
+  #pragma warning(push)
+  #pragma warning(disable: 4127) // C4127: conditional expression is constant
+#endif
+
+/// @endcond
+
+/// @file
+namespace flatbuffers {
+
+/// @cond FLATBUFFERS_INTERNAL
+// Our default offset / size type, 32bit on purpose on 64bit systems.
+// Also, using a consistent offset type maintains compatibility of serialized
+// offset values between 32bit and 64bit systems.
+typedef uint32_t uoffset_t;
+
+// Signed offsets for references that can go in both directions.
+typedef int32_t soffset_t;
+
+// Offset/index used in v-tables, can be changed to uint8_t in
+// format forks to save a bit of space if desired.
+typedef uint16_t voffset_t;
+
+typedef uintmax_t largest_scalar_t;
+
+// In 32bits, this evaluates to 2GB - 1
+#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
+
+// We support aligning the contents of buffers up to this size.
+#define FLATBUFFERS_MAX_ALIGNMENT 16
+
+template<typename T> T EndianSwap(T t) {
+  #if defined(_MSC_VER)
+    #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
+    #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
+    #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
+  #else
+    #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408 && !defined(__clang__)
+      // __builtin_bswap16 was missing prior to GCC 4.8.
+      #define FLATBUFFERS_BYTESWAP16(x) \
+        static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
+    #else
+      #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
+    #endif
+    #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
+    #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
+  #endif
+  if (sizeof(T) == 1) {   // Compile-time if-then's.
+    return t;
+  } else if (sizeof(T) == 2) {
+    union { T t; uint16_t i; } u;
+    u.t = t;
+    u.i = FLATBUFFERS_BYTESWAP16(u.i);
+    return u.t;
+  } else if (sizeof(T) == 4) {
+    union { T t; uint32_t i; } u;
+    u.t = t;
+    u.i = FLATBUFFERS_BYTESWAP32(u.i);
+    return u.t;
+  } else if (sizeof(T) == 8) {
+    union { T t; uint64_t i; } u;
+    u.t = t;
+    u.i = FLATBUFFERS_BYTESWAP64(u.i);
+    return u.t;
+  } else {
+    assert(0);
+  }
+}
+
+
+template<typename T> T EndianScalar(T t) {
+  #if FLATBUFFERS_LITTLEENDIAN
+    return t;
+  #else
+    return EndianSwap(t);
+  #endif
+}
+
+template<typename T> T ReadScalar(const void *p) {
+  return EndianScalar(*reinterpret_cast<const T *>(p));
+}
+
+template<typename T> void WriteScalar(void *p, T t) {
+  *reinterpret_cast<T *>(p) = EndianScalar(t);
+}
+
+// Computes how many bytes you'd have to pad to be able to write an
+// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
+// memory).
+inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
+  return ((~buf_size) + 1) & (scalar_size - 1);
+}
+
+}  // namespace flatbuffers
+#endif  // FLATBUFFERS_BASE_H_
diff --git a/include/flatbuffers/code_generators.h b/include/flatbuffers/code_generators.h
index 16e368e..fad0afe 100644
--- a/include/flatbuffers/code_generators.h
+++ b/include/flatbuffers/code_generators.h
@@ -95,8 +95,6 @@
 
   static const char *FlatBuffersGeneratedWarning();
 
-  bool IsEverythingGenerated() const;
-
   static std::string FullNamespace(const char *separator, const Namespace &ns);
 
   static std::string LastNamespacePart(const Namespace &ns);
@@ -114,6 +112,8 @@
 
   std::string WrapInNameSpace(const Definition &def) const;
 
+  std::string GetNameSpace(const Definition &def) const;
+
   const Parser &parser_;
   const std::string &path_;
   const std::string &file_name_;
diff --git a/include/flatbuffers/flatbuffers.h b/include/flatbuffers/flatbuffers.h
index ad42816..aa5df85 100644
--- a/include/flatbuffers/flatbuffers.h
+++ b/include/flatbuffers/flatbuffers.h
@@ -17,134 +17,17 @@
 #ifndef FLATBUFFERS_H_
 #define FLATBUFFERS_H_
 
-#include <assert.h>
+#include "flatbuffers/base.h"
 
-#include <cstdint>
-#include <cstddef>
-#include <cstdlib>
-#include <cstring>
-#include <string>
-#include <utility>
-#include <type_traits>
-#include <vector>
-#include <set>
-#include <algorithm>
-#include <memory>
-
-#ifdef _STLPORT_VERSION
-  #define FLATBUFFERS_CPP98_STL
-#endif
-#ifndef FLATBUFFERS_CPP98_STL
-  #include <functional>
-#endif
-
-/// @cond FLATBUFFERS_INTERNAL
-#if __cplusplus <= 199711L && \
-    (!defined(_MSC_VER) || _MSC_VER < 1600) && \
-    (!defined(__GNUC__) || \
-      (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
-  #error A C++11 compatible compiler with support for the auto typing is \
-         required for FlatBuffers.
-  #error __cplusplus _MSC_VER __GNUC__  __GNUC_MINOR__  __GNUC_PATCHLEVEL__
-#endif
-
-#if !defined(__clang__) && \
-    defined(__GNUC__) && \
-    (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
-  // Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
-  // and constexpr keywords. Note the __clang__ check is needed, because clang
-  // presents itself as an older GNUC compiler.
-  #ifndef nullptr_t
-    const class nullptr_t {
-    public:
-      template<class T> inline operator T*() const { return 0; }
-    private:
-      void operator&() const;
-    } nullptr = {};
-  #endif
-  #ifndef constexpr
-    #define constexpr const
-  #endif
-#endif
-
-// The wire format uses a little endian encoding (since that's efficient for
-// the common platforms).
-#if !defined(FLATBUFFERS_LITTLEENDIAN)
-  #if defined(__GNUC__) || defined(__clang__)
-    #ifdef __BIG_ENDIAN__
-      #define FLATBUFFERS_LITTLEENDIAN 0
-    #else
-      #define FLATBUFFERS_LITTLEENDIAN 1
-    #endif // __BIG_ENDIAN__
-  #elif defined(_MSC_VER)
-    #if defined(_M_PPC)
-      #define FLATBUFFERS_LITTLEENDIAN 0
-    #else
-      #define FLATBUFFERS_LITTLEENDIAN 1
-    #endif
-  #else
-    #error Unable to determine endianness, define FLATBUFFERS_LITTLEENDIAN.
-  #endif
-#endif // !defined(FLATBUFFERS_LITTLEENDIAN)
-
-#define FLATBUFFERS_VERSION_MAJOR 1
-#define FLATBUFFERS_VERSION_MINOR 6
-#define FLATBUFFERS_VERSION_REVISION 0
-#define FLATBUFFERS_STRING_EXPAND(X) #X
-#define FLATBUFFERS_STRING(X) FLATBUFFERS_STRING_EXPAND(X)
-
-#if (!defined(_MSC_VER) || _MSC_VER > 1600) && \
-    (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 407))
-  #define FLATBUFFERS_FINAL_CLASS final
-#else
-  #define FLATBUFFERS_FINAL_CLASS
-#endif
-
-#if (!defined(_MSC_VER) || _MSC_VER >= 1900) && \
-    (!defined(__GNUC__) || (__GNUC__ * 100 + __GNUC_MINOR__ >= 406))
-  #define FLATBUFFERS_CONSTEXPR constexpr
-#else
-  #define FLATBUFFERS_CONSTEXPR
-#endif
-
-/// @endcond
-
-/// @file
 namespace flatbuffers {
-
-/// @cond FLATBUFFERS_INTERNAL
-// Our default offset / size type, 32bit on purpose on 64bit systems.
-// Also, using a consistent offset type maintains compatibility of serialized
-// offset values between 32bit and 64bit systems.
-typedef uint32_t uoffset_t;
-
-// Signed offsets for references that can go in both directions.
-typedef int32_t soffset_t;
-
-// Offset/index used in v-tables, can be changed to uint8_t in
-// format forks to save a bit of space if desired.
-typedef uint16_t voffset_t;
-
-typedef uintmax_t largest_scalar_t;
-
-// In 32bits, this evaluates to 2GB - 1
-#define FLATBUFFERS_MAX_BUFFER_SIZE ((1ULL << (sizeof(soffset_t) * 8 - 1)) - 1)
-
-// We support aligning the contents of buffers up to this size.
-#define FLATBUFFERS_MAX_ALIGNMENT 16
-
-#ifndef FLATBUFFERS_CPP98_STL
-// Pointer to relinquished memory.
-typedef std::unique_ptr<uint8_t, std::function<void(uint8_t * /* unused */)>>
-          unique_ptr_t;
-#endif
-
 // Wrapper for uoffset_t to allow safe template specialization.
+// Value is allowed to be 0 to indicate a null object (see e.g. AddOffset).
 template<typename T> struct Offset {
   uoffset_t o;
   Offset() : o(0) {}
   Offset(uoffset_t _o) : o(_o) {}
   Offset<void> Union() const { return Offset<void>(o); }
+  bool IsNull() const { return !o; }
 };
 
 inline void EndianCheck() {
@@ -154,55 +37,7 @@
   (void)endiantest;
 }
 
-template<typename T> T EndianSwap(T t) {
-  #if defined(_MSC_VER)
-    #define FLATBUFFERS_BYTESWAP16 _byteswap_ushort
-    #define FLATBUFFERS_BYTESWAP32 _byteswap_ulong
-    #define FLATBUFFERS_BYTESWAP64 _byteswap_uint64
-  #else
-    #if defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ < 408
-      // __builtin_bswap16 was missing prior to GCC 4.8.
-      #define FLATBUFFERS_BYTESWAP16(x) \
-        static_cast<uint16_t>(__builtin_bswap32(static_cast<uint32_t>(x) << 16))
-    #else
-      #define FLATBUFFERS_BYTESWAP16 __builtin_bswap16
-    #endif
-    #define FLATBUFFERS_BYTESWAP32 __builtin_bswap32
-    #define FLATBUFFERS_BYTESWAP64 __builtin_bswap64
-  #endif
-  if (sizeof(T) == 1) {   // Compile-time if-then's.
-    return t;
-  } else if (sizeof(T) == 2) {
-    auto r = FLATBUFFERS_BYTESWAP16(*reinterpret_cast<uint16_t *>(&t));
-    return *reinterpret_cast<T *>(&r);
-  } else if (sizeof(T) == 4) {
-    auto r = FLATBUFFERS_BYTESWAP32(*reinterpret_cast<uint32_t *>(&t));
-    return *reinterpret_cast<T *>(&r);
-  } else if (sizeof(T) == 8) {
-    auto r = FLATBUFFERS_BYTESWAP64(*reinterpret_cast<uint64_t *>(&t));
-    return *reinterpret_cast<T *>(&r);
-  } else {
-    assert(0);
-  }
-}
-
-template<typename T> T EndianScalar(T t) {
-  #if FLATBUFFERS_LITTLEENDIAN
-    return t;
-  #else
-    return EndianSwap(t);
-  #endif
-}
-
-template<typename T> T ReadScalar(const void *p) {
-  return EndianScalar(*reinterpret_cast<const T *>(p));
-}
-
-template<typename T> void WriteScalar(void *p, T t) {
-  *reinterpret_cast<T *>(p) = EndianScalar(t);
-}
-
-template<typename T> size_t AlignOf() {
+template<typename T> FLATBUFFERS_CONSTEXPR size_t AlignOf() {
   #ifdef _MSC_VER
     return __alignof(T);
   #else
@@ -251,18 +86,16 @@
 // An STL compatible iterator implementation for Vector below, effectively
 // calling Get() for every element.
 template<typename T, typename IT>
-struct VectorIterator
-    : public std::iterator<std::random_access_iterator_tag, IT, uoffset_t> {
+struct VectorIterator {
+  typedef std::random_access_iterator_tag iterator_category;
+  typedef IT value_type;
+  typedef uoffset_t difference_type;
+  typedef IT *pointer;
+  typedef IT &reference;
 
-  typedef std::iterator<std::random_access_iterator_tag, IT, uoffset_t> super_type;
-
-public:
   VectorIterator(const uint8_t *data, uoffset_t i) :
       data_(data + IndirectHelper<T>::element_stride * i) {}
   VectorIterator(const VectorIterator &other) : data_(other.data_) {}
-  #ifndef FLATBUFFERS_CPP98_STL
-  VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {}
-  #endif
 
   VectorIterator &operator=(const VectorIterator &other) {
     data_ = other.data_;
@@ -278,6 +111,10 @@
     return data_ == other.data_;
   }
 
+  bool operator<(const VectorIterator &other) const {
+    return data_ < other.data_;
+  }
+
   bool operator!=(const VectorIterator &other) const {
     return data_ != other.data_;
   }
@@ -286,11 +123,11 @@
     return (data_ - other.data_) / IndirectHelper<T>::element_stride;
   }
 
-  typename super_type::value_type operator *() const {
+  IT operator *() const {
     return IndirectHelper<T>::Read(data_, 0);
   }
 
-  typename super_type::value_type operator->() const {
+  IT operator->() const {
     return IndirectHelper<T>::Read(data_, 0);
   }
 
@@ -305,7 +142,7 @@
     return temp;
   }
 
-  VectorIterator operator+(const uoffset_t &offset) {
+  VectorIterator operator+(const uoffset_t &offset) const {
     return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, 0);
   }
 
@@ -338,6 +175,8 @@
   const uint8_t *data_;
 };
 
+struct String;
+
 // This is used as a helper type for accessing vectors.
 // Vector::data() assumes the vector elements start after the length field.
 template<typename T> class Vector {
@@ -369,6 +208,18 @@
     return static_cast<E>(Get(i));
   }
 
+  // If this a vector of unions, this does the cast for you. There's no check
+  // to make sure this is the right type!
+  template<typename U> const U *GetAs(uoffset_t i) const {
+    return reinterpret_cast<const U *>(Get(i));
+  }
+
+  // If this a vector of unions, this does the cast for you. There's no check
+  // to make sure this is actually a string!
+  const String *GetAsString(uoffset_t i) const {
+    return reinterpret_cast<const String *>(Get(i));
+  }
+
   const void *GetStructFromOffset(size_t o) const {
     return reinterpret_cast<const void *>(Data() + o);
   }
@@ -436,6 +287,10 @@
   uoffset_t length_;
 
 private:
+  // This class is a pointer. Copying will therefore create an invalid object.
+  // Private and unimplemented copy constructor.
+  Vector(const Vector&);
+
   template<typename K> static int KeyCompare(const void *ap, const void *bp) {
     const K *key = reinterpret_cast<const K *>(ap);
     const uint8_t *data = reinterpret_cast<const uint8_t *>(bp);
@@ -463,8 +318,25 @@
   VectorOfAny();
 
   uoffset_t length_;
+
+private:
+  VectorOfAny(const VectorOfAny&);
 };
 
+#ifndef FLATBUFFERS_CPP98_STL
+template<typename T, typename U>
+Vector<Offset<T>> *VectorCast(Vector<Offset<U>> *ptr) {
+  static_assert(std::is_base_of<T, U>::value, "Unrelated types");
+  return reinterpret_cast<Vector<Offset<T>> *>(ptr);
+}
+
+template<typename T, typename U>
+const Vector<Offset<T>> *VectorCast(const Vector<Offset<U>> *ptr) {
+  static_assert(std::is_base_of<T, U>::value, "Unrelated types");
+  return reinterpret_cast<const Vector<Offset<T>> *>(ptr);
+}
+#endif
+
 // Convenient helper function to get the length of any vector, regardless
 // of wether it is null or not (the field is not set).
 template<typename T> static inline size_t VectorLength(const Vector<T> *v) {
@@ -480,13 +352,152 @@
   }
 };
 
-// Simple indirection for buffer allocation, to allow this to be overridden
-// with custom allocation (see the FlatBufferBuilder constructor).
-class simple_allocator {
+// Allocator interface. This is flatbuffers-specific and meant only for
+// `vector_downward` usage.
+class Allocator {
  public:
-  virtual ~simple_allocator() {}
-  virtual uint8_t *allocate(size_t size) const { return new uint8_t[size]; }
-  virtual void deallocate(uint8_t *p) const { delete[] p; }
+  virtual ~Allocator() {}
+
+  // Allocate `size` bytes of memory.
+  virtual uint8_t *allocate(size_t size) = 0;
+
+  // Deallocate `size` bytes of memory at `p` allocated by this allocator.
+  virtual void deallocate(uint8_t *p, size_t size) = 0;
+
+  // Reallocate `new_size` bytes of memory, replacing the old region of size
+  // `old_size` at `p`. In contrast to a normal realloc, this grows downwards,
+  // and is intended specifcally for `vector_downward` use.
+  virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
+                                       size_t new_size) {
+    assert(new_size > old_size);  // vector_downward only grows
+    uint8_t *new_p = allocate(new_size);
+    memcpy(new_p + (new_size - old_size), old_p, old_size);
+    deallocate(old_p, old_size);
+    return new_p;
+  }
+};
+
+// DefaultAllocator uses new/delete to allocate memory regions
+class DefaultAllocator : public Allocator {
+ public:
+  virtual uint8_t *allocate(size_t size) FLATBUFFERS_OVERRIDE {
+    return new uint8_t[size];
+  }
+
+  virtual void deallocate(uint8_t *p, size_t) FLATBUFFERS_OVERRIDE {
+    delete[] p;
+  }
+
+  static DefaultAllocator &instance() {
+    static DefaultAllocator inst;
+    return inst;
+  }
+};
+
+// DetachedBuffer is a finished flatbuffer memory region, detached from its
+// builder. The original memory region and allocator are also stored so that
+// the DetachedBuffer can manage the memory lifetime.
+class DetachedBuffer {
+ public:
+  DetachedBuffer() : allocator_(nullptr), own_allocator_(false), buf_(nullptr),
+                     reserved_(0), cur_(nullptr), size_(0) {}
+
+  DetachedBuffer(Allocator *allocator, bool own_allocator, uint8_t *buf,
+                 size_t reserved, uint8_t *cur, size_t sz)
+    : allocator_(allocator), own_allocator_(own_allocator), buf_(buf),
+      reserved_(reserved), cur_(cur), size_(sz) {
+    assert(allocator_);
+  }
+
+  DetachedBuffer(DetachedBuffer &&other)
+    : allocator_(other.allocator_), own_allocator_(other.own_allocator_),
+      buf_(other.buf_), reserved_(other.reserved_), cur_(other.cur_),
+      size_(other.size_) {
+    other.reset();  
+  }
+
+  DetachedBuffer &operator=(DetachedBuffer &&other) {
+    destroy();
+
+    allocator_ = other.allocator_;
+    own_allocator_ = other.own_allocator_;
+    buf_ = other.buf_;
+    reserved_ = other.reserved_;
+    cur_ = other.cur_;
+    size_ = other.size_;
+
+    other.reset();
+
+    return *this;
+  }
+
+  ~DetachedBuffer() {
+    destroy();
+  }
+
+  const uint8_t *data() const {
+    return cur_;
+  }
+
+  uint8_t *data() {
+    return cur_;
+  }
+
+  size_t size() const {
+    return size_;
+  }
+
+#if 0  // disabled for now due to the ordering of classes in this header
+  template <class T>
+  bool Verify() const {
+    Verifier verifier(data(), size());
+    return verifier.Verify<T>(nullptr);
+  }
+
+  template <class T>
+  const T* GetRoot() const {
+    return flatbuffers::GetRoot<T>(data());
+  }
+
+  template <class T>
+  T* GetRoot() {
+    return flatbuffers::GetRoot<T>(data());
+  }
+#endif
+
+  // These may change access mode, leave these at end of public section
+  FLATBUFFERS_DELETE_FUNC(DetachedBuffer(const DetachedBuffer &other))
+  FLATBUFFERS_DELETE_FUNC(
+      DetachedBuffer &operator=(const DetachedBuffer &other))
+
+ protected:
+  Allocator *allocator_;
+  bool own_allocator_;
+  uint8_t *buf_;
+  size_t reserved_;
+  uint8_t *cur_;
+  size_t size_;
+
+  inline void destroy() {
+    if (buf_) {
+      assert(allocator_);
+      allocator_->deallocate(buf_, reserved_);
+    }
+    if (own_allocator_ && allocator_) {
+      delete allocator_;
+    }
+
+    reset();
+  }
+
+  inline void reset() {
+    allocator_ = nullptr;
+    own_allocator_ = false;
+    buf_ = nullptr;
+    reserved_ = 0;
+    cur_ = nullptr;
+    size_ = 0;
+  }
 };
 
 // This is a minimal replication of std::vector<uint8_t> functionality,
@@ -494,49 +505,64 @@
 // in the lowest address in the vector.
 class vector_downward {
  public:
-  explicit vector_downward(size_t initial_size,
-                           const simple_allocator &allocator)
-    : reserved_((initial_size + sizeof(largest_scalar_t) - 1) &
-        ~(sizeof(largest_scalar_t) - 1)),
-      buf_(allocator.allocate(reserved_)),
-      cur_(buf_ + reserved_),
-      allocator_(allocator) {}
+  explicit vector_downward(size_t initial_size = 1024,
+                           Allocator *allocator = nullptr,
+                           bool own_allocator = false)
+    : allocator_(allocator ? allocator : &DefaultAllocator::instance()),
+      own_allocator_(own_allocator), initial_size_(initial_size), reserved_(0),
+      buf_(nullptr), cur_(nullptr) {
+    assert(allocator_);
+  }
 
   ~vector_downward() {
-    if (buf_)
-      allocator_.deallocate(buf_);
+    if (buf_) {
+      assert(allocator_);
+      allocator_->deallocate(buf_, reserved_);
+    }
+    if (own_allocator_ && allocator_) {
+      delete allocator_;
+    }
+  }
+
+  void reset() {
+    if (buf_) {
+      assert(allocator_);
+      allocator_->deallocate(buf_, reserved_);
+    }
+    reserved_ = 0;
+    buf_ = nullptr;
+    cur_ = nullptr;
   }
 
   void clear() {
-    if (buf_ == nullptr)
-      buf_ = allocator_.allocate(reserved_);
-
-    cur_ = buf_ + reserved_;
+    if (buf_) {
+      cur_ = buf_ + reserved_;
+    } else {
+      reserved_ = 0;
+      buf_ = nullptr;
+      cur_ = nullptr;
+    }
   }
 
-  #ifndef FLATBUFFERS_CPP98_STL
   // Relinquish the pointer to the caller.
-  unique_ptr_t release() {
-    // Actually deallocate from the start of the allocated memory.
-    std::function<void(uint8_t *)> deleter(
-      std::bind(&simple_allocator::deallocate, allocator_, buf_));
-
-    // Point to the desired offset.
-    unique_ptr_t retval(data(), deleter);
-
-    // Don't deallocate when this instance is destroyed.
+  DetachedBuffer release() {
+    DetachedBuffer fb(allocator_, own_allocator_, buf_, reserved_, cur_,
+                      size());
+    allocator_ = nullptr;
+    own_allocator_ = false;
+    reserved_ = 0;
     buf_ = nullptr;
     cur_ = nullptr;
-
-    return retval;
+    return fb;
   }
-  #endif
 
   size_t growth_policy(size_t bytes) {
-    return (bytes / 2) & ~(sizeof(largest_scalar_t) - 1);
+    return (bytes == 0) ? initial_size_
+                        : ((bytes / 2) & ~(AlignOf<largest_scalar_t>() - 1));
   }
 
   uint8_t *make_space(size_t len) {
+    assert(cur_ >= buf_);
     if (len > static_cast<size_t>(cur_ - buf_)) {
       reallocate(len);
     }
@@ -547,13 +573,23 @@
     return cur_;
   }
 
+  Allocator &get_allocator() { return *allocator_; }
+
   uoffset_t size() const {
-    assert(cur_ != nullptr && buf_ != nullptr);
     return static_cast<uoffset_t>(reserved_ - (cur_ - buf_));
   }
 
+  size_t capacity() const {
+    return reserved_;
+  }
+
+  uint8_t *buf() const {
+    assert(buf_);
+    return buf_;
+  }
+
   uint8_t *data() const {
-    assert(cur_ != nullptr);
+    assert(cur_);
     return cur_;
   }
 
@@ -565,7 +601,7 @@
   }
 
   // Specialized version of push() that avoids memcpy call for small data.
-  template<typename T> void push_small(T little_endian_t) {
+  template<typename T> void push_small(const T& little_endian_t) {
     auto dest = make_space(sizeof(T));
     *reinterpret_cast<T *>(dest) = little_endian_t;
   }
@@ -587,26 +623,29 @@
 
  private:
   // You shouldn't really be copying instances of this class.
-  vector_downward(const vector_downward &);
-  vector_downward &operator=(const vector_downward &);
+  FLATBUFFERS_DELETE_FUNC(vector_downward(const vector_downward &))
+  FLATBUFFERS_DELETE_FUNC(vector_downward &operator=(const vector_downward &))
 
+  Allocator *allocator_;
+  bool own_allocator_;
+  size_t initial_size_;
   size_t reserved_;
   uint8_t *buf_;
   uint8_t *cur_;  // Points at location between empty (below) and used (above).
-  const simple_allocator &allocator_;
 
   void reallocate(size_t len) {
+    assert(allocator_);
+    auto old_reserved = reserved_;
     auto old_size = size();
-    auto largest_align = AlignOf<largest_scalar_t>();
-    reserved_ += (std::max)(len, growth_policy(reserved_));
-    // Round up to avoid undefined behavior from unaligned loads and stores.
-    reserved_ = (reserved_ + (largest_align - 1)) & ~(largest_align - 1);
-    auto new_buf = allocator_.allocate(reserved_);
-    auto new_cur = new_buf + reserved_ - old_size;
-    memcpy(new_cur, cur_, old_size);
-    cur_ = new_cur;
-    allocator_.deallocate(buf_);
-    buf_ = new_buf;
+    reserved_ += (std::max)(len, growth_policy(old_reserved));
+    FLATBUFFERS_CONSTEXPR size_t alignment = AlignOf<largest_scalar_t>();
+    reserved_ = (reserved_ + alignment - 1) & ~(alignment - 1);
+    if (buf_) {
+      buf_ = allocator_->reallocate_downward(buf_, old_reserved, reserved_);
+    } else {
+      buf_ = allocator_->allocate(reserved_);
+    }
+    cur_ = buf_ + reserved_ - old_size;
   }
 };
 
@@ -617,17 +656,10 @@
   return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t));
 }
 
-// Computes how many bytes you'd have to pad to be able to write an
-// "scalar_size" scalar if the buffer had grown to "buf_size" (downwards in
-// memory).
-inline size_t PaddingBytes(size_t buf_size, size_t scalar_size) {
-  return ((~buf_size) + 1) & (scalar_size - 1);
-}
-
-template <typename T> const T* data(const std::vector<T> &v) {
+template <typename T, typename Alloc> const T* data(const std::vector<T, Alloc> &v) {
   return v.empty() ? nullptr : &v.front();
 }
-template <typename T> T* data(std::vector<T> &v) {
+template <typename T, typename Alloc> T* data(std::vector<T, Alloc> &v) {
   return v.empty() ? nullptr : &v.front();
 }
 
@@ -643,22 +675,21 @@
 /// `CreateVector` functions. Do this is depth-first order to build up a tree to
 /// the root. `Finish()` wraps up the buffer ready for transport.
 class FlatBufferBuilder
-/// @cond FLATBUFFERS_INTERNAL
-FLATBUFFERS_FINAL_CLASS
-/// @endcond
 {
  public:
   /// @brief Default constructor for FlatBufferBuilder.
   /// @param[in] initial_size The initial size of the buffer, in bytes. Defaults
-  /// to`1024`.
-  /// @param[in] allocator A pointer to the `simple_allocator` that should be
-  /// used. Defaults to `nullptr`, which means the `default_allocator` will be
-  /// be used.
-  explicit FlatBufferBuilder(uoffset_t initial_size = 1024,
-                             const simple_allocator *allocator = nullptr)
-      : buf_(initial_size, allocator ? *allocator : default_allocator),
-        nested(false), finished(false), minalign_(1), force_defaults_(false),
-        dedup_vtables_(true), string_pool(nullptr) {
+  /// to `1024`.
+  /// @param[in] allocator An `Allocator` to use. Defaults to a new instance of
+  /// a `DefaultAllocator`.
+  /// @param[in] own_allocator Whether the builder/vector should own the
+  /// allocator. Defaults to / `false`.
+  explicit FlatBufferBuilder(size_t initial_size = 1024,
+                             Allocator *allocator = nullptr,
+                             bool own_allocator = false)
+    : buf_(initial_size, allocator, own_allocator), max_voffset_(0),
+      nested(false), finished(false), minalign_(1), force_defaults_(false),
+      dedup_vtables_(true), string_pool(nullptr) {
     offsetbuf_.reserve(16);  // Avoid first few reallocs.
     vtables_.reserve(16);
     EndianCheck();
@@ -668,11 +699,16 @@
     if (string_pool) delete string_pool;
   }
 
+  void Reset() {
+    Clear();  // clear builder state
+    buf_.reset();  // deallocate buffer
+  }
+
   /// @brief Reset all the state in this FlatBufferBuilder so it can be reused
   /// to construct another buffer.
   void Clear() {
     buf_.clear();
-    offsetbuf_.clear();
+    ClearOffsets();
     nested = false;
     finished = false;
     vtables_.clear();
@@ -696,18 +732,22 @@
   /// @return Returns a `uint8_t` pointer to the unfinished buffer.
   uint8_t *GetCurrentBufferPointer() const { return buf_.data(); }
 
-  #ifndef FLATBUFFERS_CPP98_STL
   /// @brief Get the released pointer to the serialized buffer.
   /// @warning Do NOT attempt to use this FlatBufferBuilder afterwards!
-  /// @return The `unique_ptr` returned has a special allocator that knows how
-  /// to deallocate this pointer (since it points to the middle of an
-  /// allocation). Thus, do not mix this pointer with other `unique_ptr`'s, or
-  /// call `release()`/`reset()` on it.
-  unique_ptr_t ReleaseBufferPointer() {
+  /// @return A `FlatBuffer` that owns the buffer and its allocator and
+  /// behaves similar to a `unique_ptr` with a deleter.
+  /// Deprecated: use Release() instead
+  DetachedBuffer ReleaseBufferPointer() {
     Finished();
     return buf_.release();
   }
-  #endif
+
+  /// @brief Get the released DetachedBuffer.
+  /// @return A `DetachedBuffer` that owns the buffer and its allocator.
+  DetachedBuffer Release() {
+    Finished();
+    return buf_.release();
+  }
 
   /// @brief get the minimum alignment this buffer needs to be accessed
   /// properly. This is only known once all elements have been written (after
@@ -759,13 +799,8 @@
   void PopBytes(size_t amount) { buf_.pop(amount); }
 
   template<typename T> void AssertScalarT() {
-    #ifndef FLATBUFFERS_CPP98_STL
     // The code assumes power of 2 sizes and endian-swap-ability.
-    static_assert(std::is_scalar<T>::value
-        // The Offset<T> type is essentially a scalar but fails is_scalar.
-        || sizeof(T) == sizeof(Offset<void>),
-           "T must be a scalar type");
-    #endif
+    static_assert(flatbuffers::is_scalar<T>::value, "T must be a scalar type");
   }
 
   // Write a single aligned scalar to the buffer
@@ -787,6 +822,7 @@
   void TrackField(voffset_t field, uoffset_t off) {
     FieldLoc fl = { off, field };
     offsetbuf_.push_back(fl);
+    max_voffset_ = (std::max)(max_voffset_, field);
   }
 
   // Like PushElement, but additionally tracks the field this represents.
@@ -798,7 +834,7 @@
   }
 
   template<typename T> void AddOffset(voffset_t field, Offset<T> off) {
-    if (!off.o) return;  // An offset of 0 means NULL, don't store.
+    if (off.IsNull()) return;  // Don't store.
     AddElement(field, ReferTo(off.o), static_cast<uoffset_t>(0));
   }
 
@@ -847,7 +883,7 @@
   // This finishes one serialized object by generating the vtable if it's a
   // table, comparing it against existing vtables, and writing the
   // resulting vtable offset.
-  uoffset_t EndTable(uoffset_t start, voffset_t numfields) {
+  uoffset_t EndTable(uoffset_t start) {
     // If you get this assert, a corresponding StartTable wasn't called.
     assert(nested);
     // Write the vtable offset, which is the start of any Table.
@@ -856,11 +892,17 @@
     // Write a vtable, which consists entirely of voffset_t elements.
     // It starts with the number of offsets, followed by a type id, followed
     // by the offsets themselves. In reverse:
-    buf_.fill_big(numfields * sizeof(voffset_t));
+    // Include space for the last offset and ensure empty tables have a
+    // minimum size.
+    max_voffset_ = (std::max)(static_cast<voffset_t>(max_voffset_ +
+                                                     sizeof(voffset_t)),
+                              FieldIndexToOffset(0));
+    buf_.fill_big(max_voffset_);
     auto table_object_size = vtableoffsetloc - start;
     assert(table_object_size < 0x10000);  // Vtable use 16bit offsets.
-    PushElement<voffset_t>(static_cast<voffset_t>(table_object_size));
-    PushElement<voffset_t>(FieldIndexToOffset(numfields));
+    WriteScalar<voffset_t>(buf_.data() + sizeof(voffset_t),
+                           static_cast<voffset_t>(table_object_size));
+    WriteScalar<voffset_t>(buf_.data(), max_voffset_);
     // Write the offsets into the table
     for (auto field_location = offsetbuf_.begin();
               field_location != offsetbuf_.end();
@@ -870,7 +912,7 @@
       assert(!ReadScalar<voffset_t>(buf_.data() + field_location->id));
       WriteScalar<voffset_t>(buf_.data() + field_location->id, pos);
     }
-    offsetbuf_.clear();
+    ClearOffsets();
     auto vt1 = reinterpret_cast<voffset_t *>(buf_.data());
     auto vt1_size = ReadScalar<voffset_t>(vt1);
     auto vt_use = GetSize();
@@ -903,6 +945,11 @@
     return vtableoffsetloc;
   }
 
+  // DEPRECATED: call the version above instead.
+  uoffset_t EndTable(uoffset_t start, voffset_t /*numfields*/) {
+    return EndTable(start);
+  }
+
   // This checks a required field has been set in a given table that has
   // just been constructed.
   template<typename T> void Required(Offset<T> table, voffset_t field) {
@@ -921,7 +968,10 @@
 
   uoffset_t EndStruct() { return GetSize(); }
 
-  void ClearOffsets() { offsetbuf_.clear(); }
+  void ClearOffsets() {
+    offsetbuf_.clear();
+    max_voffset_ = 0;
+  }
 
   // Aligns such that when "len" bytes are written, an object can be written
   // after it with "alignment" without padding.
@@ -969,6 +1019,15 @@
   }
 
   /// @brief Store a string in the buffer, which can contain any binary data.
+  /// @param[in] str A const reference to a std::string like type with support
+  /// of T::c_str() and T::length() to store in the buffer.
+  /// @return Returns the offset in the buffer where the string starts.
+  template<typename T>
+    Offset<String> CreateString(const T &str) {
+    return CreateString(str.c_str(), str.length());
+  }
+
+  /// @brief Store a string in the buffer, which can contain any binary data.
   /// If a string with this exact contents has already been serialized before,
   /// instead simply returns the offset of the existing string.
   /// @param[in] str A const char pointer to the data to be stored as a string.
@@ -1056,11 +1115,30 @@
   /// @return Returns a typed `Offset` into the serialized data indicating
   /// where the vector is stored.
   template<typename T> Offset<Vector<T>> CreateVector(const T *v, size_t len) {
+    // If this assert hits, you're specifying a template argument that is
+    // causing the wrong overload to be selected, remove it.
+    AssertScalarT<T>();
     StartVector(len, sizeof(T));
+    #if FLATBUFFERS_LITTLEENDIAN
+      PushBytes(reinterpret_cast<const uint8_t *>(v), len * sizeof(T));
+    #else
+      if (sizeof(T) == 1) {
+        PushBytes(reinterpret_cast<const uint8_t *>(v), len);
+      } else {
+        for (auto i = len; i > 0; ) {
+          PushElement(v[--i]);
+        }
+      }
+    #endif
+    return Offset<Vector<T>>(EndVector(len));
+  }
+
+  template<typename T> Offset<Vector<Offset<T>>> CreateVector(const Offset<T> *v, size_t len) {
+    StartVector(len, sizeof(Offset<T>));
     for (auto i = len; i > 0; ) {
       PushElement(v[--i]);
     }
-    return Offset<Vector<T>>(EndVector(len));
+    return Offset<Vector<Offset<T>>>(EndVector(len));
   }
 
   /// @brief Serialize a `std::vector` into a FlatBuffer `vector`.
@@ -1100,6 +1178,22 @@
   }
   #endif
 
+  /// @brief Serialize values returned by a function into a FlatBuffer `vector`.
+  /// This is a convenience function that takes care of iteration for you.
+  /// @tparam T The data type of the `std::vector` elements.
+  /// @param f A function that takes the current iteration 0..vector_size-1,
+  /// and the state parameter returning any type that you can construct a
+  /// FlatBuffers vector out of.
+  /// @param state State passed to f.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template <typename T, typename F, typename S> Offset<Vector<T>> CreateVector(
+      size_t vector_size, F f, S *state) {
+    std::vector<T> elems(vector_size);
+    for (size_t i = 0; i < vector_size; i++) elems[i] = f(i, state);
+    return CreateVector(elems);
+  }
+
   /// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`.
   /// This is a convenience function for a common case.
   /// @param v A const reference to the `std::vector` to serialize into the
@@ -1127,6 +1221,23 @@
     return Offset<Vector<const T *>>(EndVector(len));
   }
 
+  /// @brief Serialize an array of native structs into a FlatBuffer `vector`.
+  /// @tparam T The data type of the struct array elements.
+  /// @tparam S The data type of the native struct array elements.
+  /// @param[in] v A pointer to the array of type `S` to serialize into the
+  /// buffer as a `vector`.
+  /// @param[in] len The number of elements to serialize.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfNativeStructs(
+      const S *v, size_t len) {
+    extern T Pack(const S&);
+    typedef T (*Pack_t)(const S&);
+    std::vector<T> vv(len);
+    std::transform(v, v+len, vv.begin(), *(Pack_t)&Pack);
+    return CreateVectorOfStructs<T>(vv.data(), vv.size());
+  }
+
   #ifndef FLATBUFFERS_CPP98_STL
   /// @brief Serialize an array of structs into a FlatBuffer `vector`.
   /// @tparam T The data type of the struct array elements.
@@ -1138,27 +1249,127 @@
   /// accessors.
   template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
       size_t vector_size, const std::function<void(size_t i, T *)> &filler) {
-    StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>());
-    T *structs = reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T)));
+    T* structs = StartVectorOfStructs<T>(vector_size);
     for (size_t i = 0; i < vector_size; i++) {
       filler(i, structs);
       structs++;
     }
-    return Offset<Vector<const T *>>(EndVector(vector_size));
+    return EndVectorOfStructs<T>(vector_size);
   }
   #endif
 
+  /// @brief Serialize an array of structs into a FlatBuffer `vector`.
+  /// @tparam T The data type of the struct array elements.
+  /// @param[in] f A function that takes the current iteration 0..vector_size-1,
+  /// a pointer to the struct that must be filled and the state argument.
+  /// @param[in] state Arbitrary state to pass to f.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  /// This is mostly useful when flatbuffers are generated with mutation
+  /// accessors.
+  template <typename T, typename F, typename S> Offset<Vector<const T *>>
+      CreateVectorOfStructs(size_t vector_size, F f, S *state) {
+    T* structs = StartVectorOfStructs<T>(vector_size);
+    for (size_t i = 0; i < vector_size; i++) {
+      f(i, structs, state);
+      structs++;
+    }
+    return EndVectorOfStructs<T>(vector_size);
+  }
+
   /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`.
   /// @tparam T The data type of the `std::vector` struct elements.
   /// @param[in]] v A const reference to the `std::vector` of structs to
   /// serialize into the buffer as a `vector`.
   /// @return Returns a typed `Offset` into the serialized data indicating
   /// where the vector is stored.
-  template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
-      const std::vector<T> &v) {
+  template<typename T, typename Alloc> Offset<Vector<const T *>> CreateVectorOfStructs(
+      const std::vector<T, Alloc> &v) {
     return CreateVectorOfStructs(data(v), v.size());
   }
 
+  /// @brief Serialize a `std::vector` of native structs into a FlatBuffer `vector`.
+  /// @tparam T The data type of the `std::vector` struct elements.
+  /// @tparam S The data type of the `std::vector` native struct elements.
+  /// @param[in]] v A const reference to the `std::vector` of structs to
+  /// serialize into the buffer as a `vector`.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfNativeStructs(
+      const std::vector<S> &v) {
+    return CreateVectorOfNativeStructs<T, S>(data(v), v.size());
+  }
+
+
+  /// @cond FLATBUFFERS_INTERNAL
+  template<typename T>
+  struct StructKeyComparator {
+    bool operator()(const T &a, const T &b) const {
+      return a.KeyCompareLessThan(&b);
+    }
+
+  private:
+    StructKeyComparator& operator= (const StructKeyComparator&);
+  };
+  /// @endcond
+
+  /// @brief Serialize a `std::vector` of structs into a FlatBuffer `vector`
+  /// in sorted order.
+  /// @tparam T The data type of the `std::vector` struct elements.
+  /// @param[in]] v A const reference to the `std::vector` of structs to
+  /// serialize into the buffer as a `vector`.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T> Offset<Vector<const T *>> CreateVectorOfSortedStructs(
+      std::vector<T> *v) {
+    return CreateVectorOfSortedStructs(data(*v), v->size());
+  }
+
+  /// @brief Serialize a `std::vector` of native structs into a FlatBuffer `vector`
+  /// in sorted order.
+  /// @tparam T The data type of the `std::vector` struct elements.
+  /// @tparam S The data type of the `std::vector` native struct elements.
+  /// @param[in]] v A const reference to the `std::vector` of structs to
+  /// serialize into the buffer as a `vector`.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
+      std::vector<S> *v) {
+    return CreateVectorOfSortedNativeStructs<T, S>(data(*v), v->size());
+  }
+
+  /// @brief Serialize an array of structs into a FlatBuffer `vector` in sorted
+  /// order.
+  /// @tparam T The data type of the struct array elements.
+  /// @param[in] v A pointer to the array of type `T` to serialize into the
+  /// buffer as a `vector`.
+  /// @param[in] len The number of elements to serialize.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T> Offset<Vector<const T *>> CreateVectorOfSortedStructs(
+      T *v, size_t len) {
+    std::sort(v, v + len, StructKeyComparator<T>());
+    return CreateVectorOfStructs(v, len);
+  }
+
+  /// @brief Serialize an array of native structs into a FlatBuffer `vector` in sorted
+  /// order.
+  /// @tparam T The data type of the struct array elements.
+  /// @tparam S The data type of the native struct array elements.
+  /// @param[in] v A pointer to the array of type `S` to serialize into the
+  /// buffer as a `vector`.
+  /// @param[in] len The number of elements to serialize.
+  /// @return Returns a typed `Offset` into the serialized data indicating
+  /// where the vector is stored.
+  template<typename T, typename S> Offset<Vector<const T *>> CreateVectorOfSortedNativeStructs(
+      S *v, size_t len) {
+    extern T Pack(const S&);
+    typedef T (*Pack_t)(const S&);
+    std::vector<T> vv(len);
+    std::transform(v, v+len, vv.begin(), *(Pack_t)&Pack);
+    return CreateVectorOfSortedStructs<T>(vv, len);
+  }
+
   /// @cond FLATBUFFERS_INTERNAL
   template<typename T>
   struct TableKeyComparator {
@@ -1233,6 +1444,13 @@
                                      reinterpret_cast<uint8_t **>(buf));
   }
 
+  /// @brief Write a struct by itself, typically to be part of a union.
+  template<typename T> Offset<const T *> CreateStruct(const T &structobj) {
+    Align(AlignOf<T>());
+    buf_.push_small(structobj);
+    return Offset<const T *>(GetSize());
+  }
+
   /// @brief The length of a FlatBuffer file header.
   static const size_t kFileIdentifierLength = 4;
 
@@ -1257,7 +1475,7 @@
     Finish(root.o, file_identifier, true);
   }
 
- private:
+ protected:
   // You shouldn't really be copying instances of this class.
   FlatBufferBuilder(const FlatBufferBuilder &);
   FlatBufferBuilder &operator=(const FlatBufferBuilder &);
@@ -1286,12 +1504,13 @@
     voffset_t id;
   };
 
-  simple_allocator default_allocator;
-
   vector_downward buf_;
 
   // Accumulating offsets of table members while it is being built.
   std::vector<FieldLoc> offsetbuf_;
+  // Track how much of the vtable is in use, so we can output the most compact
+  // possible vtable.
+  voffset_t max_voffset_;
 
   // Ensure objects are not nested.
   bool nested;
@@ -1313,7 +1532,7 @@
       auto stra = reinterpret_cast<const String *>(buf_->data_at(a.o));
       auto strb = reinterpret_cast<const String *>(buf_->data_at(b.o));
       return strncmp(stra->c_str(), strb->c_str(),
-                     std::min(stra->size(), strb->size()) + 1) < 0;
+                     (std::min)(stra->size(), strb->size()) + 1) < 0;
     }
     const vector_downward *buf_;
   };
@@ -1321,6 +1540,21 @@
   // For use with CreateSharedString. Instantiated on first use only.
   typedef std::set<Offset<String>, StringOffsetCompare> StringOffsetMap;
   StringOffsetMap *string_pool;
+
+ private:
+  // Allocates space for a vector of structures.
+  // Must be completed with EndVectorOfStructs().
+  template<typename T> T* StartVectorOfStructs(size_t vector_size) {
+    StartVector(vector_size * sizeof(T) / AlignOf<T>(), AlignOf<T>());
+    return reinterpret_cast<T *>(buf_.make_space(vector_size * sizeof(T)));
+  }
+
+  // End the vector of structues in the flatbuffers.
+  // Vector should have previously be started with StartVectorOfStructs().
+  template<typename T> Offset<Vector<const T *>> EndVectorOfStructs(
+      size_t vector_size) {
+    return Offset<Vector<const T *>>(EndVector(vector_size));
+  }
 };
 /// @}
 
@@ -1354,17 +1588,29 @@
   return GetMutableTemporaryPointer<T>(fbb, offset);
 }
 
+
+/// @brief Get a pointer to the the file_identifier section of the buffer.
+/// @return Returns a const char pointer to the start of the file_identifier
+/// characters in the buffer.  The returned char * has length
+/// 'flatbuffers::FlatBufferBuilder::kFileIdentifierLength'.
+/// This function is UNDEFINED for FlatBuffers whose schema does not include
+/// a file_identifier (likely points at padding or the start of a the root
+/// vtable).
+inline const char *GetBufferIdentifier(const void *buf) {
+  return reinterpret_cast<const char *>(buf) + sizeof(uoffset_t);
+}
+
 // Helper to see if the identifier in a buffer has the expected value.
 inline bool BufferHasIdentifier(const void *buf, const char *identifier) {
-  return strncmp(reinterpret_cast<const char *>(buf) + sizeof(uoffset_t),
+  return strncmp(GetBufferIdentifier(buf),
                  identifier, FlatBufferBuilder::kFileIdentifierLength) == 0;
 }
 
 // Helper class to verify the integrity of a FlatBuffer
 class Verifier FLATBUFFERS_FINAL_CLASS {
  public:
-  Verifier(const uint8_t *buf, size_t buf_len, size_t _max_depth = 64,
-           size_t _max_tables = 1000000)
+  Verifier(const uint8_t *buf, size_t buf_len, uoffset_t _max_depth = 64,
+           uoffset_t _max_tables = 1000000)
     : buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth),
       num_tables_(0), max_tables_(_max_tables)
     #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
@@ -1473,8 +1719,9 @@
     }
 
     // Call T::Verify, which must be in the generated code for this type.
-    return Verify<uoffset_t>(start) &&
-      reinterpret_cast<const T *>(start + ReadScalar<uoffset_t>(start))->
+    auto o = VerifyOffset(start);
+    return o &&
+      reinterpret_cast<const T *>(start + o)->
         Verify(*this)
         #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
           && GetComputedSize()
@@ -1483,6 +1730,10 @@
   }
 
   // Verify this whole buffer, starting with root type T.
+  template<typename T> bool VerifyBuffer() {
+    return VerifyBuffer<T>(nullptr);
+  }
+
   template<typename T> bool VerifyBuffer(const char *identifier) {
     return VerifyBufferFromStart<T>(identifier, buf_);
   }
@@ -1493,6 +1744,13 @@
            VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t));
   }
 
+  uoffset_t VerifyOffset(const uint8_t *start) const {
+    if (!Verify<uoffset_t>(start)) return false;
+    auto o = ReadScalar<uoffset_t>(start);
+    Check(o != 0);
+    return o;
+  }
+
   // Called at the start of a table to increase counters measuring data
   // structure depth and amount, and possibly bails out with false if
   // limits set by the constructor have been hit. Needs to be balanced
@@ -1522,10 +1780,10 @@
  private:
   const uint8_t *buf_;
   const uint8_t *end_;
-  size_t depth_;
-  size_t max_depth_;
-  size_t num_tables_;
-  size_t max_tables_;
+  uoffset_t depth_;
+  uoffset_t max_depth_;
+  uoffset_t num_tables_;
+  uoffset_t max_tables_;
 #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE
   mutable const uint8_t *upper_bound_;
 #endif
@@ -1617,9 +1875,9 @@
     return field_offset ? reinterpret_cast<P>(p) : nullptr;
   }
 
-  template<typename T> bool SetField(voffset_t field, T val) {
+  template<typename T> bool SetField(voffset_t field, T val, T def) {
     auto field_offset = GetOptionalFieldOffset(field);
-    if (!field_offset) return false;
+    if (!field_offset) return val == def;
     WriteScalar(data_ + field_offset, val);
     return true;
   }
@@ -1669,12 +1927,24 @@
 
   // VerifyField for required fields.
   template<typename T> bool VerifyFieldRequired(const Verifier &verifier,
-                                        voffset_t field) const {
+                                                voffset_t field) const {
     auto field_offset = GetOptionalFieldOffset(field);
     return verifier.Check(field_offset != 0) &&
            verifier.Verify<T>(data_ + field_offset);
   }
 
+  // Versions for offsets.
+  bool VerifyOffset(const Verifier &verifier, voffset_t field) const {
+    auto field_offset = GetOptionalFieldOffset(field);
+    return !field_offset || verifier.VerifyOffset(data_ + field_offset);
+  }
+
+  bool VerifyOffsetRequired(const Verifier &verifier, voffset_t field) const {
+    auto field_offset = GetOptionalFieldOffset(field);
+    return verifier.Check(field_offset != 0) &&
+           verifier.VerifyOffset(data_ + field_offset);
+  }
+
  private:
   // private constructor & copy constructor: you obtain instances of this
   // class by pointing to existing data only
@@ -1692,7 +1962,7 @@
   auto table = reinterpret_cast<const Table *>(root);
   auto vtable = table->GetVTable();
   // Either the vtable is before the root or after the root.
-  auto start = std::min(vtable, reinterpret_cast<const uint8_t *>(root));
+  auto start = (std::min)(vtable, reinterpret_cast<const uint8_t *>(root));
   // Align to at least sizeof(uoffset_t).
   start = reinterpret_cast<const uint8_t *>(
             reinterpret_cast<uintptr_t>(start) & ~(sizeof(uoffset_t) - 1));
@@ -1796,6 +2066,73 @@
   #error Unknown compiler, please define structure alignment macros
 #endif
 
+// Minimal reflection via code generation.
+// Besides full-fat reflection (see reflection.h) and parsing/printing by
+// loading schemas (see idl.h), we can also have code generation for mimimal
+// reflection data which allows pretty-printing and other uses without needing
+// a schema or a parser.
+// Generate code with --reflect-types (types only) or --reflect-names (names
+// also) to enable.
+// See minireflect.h for utilities using this functionality.
+
+// These types are organized slightly differently as the ones in idl.h.
+enum SequenceType { ST_TABLE, ST_STRUCT, ST_UNION, ST_ENUM };
+
+// Scalars have the same order as in idl.h
+#define FLATBUFFERS_GEN_ELEMENTARY_TYPES(ET) \
+  ET(ET_UTYPE) \
+  ET(ET_BOOL) \
+  ET(ET_CHAR) \
+  ET(ET_UCHAR) \
+  ET(ET_SHORT) \
+  ET(ET_USHORT) \
+  ET(ET_INT) \
+  ET(ET_UINT) \
+  ET(ET_LONG) \
+  ET(ET_ULONG) \
+  ET(ET_FLOAT) \
+  ET(ET_DOUBLE) \
+  ET(ET_STRING) \
+  ET(ET_SEQUENCE)  // See SequenceType.
+
+enum ElementaryType {
+  #define FLATBUFFERS_ET(E) E,
+    FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
+  #undef FLATBUFFERS_ET
+};
+
+inline const char **ElementaryTypeNames() {
+  static const char *names[] = {
+    #define FLATBUFFERS_ET(E) #E,
+      FLATBUFFERS_GEN_ELEMENTARY_TYPES(FLATBUFFERS_ET)
+    #undef FLATBUFFERS_ET
+  };
+  return names;
+}
+
+// Basic type info cost just 16bits per field!
+struct TypeCode {
+  uint16_t base_type : 4;      // ElementaryType
+  uint16_t is_vector : 1;
+  int16_t sequence_ref : 11;   // Index into type_refs below, or -1 for none.
+};
+
+static_assert(sizeof(TypeCode) == 2, "TypeCode");
+
+struct TypeTable;
+
+// Signature of the static method present in each type.
+typedef TypeTable *(*TypeFunction)();
+
+struct TypeTable {
+  SequenceType st;
+  size_t num_elems;  // of each of the arrays below.
+  const TypeCode *type_codes;
+  const TypeFunction *type_refs;
+  const int32_t *values;  // Only set for non-consecutive enum/union or structs.
+  const char **names;  // Only set if compiled with --reflect-names.
+};
+
 // String which identifies the current version of FlatBuffers.
 // flatbuffer_version_string is used by Google developers to identify which
 // applications uploaded to Google Play are using this library.  This allows
@@ -1849,4 +2186,8 @@
 /// @endcond
 }  // namespace flatbuffers
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
 #endif  // FLATBUFFERS_H_
diff --git a/include/flatbuffers/flatc.h b/include/flatbuffers/flatc.h
index e7bc835..00d1a61 100644
--- a/include/flatbuffers/flatc.h
+++ b/include/flatbuffers/flatc.h
@@ -42,6 +42,7 @@
     const char *generator_opt_short;
     const char *generator_opt_long;
     const char *lang_name;
+    bool schema_only;
     GenerateFn generateGRPC;
     flatbuffers::IDLOptions::Language lang;
     const char *generator_help;
diff --git a/include/flatbuffers/flexbuffers.h b/include/flatbuffers/flexbuffers.h
index bd2be0d..3050c2f 100644
--- a/include/flatbuffers/flexbuffers.h
+++ b/include/flatbuffers/flexbuffers.h
@@ -17,14 +17,21 @@
 #ifndef FLATBUFFERS_FLEXBUFFERS_H_
 #define FLATBUFFERS_FLEXBUFFERS_H_
 
+#include <map>
+// Used to select STL variant.
+#include "flatbuffers/base.h"
 // We use the basic binary writing functions from the regular FlatBuffers.
-#include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/util.h"
 
 #ifdef _MSC_VER
 #include <intrin.h>
 #endif
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4127) // C4127: conditional expression is constant
+#endif
+
 namespace flexbuffers {
 
 class Reference;
@@ -69,23 +76,25 @@
   TYPE_VECTOR_UINT4 = 23,
   TYPE_VECTOR_FLOAT4 = 24,
   TYPE_BLOB = 25,
+  TYPE_BOOL = 26,
+  TYPE_VECTOR_BOOL = 36, // To Allow the same type of conversion of type to vector type
 };
 
-inline bool IsInline(Type t) { return t <= TYPE_FLOAT; }
+inline bool IsInline(Type t) { return t <= TYPE_FLOAT || t == TYPE_BOOL; }
 
 inline bool IsTypedVectorElementType(Type t) {
-  return t >= TYPE_INT && t <= TYPE_STRING;
+  return (t >= TYPE_INT && t <= TYPE_STRING) || t == TYPE_BOOL;
 }
 
 inline bool IsTypedVector(Type t) {
-  return t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING;
+  return (t >= TYPE_VECTOR_INT && t <= TYPE_VECTOR_STRING) || t == TYPE_VECTOR_BOOL;
 }
 
 inline bool IsFixedTypedVector(Type t) {
   return t >= TYPE_VECTOR_INT2 && t <= TYPE_VECTOR_FLOAT4;
 }
 
-inline Type ToTypedVector(Type t, int fixed_len = 0) {
+inline Type ToTypedVector(Type t, size_t fixed_len = 0) {
   assert(IsTypedVectorElementType(t));
   switch (fixed_len) {
     case 0: return static_cast<Type>(t - TYPE_INT + TYPE_VECTOR_INT);
@@ -104,7 +113,7 @@
 inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) {
   assert(IsFixedTypedVector(t));
   auto fixed_type = t - TYPE_VECTOR_INT2;
-  *len = fixed_type / 3 + 2;  // 3 types each, starting from length 2.
+  *len = static_cast<uint8_t>(fixed_type / 3 + 2);  // 3 types each, starting from length 2.
   return static_cast<Type>(fixed_type % 3 + TYPE_INT);
 }
 
@@ -155,7 +164,7 @@
            byte_width);
 }
 
-const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
+inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) {
   return offset - ReadUInt64(offset, byte_width);
 }
 
@@ -163,7 +172,7 @@
   return offset - flatbuffers::ReadScalar<T>(offset);
 }
 
-static BitWidth WidthU(uint64_t u) {
+inline BitWidth WidthU(uint64_t u) {
   #define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) { \
     if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \
   }
@@ -174,12 +183,12 @@
   return BIT_WIDTH_64;
 }
 
-static BitWidth WidthI(int64_t i) {
+inline BitWidth WidthI(int64_t i) {
   auto u = static_cast<uint64_t>(i) << 1;
   return WidthU(i >= 0 ? u : ~u);
 }
 
-static BitWidth WidthF(double f) {
+inline BitWidth WidthF(double f) {
   return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32
                                                          : BIT_WIDTH_64;
 }
@@ -212,6 +221,7 @@
 
   size_t length() const { return size(); }
   const char *c_str() const { return reinterpret_cast<const char *>(data_); }
+  std::string str() const { return std::string(c_str(), length()); }
 
   static String EmptyString() {
     static const uint8_t empty_string[] = { 0/*len*/, 0/*terminator*/ };
@@ -222,14 +232,15 @@
 
 class Blob : public Sized {
  public:
-  Blob(const uint8_t *data, uint8_t byte_width)
-    : Sized(data, byte_width) {}
+  Blob(const uint8_t *data_buf, uint8_t byte_width)
+    : Sized(data_buf, byte_width) {}
 
   static Blob EmptyBlob() {
     static const uint8_t empty_blob[] = { 0/*len*/ };
     return Blob(empty_blob + 1, 1);
   }
   bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; }
+  const uint8_t *data() const { return data_; }
 };
 
 class Vector : public Sized {
@@ -340,6 +351,7 @@
   Type GetType() const { return type_; }
 
   bool IsNull() const { return type_ == TYPE_NULL; }
+  bool IsBool() const { return type_ == TYPE_BOOL; }
   bool IsInt() const { return type_ == TYPE_INT ||
                               type_ == TYPE_INDIRECT_INT; }
   bool IsUInt() const { return type_ == TYPE_UINT||
@@ -352,6 +364,11 @@
   bool IsKey() const { return type_ == TYPE_KEY; }
   bool IsVector() const { return type_ == TYPE_VECTOR || type_ == TYPE_MAP; }
   bool IsMap() const { return type_ == TYPE_MAP; }
+  bool IsBlob() const { return type_ == TYPE_BLOB; }
+
+  bool AsBool() const {
+    return (type_ == TYPE_BOOL ? ReadUInt64(data_, parent_width_) : AsUInt64()) != 0;
+  }
 
   // Reads any type as a int64_t. Never fails, does most sensible conversion.
   // Truncates floats, strings are attempted to be parsed for a number,
@@ -371,6 +388,7 @@
       case TYPE_NULL: return 0;
       case TYPE_STRING: return flatbuffers::StringToInt(AsString().c_str());
       case TYPE_VECTOR: return static_cast<int64_t>(AsVector().size());
+      case TYPE_BOOL: return ReadInt64(data_, parent_width_);
       default:
       // Convert other things to int.
       return 0;
@@ -398,6 +416,7 @@
       case TYPE_NULL: return 0;
       case TYPE_STRING: return flatbuffers::StringToUInt(AsString().c_str());
       case TYPE_VECTOR: return static_cast<uint64_t>(AsVector().size());
+      case TYPE_BOOL: return ReadUInt64(data_, parent_width_);
       default:
       // Convert other things to uint.
       return 0;
@@ -425,6 +444,8 @@
       case TYPE_NULL: return 0.0;
       case TYPE_STRING: return strtod(AsString().c_str(), nullptr);
       case TYPE_VECTOR: return static_cast<double>(AsVector().size());
+      case TYPE_BOOL: return static_cast<double>(
+                               ReadUInt64(data_, parent_width_));
       default:
       // Convert strings and other things to float.
       return 0;
@@ -451,25 +472,63 @@
   }
 
   // Unlike AsString(), this will convert any type to a std::string.
-  std::string ToString() const {
+  std::string ToString() {
+    std::string s;
+    ToString(false, false, s);
+    return s;
+  }
+
+  // Convert any type to a JSON-like string. strings_quoted determines if
+  // string values at the top level receive "" quotes (inside other values
+  // they always do). keys_quoted determines if keys are quoted, at any level.
+  // TODO(wvo): add further options to have indentation/newlines.
+  void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const {
     if (type_ == TYPE_STRING) {
-      return String(Indirect(), byte_width_).c_str();
+      String str(Indirect(), byte_width_);
+      if (strings_quoted) {
+        flatbuffers::EscapeString(str.c_str(), str.length(), &s, true);
+      } else {
+        s.append(str.c_str(), str.length());
+      }
     } else if (IsKey()) {
-      return AsKey();
+      auto str = AsKey();
+      if (keys_quoted) {
+        flatbuffers::EscapeString(str, strlen(str), &s, true);
+      } else {
+        s += str;
+      }
     } else if (IsInt()) {
-      return flatbuffers::NumToString(AsInt64());
+      s += flatbuffers::NumToString(AsInt64());
     } else if (IsUInt()) {
-      return flatbuffers::NumToString(AsUInt64());
+      s += flatbuffers::NumToString(AsUInt64());
     } else if (IsFloat()) {
-      return flatbuffers::NumToString(AsDouble());
+      s += flatbuffers::NumToString(AsDouble());
     } else if (IsNull()) {
-      return "null";
+      s += "null";
+    } else if (IsBool()) {
+      s += AsBool() ? "true" : "false";
     } else if (IsMap()) {
-      return "{..}";  // TODO: show elements.
+      s += "{ ";
+      auto m = AsMap();
+      auto keys = m.Keys();
+      auto vals = m.Values();
+      for (size_t i = 0; i < keys.size(); i++) {
+        keys[i].ToString(true, keys_quoted, s);
+        s += ": ";
+        vals[i].ToString(true, keys_quoted, s);
+        if (i < keys.size() - 1) s += ", ";
+      }
+      s += " }";
     } else if (IsVector()) {
-      return "[..]";  // TODO: show elements.
+      s += "[ ";
+      auto v = AsVector();
+      for (size_t i = 0; i < v.size(); i++) {
+        v[i].ToString(true, keys_quoted, s);
+        if (i < v.size() - 1) s += ", ";
+      }
+      s += " ]";
     } else {
-      return "(?)";
+      s += "(?)";
     }
   }
 
@@ -520,6 +579,8 @@
     }
   }
 
+  template<typename T> T As();
+
   // Experimental: Mutation functions.
   // These allow scalars in an already created buffer to be updated in-place.
   // Since by default scalars are stored in the smallest possible space,
@@ -542,6 +603,10 @@
     }
   }
 
+  bool MutateBool(bool b) {
+    return type_ == TYPE_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8);
+  }
+
   bool MutateUInt(uint64_t u) {
     if (type_ == TYPE_UINT) {
       return Mutate(data_, u, parent_width_, WidthU(u));
@@ -601,7 +666,7 @@
 
   template<typename T> bool Mutate(const uint8_t *dest, T t, size_t byte_width,
                                    BitWidth value_width) {
-    auto fits = (1U << value_width) <= byte_width;
+    auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <= byte_width;
     if (fits) {
       t = flatbuffers::EndianScalar(t);
       memcpy(const_cast<uint8_t *>(dest), &t, byte_width);
@@ -625,6 +690,31 @@
   Type type_;
 };
 
+// Template specialization for As().
+template<> inline bool Reference::As<bool>() { return AsBool(); }
+
+template<> inline int8_t Reference::As<int8_t>() { return AsInt8(); }
+template<> inline int16_t Reference::As<int16_t>() { return AsInt16(); }
+template<> inline int32_t Reference::As<int32_t>() { return AsInt32(); }
+template<> inline int64_t Reference::As<int64_t>() { return AsInt64(); }
+
+template<> inline uint8_t Reference::As<uint8_t>() { return AsUInt8(); }
+template<> inline uint16_t Reference::As<uint16_t>() { return AsUInt16(); }
+template<> inline uint32_t Reference::As<uint32_t>() { return AsUInt32(); }
+template<> inline uint64_t Reference::As<uint64_t>() { return AsUInt64(); }
+
+template<> inline double Reference::As<double>() { return AsDouble(); }
+template<> inline float Reference::As<float>() { return AsFloat(); }
+
+template<> inline String Reference::As<String>() { return AsString(); }
+template<> inline std::string Reference::As<std::string>() { return AsString().str(); }
+
+template<> inline Blob Reference::As<Blob>() { return AsBlob(); }
+template<> inline Vector Reference::As<Vector>() { return AsVector(); }
+template<> inline TypedVector Reference::As<TypedVector>() { return AsTypedVector(); }
+template<> inline FixedTypedVector Reference::As<FixedTypedVector>() { return AsFixedTypedVector(); }
+template<> inline Map Reference::As<Map>() { return AsMap(); }
+
 inline uint8_t PackedType(BitWidth bit_width, Type type) {
   return static_cast<uint8_t>(bit_width | (type << 2));
 }
@@ -701,7 +791,7 @@
 }
 
 inline Reference GetRoot(const std::vector<uint8_t> &buffer) {
-  return GetRoot(buffer.data(), buffer.size());
+  return GetRoot(flatbuffers::vector_data(buffer), buffer.size());
 }
 
 // Flags that configure how the Builder behaves.
@@ -740,6 +830,22 @@
     return buf_;
   }
 
+  // Size of the buffer. Does not include unfinished values.
+  size_t GetSize() const {
+    return buf_.size();
+  }
+
+  // Reset all state so we can re-use the buffer.
+  void Clear() {
+    buf_.clear();
+    stack_.clear();
+    finished_ = false;
+    // flags_ remains as-is;
+    force_min_bit_width_ = BIT_WIDTH_8;
+    key_pool.clear();
+    string_pool.clear();
+  }
+
   // All value constructing functions below have two versions: one that
   // takes a key (for placement inside a map) and one that doesn't (for inside
   // vectors and elsewhere).
@@ -759,7 +865,7 @@
   void Double(double f) { stack_.push_back(Value(f)); }
   void Double(const char *key, double d) { Key(key); Double(d); }
 
-  void Bool(bool b) { Int(static_cast<int64_t>(b)); }
+  void Bool(bool b) { stack_.push_back(Value(b)); }
   void Bool(const char *key, bool b) { Key(key); Bool(b); }
 
   void IndirectInt(int64_t i) {
@@ -860,7 +966,7 @@
     return CreateBlob(data, len, 0, TYPE_BLOB);
   }
   size_t Blob(const std::vector<uint8_t> &v) {
-    return CreateBlob(v.data(), v.size(), 0, TYPE_BLOB);
+    return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, TYPE_BLOB);
   }
 
   // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String),
@@ -904,11 +1010,15 @@
     // step automatically when appliccable, and encourage people to write in
     // sorted fashion.
     // std::sort is typically already a lot faster on sorted data though.
-    auto dict = reinterpret_cast<TwoValue *>(stack_.data() + start);
+    auto dict =
+        reinterpret_cast<TwoValue *>(flatbuffers::vector_data(stack_) +
+                                     start);
     std::sort(dict, dict + len,
               [&](const TwoValue &a, const TwoValue &b) -> bool {
-      auto as = reinterpret_cast<const char *>(buf_.data() + a.key.u_);
-      auto bs = reinterpret_cast<const char *>(buf_.data() + b.key.u_);
+      auto as = reinterpret_cast<const char *>(
+          flatbuffers::vector_data(buf_) + a.key.u_);
+      auto bs = reinterpret_cast<const char *>(
+          flatbuffers::vector_data(buf_) + b.key.u_);
       auto comp = strcmp(as, bs);
       // If this assertion hits, you've added two keys with the same value to
       // this map.
@@ -933,13 +1043,25 @@
     f();
     return EndVector(start, false, false);
   }
+  template <typename F, typename T> size_t Vector(F f, T &state) {
+    auto start = StartVector();
+    f(state);
+    return EndVector(start, false, false);
+  }
   template<typename F> size_t Vector(const char *key, F f) {
     auto start = StartVector(key);
     f();
     return EndVector(start, false, false);
   }
+  template <typename F, typename T> size_t Vector(const char *key, F f,
+                                                  T &state) {
+    auto start = StartVector(key);
+    f(state);
+    return EndVector(start, false, false);
+  }
+
   template<typename T> void Vector(const T *elems, size_t len) {
-    if (std::is_scalar<T>::value) {
+    if (flatbuffers::is_scalar<T>::value) {
       // This path should be a lot quicker and use less space.
       ScalarVector(elems, len, false);
     } else {
@@ -954,7 +1076,7 @@
     Vector(elems, len);
   }
   template<typename T> void Vector(const std::vector<T> &vec) {
-    Vector(vec.data(), vec.size());
+    Vector(flatbuffers::vector_data(vec), vec.size());
   }
 
   template<typename F> size_t TypedVector(F f) {
@@ -962,18 +1084,29 @@
     f();
     return EndVector(start, true, false);
   }
+  template <typename F, typename T> size_t TypedVector(F f, T &state) {
+    auto start = StartVector();
+    f(state);
+    return EndVector(start, true, false);
+  }
   template<typename F> size_t TypedVector(const char *key, F f) {
     auto start = StartVector(key);
     f();
     return EndVector(start, true, false);
   }
+  template <typename F, typename T> size_t TypedVector(const char *key, F f,
+                                                       T &state) {
+    auto start = StartVector(key);
+    f(state);
+    return EndVector(start, true, false);
+  }
 
   template<typename T> size_t FixedTypedVector(const T *elems, size_t len) {
     // We only support a few fixed vector lengths. Anything bigger use a
     // regular typed vector.
     assert(len >= 2 && len <= 4);
     // And only scalar values.
-    assert(std::is_scalar<T>::value);
+    assert(flatbuffers::is_scalar<T>::value);
     return ScalarVector(elems, len, true);
   }
 
@@ -988,11 +1121,22 @@
     f();
     return EndMap(start);
   }
+  template <typename F, typename T> size_t Map(F f, T &state) {
+    auto start = StartMap();
+    f(state);
+    return EndMap(start);
+  }
   template<typename F> size_t Map(const char *key, F f) {
     auto start = StartMap(key);
     f();
     return EndMap(start);
   }
+  template <typename F, typename T> size_t Map(const char *key, F f,
+                                               T &state) {
+    auto start = StartMap(key);
+    f(state);
+    return EndMap(start);
+  }
   template<typename T> void Map(const std::map<std::string, T> &map) {
     auto start = StartMap();
     for (auto it = map.begin(); it != map.end(); ++it)
@@ -1072,7 +1216,7 @@
     auto byte_width = 1U << alignment;
     buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width),
                 0);
-    return byte_width;
+    return static_cast<uint8_t>(byte_width);
   }
 
   void WriteBytes(const void *val, size_t size) {
@@ -1081,8 +1225,8 @@
                 reinterpret_cast<const uint8_t *>(val) + size);
   }
 
-  // For values T >= byte_width
-  template<typename T> void Write(T val, uint8_t byte_width) {
+  template<typename T> void Write(T val, size_t byte_width) {
+    assert(sizeof(T) >= byte_width);
     val = flatbuffers::EndianScalar(val);
     WriteBytes(&val, byte_width);
   }
@@ -1121,10 +1265,11 @@
   }
 
   template<typename T> static Type GetScalarType() {
-    assert(std::is_scalar<T>::value);
-    return std::is_floating_point<T>::value
+    assert(flatbuffers::is_scalar<T>::value);
+    return flatbuffers::is_floating_point<T>::value
         ? TYPE_FLOAT
-        : (std::is_unsigned<T>::value ? TYPE_UINT : TYPE_INT);
+        : flatbuffers::is_same<T, bool>::value ? TYPE_BOOL
+            : (flatbuffers::is_unsigned<T>::value ? TYPE_UINT : TYPE_INT);
   }
 
   struct Value {
@@ -1141,6 +1286,8 @@
 
     Value() : i_(0), type_(TYPE_NULL), min_bit_width_(BIT_WIDTH_8) {}
 
+    Value(bool b) : u_(static_cast<uint64_t>(b)), type_(TYPE_BOOL), min_bit_width_(BIT_WIDTH_8) {}
+
     Value(int64_t i, Type t, BitWidth bw)
       : i_(i), type_(t), min_bit_width_(bw) {}
     Value(uint64_t u, Type t, BitWidth bw)
@@ -1176,7 +1323,8 @@
           auto offset = offset_loc - u_;
           // Does it fit?
           auto bit_width = WidthU(offset);
-          if (1U << bit_width == byte_width) return bit_width;
+          if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) == byte_width)
+            return bit_width;
         }
         assert(false);  // Must match one of the sizes above.
         return BIT_WIDTH_64;
@@ -1185,7 +1333,7 @@
 
     BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const {
       if (IsInline(type_)) {
-          return std::max(min_bit_width_, parent_bit_width_);
+          return (std::max)(min_bit_width_, parent_bit_width_);
       } else {
           return min_bit_width_;
       }
@@ -1198,6 +1346,7 @@
       case TYPE_INT:
         Write(val.i_, byte_width);
         break;
+      case TYPE_BOOL:
       case TYPE_UINT:
         Write(val.u_, byte_width);
         break;
@@ -1231,7 +1380,7 @@
     // TODO: instead of asserting, could write vector with larger elements
     // instead, though that would be wasteful.
     assert(WidthU(len) <= bit_width);
-    if (!fixed) Write(len, byte_width);
+    if (!fixed) Write<uint64_t>(len, byte_width);
     auto vloc = buf_.size();
     for (size_t i = 0; i < len; i++) Write(elems[i], byte_width);
     stack_.push_back(Value(static_cast<uint64_t>(vloc),
@@ -1243,19 +1392,19 @@
   Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed,
                      bool fixed, const Value *keys = nullptr) {
     // Figure out smallest bit width we can store this vector with.
-    auto bit_width = std::max(force_min_bit_width_, WidthU(vec_len));
+    auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len));
     auto prefix_elems = 1;
     if (keys) {
       // If this vector is part of a map, we will pre-fix an offset to the keys
       // to this vector.
-      bit_width = std::max(bit_width, keys->ElemWidth(buf_.size(), 0));
+      bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0));
       prefix_elems += 2;
     }
     Type vector_type = TYPE_KEY;
     // Check bit widths and types for all elements.
     for (size_t i = start; i < stack_.size(); i += step) {
       auto elem_width = stack_[i].ElemWidth(buf_.size(), i + prefix_elems);
-      bit_width = std::max(bit_width, elem_width);
+      bit_width = (std::max)(bit_width, elem_width);
       if (typed) {
         if (i == start) {
           vector_type = stack_[i].type_;
@@ -1273,9 +1422,9 @@
     // Write vector. First the keys width/offset if available, and size.
     if (keys) {
       WriteOffset(keys->u_, byte_width);
-      Write(1U << keys->min_bit_width_, byte_width);
+      Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width);
     }
-    if (!fixed) Write(vec_len, byte_width);
+    if (!fixed) Write<uint64_t>(vec_len, byte_width);
     // Then the actual data.
     auto vloc = buf_.size();
     for (size_t i = start; i < stack_.size(); i += step) {
@@ -1310,9 +1459,11 @@
 
   struct KeyOffsetCompare {
     KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
-    bool operator() (size_t a, size_t b) const {
-      auto stra = reinterpret_cast<const char *>(buf_->data() + a);
-      auto strb = reinterpret_cast<const char *>(buf_->data() + b);
+    bool operator()(size_t a, size_t b) const {
+      auto stra =
+          reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a);
+      auto strb =
+          reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + b);
       return strcmp(stra, strb) < 0;
     }
     const std::vector<uint8_t> *buf_;
@@ -1321,10 +1472,12 @@
   typedef std::pair<size_t, size_t> StringOffset;
   struct StringOffsetCompare {
     StringOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {}
-    bool operator() (const StringOffset &a, const StringOffset &b) const {
-      auto stra = reinterpret_cast<const char *>(buf_->data() + a.first);
-      auto strb = reinterpret_cast<const char *>(buf_->data() + b.first);
-      return strncmp(stra, strb, std::min(a.second, b.second) + 1) < 0;
+    bool operator()(const StringOffset &a, const StringOffset &b) const {
+      auto stra = reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) +
+                                                 a.first);
+      auto strb = reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) +
+                                                 b.first);
+      return strncmp(stra, strb, (std::min)(a.second, b.second) + 1) < 0;
     }
     const std::vector<uint8_t> *buf_;
   };
@@ -1338,4 +1491,8 @@
 
 }  // namespace flexbuffers
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
 #endif  // FLATBUFFERS_FLEXBUFFERS_H_
diff --git a/include/flatbuffers/grpc.h b/include/flatbuffers/grpc.h
index 48ff3c8..a5730f6 100644
--- a/include/flatbuffers/grpc.h
+++ b/include/flatbuffers/grpc.h
@@ -19,49 +19,234 @@
 
 // Helper functionality to glue FlatBuffers and GRPC.
 
+#include "flatbuffers/flatbuffers.h"
 #include "grpc++/support/byte_buffer.h"
 #include "grpc/byte_buffer_reader.h"
 
+namespace flatbuffers {
+namespace grpc {
+
+// Message is a typed wrapper around a buffer that manages the underlying
+// `grpc_slice` and also provides flatbuffers-specific helpers such as `Verify`
+// and `GetRoot`. Since it is backed by a `grpc_slice`, the underlying buffer
+// is refcounted and ownership is be managed automatically.
+template <class T>
+class Message {
+ public:
+  Message() : slice_(grpc_empty_slice()) {}
+
+  Message(grpc_slice slice, bool add_ref)
+    : slice_(add_ref ? grpc_slice_ref(slice) : slice) {}
+
+  Message &operator=(const Message &other) = delete;
+
+  Message(Message &&other) : slice_(other.slice_) {
+    other.slice_ = grpc_empty_slice();
+  }
+
+  Message(const Message &other) = delete;
+
+  Message &operator=(Message &&other) {
+    grpc_slice_unref(slice_);
+    slice_ = other.slice_;
+    other.slice_ = grpc_empty_slice();
+    return *this;
+  }
+
+  ~Message() { grpc_slice_unref(slice_); }
+
+  const uint8_t *mutable_data() const { return GRPC_SLICE_START_PTR(slice_); }
+
+  const uint8_t *data() const { return GRPC_SLICE_START_PTR(slice_); }
+
+  size_t size() const { return GRPC_SLICE_LENGTH(slice_); }
+
+  bool Verify() const {
+    Verifier verifier(data(), size());
+    return verifier.VerifyBuffer<T>(nullptr);
+  }
+
+  T *GetMutableRoot() { return flatbuffers::GetMutableRoot<T>(mutable_data()); }
+
+  const T *GetRoot() const { return flatbuffers::GetRoot<T>(data()); }
+
+  // This is only intended for serializer use, or if you know what you're doing
+  const grpc_slice &BorrowSlice() const { return slice_; }
+
+ private:
+  grpc_slice slice_;
+};
+
+class MessageBuilder;
+
+// SliceAllocator is a gRPC-specific allocator that uses the `grpc_slice`
+// refcounted slices to manage memory ownership. This makes it easy and
+// efficient to transfer buffers to gRPC.
+class SliceAllocator : public Allocator {
+ public:
+  SliceAllocator() : slice_(grpc_empty_slice()) {}
+
+  SliceAllocator(const SliceAllocator &other) = delete;
+  SliceAllocator &operator=(const SliceAllocator &other) = delete;
+
+  virtual ~SliceAllocator() { grpc_slice_unref(slice_); }
+
+  virtual uint8_t *allocate(size_t size) override {
+    assert(GRPC_SLICE_IS_EMPTY(slice_));
+    slice_ = grpc_slice_malloc(size);
+    return GRPC_SLICE_START_PTR(slice_);
+  }
+
+  virtual void deallocate(uint8_t *p, size_t size) override {
+    assert(p == GRPC_SLICE_START_PTR(slice_));
+    assert(size == GRPC_SLICE_LENGTH(slice_));
+    grpc_slice_unref(slice_);
+    slice_ = grpc_empty_slice();
+  }
+
+  virtual uint8_t *reallocate_downward(uint8_t *old_p, size_t old_size,
+                                       size_t new_size) override {
+    assert(old_p == GRPC_SLICE_START_PTR(slice_));
+    assert(old_size == GRPC_SLICE_LENGTH(slice_));
+    assert(new_size > old_size);
+    grpc_slice old_slice = slice_;
+    grpc_slice new_slice = grpc_slice_malloc(new_size);
+    uint8_t *new_p = GRPC_SLICE_START_PTR(new_slice);
+    memcpy(new_p + (new_size - old_size), old_p, old_size);
+    slice_ = new_slice;
+    grpc_slice_unref(old_slice);
+    return new_p;
+  }
+
+ private:
+  grpc_slice &get_slice(uint8_t *p, size_t size) {
+    assert(p == GRPC_SLICE_START_PTR(slice_));
+    assert(size == GRPC_SLICE_LENGTH(slice_));
+    return slice_;
+  }
+
+  grpc_slice slice_;
+
+  friend class MessageBuilder;
+};
+
+// SliceAllocatorMember is a hack to ensure that the MessageBuilder's
+// slice_allocator_ member is constructed before the FlatBufferBuilder, since
+// the allocator is used in the FlatBufferBuilder ctor.
+namespace detail {
+struct SliceAllocatorMember {
+  SliceAllocator slice_allocator_;
+};
+}
+
+// MessageBuilder is a gRPC-specific FlatBufferBuilder that uses SliceAllocator
+// to allocate gRPC buffers.
+class MessageBuilder : private detail::SliceAllocatorMember,
+                       public FlatBufferBuilder {
+ public:
+  explicit MessageBuilder(uoffset_t initial_size = 1024)
+    : FlatBufferBuilder(initial_size, &slice_allocator_, false) {}
+
+  MessageBuilder(const MessageBuilder &other) = delete;
+  MessageBuilder &operator=(const MessageBuilder &other) = delete;
+
+  ~MessageBuilder() {}
+
+  // GetMessage extracts the subslice of the buffer corresponding to the
+  // flatbuffers-encoded region and wraps it in a `Message<T>` to handle buffer
+  // ownership.
+  template <class T>
+  Message<T> GetMessage() {
+    auto buf_data = buf_.buf();       // pointer to memory
+    auto buf_size = buf_.capacity();  // size of memory
+    auto msg_data = buf_.data();      // pointer to msg
+    auto msg_size = buf_.size();      // size of msg
+    // Do some sanity checks on data/size
+    assert(msg_data);
+    assert(msg_size);
+    assert(msg_data >= buf_data);
+    assert(msg_data + msg_size <= buf_data + buf_size);
+    // Calculate offsets from the buffer start
+    auto begin = msg_data - buf_data;
+    auto end = begin + msg_size;
+    // Get the slice we are working with (no refcount change)
+    grpc_slice slice = slice_allocator_.get_slice(buf_data, buf_size);
+    // Extract a subslice of the existing slice (increment refcount)
+    grpc_slice subslice = grpc_slice_sub(slice, begin, end);
+    // Wrap the subslice in a `Message<T>`, but don't increment refcount
+    Message<T> msg(subslice, false);
+    return msg;
+  }
+
+  template <class T>
+  Message<T> ReleaseMessage() {
+    Message<T> msg = GetMessage<T>();
+    Reset();
+    return msg;
+  }
+
+ private:
+  // SliceAllocator slice_allocator_;  // part of SliceAllocatorMember
+};
+
+}  // namespace grpc
+}  // namespace flatbuffers
+
 namespace grpc {
 
 template <class T>
-class SerializationTraits<T, typename std::enable_if<std::is_base_of<
-                                 flatbuffers::BufferRefBase, T>::value>::type> {
+class SerializationTraits<flatbuffers::grpc::Message<T>> {
  public:
-  // The type we're passing here is a BufferRef, which is already serialized
-  // FlatBuffer data, which then gets passed to GRPC.
-  static grpc::Status Serialize(const T& msg,
-                                grpc_byte_buffer **buffer,
-                                bool *own_buffer) {
-    // TODO(wvo): make this work without copying.
-    auto slice = gpr_slice_from_copied_buffer(
-                   reinterpret_cast<const char *>(msg.buf), msg.len);
-    *buffer = grpc_raw_byte_buffer_create(&slice, 1);
+  static grpc::Status Serialize(const flatbuffers::grpc::Message<T> &msg,
+                                grpc_byte_buffer **buffer, bool *own_buffer) {
+    // We are passed in a `Message<T>`, which is a wrapper around a
+    // `grpc_slice`. We extract it here using `BorrowSlice()`. The const cast
+    // is necesary because the `grpc_raw_byte_buffer_create` func expects
+    // non-const slices in order to increment their refcounts.
+    grpc_slice *slice = const_cast<grpc_slice *>(&msg.BorrowSlice());
+    // Now use `grpc_raw_byte_buffer_create` to package the single slice into a
+    // `grpc_byte_buffer`, incrementing the refcount in the process.
+    *buffer = grpc_raw_byte_buffer_create(slice, 1);
     *own_buffer = true;
-    return grpc::Status();
+    return grpc::Status::OK;
   }
 
-  // There is no de-serialization step in FlatBuffers, so we just receive
-  // the data from GRPC.
-  static grpc::Status Deserialize(grpc_byte_buffer *buffer, T *msg) {
-    // TODO(wvo): make this more efficient / zero copy when possible.
-    auto len = grpc_byte_buffer_length(buffer);
-    msg->buf = reinterpret_cast<uint8_t *>(malloc(len));
-    msg->len = static_cast<flatbuffers::uoffset_t>(len);
-    msg->must_free = true;
-    uint8_t *current = msg->buf;
-    grpc_byte_buffer_reader reader;
-    grpc_byte_buffer_reader_init(&reader, buffer);
-    gpr_slice slice;
-    while (grpc_byte_buffer_reader_next(&reader, &slice)) {
-      memcpy(current, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
-      current += GPR_SLICE_LENGTH(slice);
-      gpr_slice_unref(slice);
+  // Deserialize by pulling the
+  static grpc::Status Deserialize(grpc_byte_buffer *buffer,
+                                  flatbuffers::grpc::Message<T> *msg) {
+    if (!buffer) {
+      return ::grpc::Status(::grpc::StatusCode::INTERNAL, "No payload");
     }
-    GPR_ASSERT(current == msg->buf + msg->len);
-    grpc_byte_buffer_reader_destroy(&reader);
+    // Check if this is a single uncompressed slice.
+    if ((buffer->type == GRPC_BB_RAW) &&
+        (buffer->data.raw.compression == GRPC_COMPRESS_NONE) &&
+        (buffer->data.raw.slice_buffer.count == 1)) {
+      // If it is, then we can reference the `grpc_slice` directly.
+      grpc_slice slice = buffer->data.raw.slice_buffer.slices[0];
+      // We wrap a `Message<T>` around the slice, incrementing the refcount.
+      *msg = flatbuffers::grpc::Message<T>(slice, true);
+    } else {
+      // Otherwise, we need to use `grpc_byte_buffer_reader_readall` to read
+      // `buffer` into a single contiguous `grpc_slice`. The gRPC reader gives
+      // us back a new slice with the refcount already incremented.
+      grpc_byte_buffer_reader reader;
+      grpc_byte_buffer_reader_init(&reader, buffer);
+      grpc_slice slice = grpc_byte_buffer_reader_readall(&reader);
+      grpc_byte_buffer_reader_destroy(&reader);
+      // We wrap a `Message<T>` around the slice, but dont increment refcount
+      *msg = flatbuffers::grpc::Message<T>(slice, false);
+    }
     grpc_byte_buffer_destroy(buffer);
-    return grpc::Status();
+    #if FLATBUFFERS_GRPC_DISABLE_AUTO_VERIFICATION
+    return ::grpc::Status::OK;
+    #else
+    if (msg->Verify()) {
+      return ::grpc::Status::OK;
+    } else {
+      return ::grpc::Status(::grpc::StatusCode::INTERNAL,
+                            "Message verification failed");
+    }
+    #endif
   }
 };
 
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 5b7a72a..d06b5a4 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -20,11 +20,16 @@
 #include <map>
 #include <stack>
 #include <memory>
-#include <functional>
 
+#include "flatbuffers/base.h"
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/hash.h"
 #include "flatbuffers/reflection.h"
+#include "flatbuffers/flexbuffers.h"
+
+#if !defined(FLATBUFFERS_CPP98_STL)
+  #include <functional>
+#endif  // !defined(FLATBUFFERS_CPP98_STL)
 
 // This file defines the data types representing a parsed IDL (Interface
 // Definition Language) / schema file.
@@ -104,6 +109,7 @@
                                            t == BASE_TYPE_DOUBLE; }
 inline bool IsLong   (BaseType t) { return t == BASE_TYPE_LONG ||
                                            t == BASE_TYPE_ULONG; }
+inline bool IsBool   (BaseType t) { return t == BASE_TYPE_BOOL; }
 
 extern const char *const kTypeNames[];
 extern const char kTypeSizes[];
@@ -163,7 +169,7 @@
   }
 
   bool Add(const std::string &name, T *e) {
-    vec.emplace_back(e);
+    vector_emplace_back(&vec, e);
     auto it = dict.find(name);
     if (it != dict.end()) return true;
     dict[name] = e;
@@ -193,7 +199,8 @@
 
 // A name space, as set in the schema.
 struct Namespace {
-  std::vector<std::string> components;
+  Namespace() : from_table(0) {}
+
 
   // Given a (potentally unqualified) name, return the "fully qualified" name
   // which has a full namespaced descriptor.
@@ -201,12 +208,15 @@
   // the current namespace has.
   std::string GetFullyQualifiedName(const std::string &name,
                                     size_t max_components = 1000) const;
+
+  std::vector<std::string> components;
+  size_t from_table;  // Part of the namespace corresponds to a message/table.
 };
 
 // Base class for all definition types (fields, structs_, enums_).
 struct Definition {
   Definition() : generated(false), defined_namespace(nullptr),
-                 serialized_location(0), index(-1) {}
+                 serialized_location(0), index(-1), refcount(1) {}
 
   flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<
     reflection::KeyValue>>>
@@ -223,21 +233,26 @@
   // For use with Serialize()
   uoffset_t serialized_location;
   int index;  // Inside the vector it is stored.
+  int refcount;
 };
 
 struct FieldDef : public Definition {
-  FieldDef() : deprecated(false), required(false), key(false), padding(0) {}
+  FieldDef() : deprecated(false), required(false), key(false),
+               native_inline(false), flexbuffer(false), nested_flatbuffer(NULL),
+               padding(0) {}
 
   Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id,
                                       const Parser &parser) const;
 
   Value value;
-  bool deprecated; // Field is allowed to be present in old data, but can't be
+  bool deprecated; // Field is allowed to be present in old data, but can't be.
                    // written in new data nor accessed in new code.
   bool required;   // Field must always be present.
   bool key;        // Field functions as a key for creating sorted vectors.
   bool native_inline;  // Field will be defined inline (instead of as a pointer)
                        // for native tables if field is a struct.
+  bool flexbuffer; // This field contains FlexBuffer data.
+  StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data.
   size_t padding;  // Bytes to always pad after this field.
 };
 
@@ -261,12 +276,15 @@
                                        const Parser &parser) const;
 
   SymbolTable<FieldDef> fields;
+
   bool fixed;       // If it's struct, not a table.
   bool predecl;     // If it's used before it was defined.
   bool sortbysize;  // Whether fields come in the declaration or size order.
   bool has_key;     // It has a key field.
   size_t minalign;  // What the whole object needs to be aligned to.
   size_t bytesize;  // Size if fixed.
+
+  flatbuffers::unique_ptr<std::string> original_location;
 };
 
 inline bool IsStruct(const Type &type) {
@@ -283,18 +301,18 @@
 
 struct EnumVal {
   EnumVal(const std::string &_name, int64_t _val)
-    : name(_name), value(_val), struct_def(nullptr) {}
+    : name(_name), value(_val) {}
 
   Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder) const;
 
   std::string name;
   std::vector<std::string> doc_comment;
   int64_t value;
-  StructDef *struct_def;  // only set if this is a union
+  Type union_type;
 };
 
 struct EnumDef : public Definition {
-  EnumDef() : is_union(false) {}
+  EnumDef() : is_union(false), uses_type_aliases(false) {}
 
   EnumVal *ReverseLookup(int enum_idx, bool skip_union_default = true) {
     for (auto it = vals.vec.begin() + static_cast<int>(is_union &&
@@ -312,6 +330,7 @@
 
   SymbolTable<EnumVal> vals;
   bool is_union;
+  bool uses_type_aliases;
   Type underlying_type;
 };
 
@@ -350,13 +369,22 @@
   bool generate_all;
   bool skip_unexpected_fields_in_json;
   bool generate_name_strings;
-  bool escape_proto_identifiers;
   bool generate_object_based_api;
   std::string cpp_object_api_pointer_type;
+  std::string cpp_object_api_string_type;
+  bool gen_nullable;
+  std::string object_prefix;
+  std::string object_suffix;
   bool union_value_namespacing;
   bool allow_non_utf8;
   std::string include_prefix;
+  bool keep_include_path;
   bool binary_schema_comments;
+  bool skip_flatbuffers_import;
+  std::string go_import;
+  std::string go_namespace;
+  bool reexport_ts_modules;
+  bool protobuf_ascii_alike;
 
   // Possible options for the more general generator below.
   enum Language {
@@ -369,11 +397,17 @@
     kPhp    = 1 << 6,
     kJson   = 1 << 7,
     kBinary = 1 << 8,
+    kTs     = 1 << 9,
+    kJsonSchema = 1 << 10,
     kMAX
   };
 
   Language lang;
 
+  enum MiniReflect { kNone, kTypes, kTypesAndNames };
+
+  MiniReflect mini_reflect;
+
   // The corresponding language bit will be set if a language is included
   // for code generation.
   unsigned long lang_to_generate;
@@ -392,13 +426,19 @@
       generate_all(false),
       skip_unexpected_fields_in_json(false),
       generate_name_strings(false),
-      escape_proto_identifiers(false),
       generate_object_based_api(false),
       cpp_object_api_pointer_type("std::unique_ptr"),
+      gen_nullable(false),
+      object_suffix("T"),
       union_value_namespacing(true),
       allow_non_utf8(false),
+      keep_include_path(false),
       binary_schema_comments(false),
+      skip_flatbuffers_import(false),
+      reexport_ts_modules(true),
+      protobuf_ascii_alike(false),
       lang(IDLOptions::kJava),
+      mini_reflect(IDLOptions::kNone),
       lang_to_generate(0) {}
 };
 
@@ -459,12 +499,17 @@
 class Parser : public ParserState {
  public:
   explicit Parser(const IDLOptions &options = IDLOptions())
-    : root_struct_def_(nullptr),
+    : current_namespace_(nullptr),
+      empty_namespace_(nullptr),
+      root_struct_def_(nullptr),
       opts(options),
+      uses_flexbuffers_(false),
       source_(nullptr),
       anonymous_counter(0) {
-    // Just in case none are declared:
-    namespaces_.push_back(new Namespace());
+    // Start out with the empty namespace being current.
+    empty_namespace_ = new Namespace();
+    namespaces_.push_back(empty_namespace_);
+    current_namespace_ = empty_namespace_;
     known_attributes_["deprecated"] = true;
     known_attributes_["required"] = true;
     known_attributes_["key"] = true;
@@ -479,9 +524,12 @@
     known_attributes_["idempotent"] = true;
     known_attributes_["cpp_type"] = true;
     known_attributes_["cpp_ptr_type"] = true;
+    known_attributes_["cpp_str_type"] = true;
     known_attributes_["native_inline"] = true;
+    known_attributes_["native_custom_alloc"] = true;
     known_attributes_["native_type"] = true;
     known_attributes_["native_default"] = true;
+    known_attributes_["flexbuffer"] = true;
   }
 
   ~Parser() {
@@ -499,6 +547,8 @@
   // directory.
   // If the source was loaded from a file and isn't an include file,
   // supply its name in source_filename.
+  // All paths specified in this call must be in posix format, if you accept
+  // paths from user input, please call PosixPath on them first.
   bool Parse(const char *_source, const char **include_paths = nullptr,
              const char *source_filename = nullptr);
 
@@ -521,14 +571,24 @@
   // of the schema provided. Returns non-empty error on any problems.
   std::string ConformTo(const Parser &base);
 
-  FLATBUFFERS_CHECKED_ERROR CheckBitsFit(int64_t val, size_t bits);
+  // Similar to Parse(), but now only accepts JSON to be parsed into a
+  // FlexBuffer.
+  bool ParseFlexBuffer(const char *source, const char *source_filename,
+                       flexbuffers::Builder *builder);
+
+  FLATBUFFERS_CHECKED_ERROR CheckInRange(int64_t val, int64_t min, int64_t max);
+
+  StructDef *LookupStruct(const std::string &id) const;
 
 private:
+  void Message(const std::string &msg);
+  void Warning(const std::string &msg);
   FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg);
   FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val);
   FLATBUFFERS_CHECKED_ERROR Next();
   FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark();
   bool Is(int t);
+  bool IsIdent(const char *id);
   FLATBUFFERS_CHECKED_ERROR Expect(int t);
   std::string TokenToStringId(int t);
   EnumDef *LookupEnum(const std::string &id);
@@ -540,18 +600,46 @@
                                      const std::string &name, const Type &type,
                                      FieldDef **dest);
   FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
+  FLATBUFFERS_CHECKED_ERROR ParseString(Value &val);
+  FLATBUFFERS_CHECKED_ERROR ParseComma();
   FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
                                           size_t parent_fieldn,
                                           const StructDef *parent_struct_def);
+  #if defined(FLATBUFFERS_CPP98_STL)
+    typedef CheckedError (*ParseTableDelimitersBody)(
+        const std::string &name, size_t &fieldn, const StructDef *struct_def,
+        void *state);
+  #else
+    typedef std::function<CheckedError(const std::string&, size_t&,
+                                       const StructDef*, void*)>
+            ParseTableDelimitersBody;
+  #endif  // defined(FLATBUFFERS_CPP98_STL)
+  FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn,
+                                                 const StructDef *struct_def,
+                                                 ParseTableDelimitersBody body,
+                                                 void *state);
   FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
                                        std::string *value, uoffset_t *ovalue);
   void SerializeStruct(const StructDef &struct_def, const Value &val);
   void AddVector(bool sortbysize, int count);
+  #if defined(FLATBUFFERS_CPP98_STL)
+    typedef CheckedError (*ParseVectorDelimitersBody)(size_t &count,
+                                                      void *state);
+  #else
+    typedef std::function<CheckedError(size_t&, void*)>
+            ParseVectorDelimitersBody;
+  #endif  // defined(FLATBUFFERS_CPP98_STL)
+  FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(
+      size_t &count, ParseVectorDelimitersBody body, void *state);
   FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue);
+  FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer(Value &val, FieldDef *field,
+                                                  size_t fieldn,
+                                                  const StructDef *parent_struct_def);
   FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes);
   FLATBUFFERS_CHECKED_ERROR TryTypedValue(int dtoken, bool check, Value &e,
                                           BaseType req, bool *destmatch);
   FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef* field);
+  FLATBUFFERS_CHECKED_ERROR TokenError();
   FLATBUFFERS_CHECKED_ERROR ParseSingleValue(Value &e);
   FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(Type &type, int64_t *result);
   StructDef *LookupCreateStruct(const std::string &name,
@@ -571,23 +659,32 @@
   FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent();
   FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type);
   FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue();
-  FLATBUFFERS_CHECKED_ERROR SkipJsonObject();
-  FLATBUFFERS_CHECKED_ERROR SkipJsonArray();
-  FLATBUFFERS_CHECKED_ERROR SkipJsonString();
-  FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
+  FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder);
+  FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source,
+                                           const char *source_filename);
+  FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source,
                                     const char **include_paths,
                                     const char *source_filename);
+  FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
+                                           const char **include_paths,
+                                           const char *source_filename,
+                                           const char *include_filename);
   FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
                                        StructDef *struct_def,
                                        const char *suffix,
                                        BaseType baseType);
 
+  bool SupportsVectorOfUnions() const;
+  Namespace *UniqueNamespace(Namespace *ns);
+
  public:
   SymbolTable<Type> types_;
   SymbolTable<StructDef> structs_;
   SymbolTable<EnumDef> enums_;
   SymbolTable<ServiceDef> services_;
   std::vector<Namespace *> namespaces_;
+  Namespace *current_namespace_;
+  Namespace *empty_namespace_;
   std::string error_;         // User readable error_ if Parse() == false
 
   FlatBufferBuilder builder_;  // any data contained in the file
@@ -595,13 +692,14 @@
   std::string file_identifier_;
   std::string file_extension_;
 
-  std::map<std::string, bool> included_files_;
+  std::map<std::string, std::string> included_files_;
   std::map<std::string, std::set<std::string>> files_included_per_file_;
   std::vector<std::string> native_included_files_;
 
   std::map<std::string, bool> known_attributes_;
 
   IDLOptions opts;
+  bool uses_flexbuffers_;
 
  private:
   const char *source_;
@@ -647,7 +745,7 @@
                         const std::string &path,
                         const std::string &file_name);
 
-// Generate JavaScript code from the definitions in the Parser object.
+// Generate JavaScript or TypeScript code from the definitions in the Parser object.
 // See idl_gen_js.
 extern std::string GenerateJS(const Parser &parser);
 extern bool GenerateJS(const Parser &parser,
@@ -678,6 +776,12 @@
                            const std::string &path,
                            const std::string &file_name);
 
+// Generate Json schema file
+// See idl_gen_json_schema.cpp.
+extern bool GenerateJsonSchema(const Parser &parser,
+                           const std::string &path,
+                           const std::string &file_name);
+
 // Generate C# files from the definitions in the Parser object.
 // See idl_gen_csharp.cpp.
 extern bool GenerateCSharp(const Parser &parser,
@@ -698,7 +802,7 @@
                         const std::string &path,
                         const std::string &file_name);
 
-// Generate a make rule for the generated JavaScript code.
+// Generate a make rule for the generated JavaScript or TypeScript code.
 // See idl_gen_js.cpp.
 extern std::string JSMakeRule(const Parser &parser,
                               const std::string &path,
@@ -743,4 +847,3 @@
 }  // namespace flatbuffers
 
 #endif  // FLATBUFFERS_IDL_H_
-
diff --git a/include/flatbuffers/minireflect.h b/include/flatbuffers/minireflect.h
new file mode 100644
index 0000000..cb3f403
--- /dev/null
+++ b/include/flatbuffers/minireflect.h
@@ -0,0 +1,352 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_MINIREFLECT_H_
+#define FLATBUFFERS_MINIREFLECT_H_
+
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/util.h"
+
+namespace flatbuffers {
+
+// Utilities that can be used with the "mini reflection" tables present
+// in generated code with --reflect-types (only types) or --reflect-names
+// (also names).
+// This allows basic reflection functionality such as pretty-printing
+// that does not require the use of the schema parser or loading of binary
+// schema files at runtime (reflection.h).
+
+// For any of the functions below that take `const TypeTable *`, you pass
+// `FooTypeTable()` if the type of the root is `Foo`.
+
+// First, a generic iterator that can be used by multiple algorithms.
+
+struct IterationVisitor {
+  // These mark the scope of a table or struct.
+  virtual void StartSequence() {}
+  virtual void EndSequence() {}
+  // Called for each field regardless of wether it is present or not.
+  // If not present, val == nullptr. set_idx is the index of all set fields.
+  virtual void Field(size_t /*field_idx*/, size_t /*set_idx*/,
+                     ElementaryType /*type*/, bool /*is_vector*/,
+                     const TypeTable * /*type_table*/, const char * /*name*/,
+                     const uint8_t * /*val*/) {}
+  // Called for a value that is actually present, after a field, or as part
+  // of a vector.
+  virtual void UType(uint8_t, const char *) {}
+  virtual void Bool(bool) {}
+  virtual void Char(int8_t, const char *) {}
+  virtual void UChar(uint8_t, const char *) {}
+  virtual void Short(int16_t, const char *) {}
+  virtual void UShort(uint16_t, const char *) {}
+  virtual void Int(int32_t, const char *) {}
+  virtual void UInt(uint32_t, const char *) {}
+  virtual void Long(int64_t) {}
+  virtual void ULong(uint64_t) {}
+  virtual void Float(float) {}
+  virtual void Double(double) {}
+  virtual void String(const String *) {}
+  virtual void Unknown(const uint8_t *) {}  // From a future version.
+  // These mark the scope of a vector.
+  virtual void StartVector() {}
+  virtual void EndVector() {}
+  virtual void Element(size_t /*i*/, ElementaryType /*type*/,
+                       const TypeTable * /*type_table*/,
+                       const uint8_t * /*val*/)
+  {}
+  virtual ~IterationVisitor() {}
+};
+
+inline size_t InlineSize(ElementaryType type, const TypeTable *type_table) {
+  switch (type) {
+    case ET_UTYPE:
+    case ET_BOOL:
+    case ET_CHAR:
+    case ET_UCHAR:
+      return 1;
+    case ET_SHORT:
+    case ET_USHORT:
+      return 2;
+    case ET_INT:
+    case ET_UINT:
+    case ET_FLOAT:
+    case ET_STRING:
+      return 4;
+    case ET_LONG:
+    case ET_ULONG:
+    case ET_DOUBLE:
+      return 8;
+    case ET_SEQUENCE:
+      switch (type_table->st) {
+        case ST_TABLE:
+        case ST_UNION:
+          return 4;
+        case ST_STRUCT:
+          return type_table->values[type_table->num_elems];
+        default:
+          assert(false);
+          return 1;
+      }
+    default:
+      assert(false);
+      return 1;
+  }
+}
+
+inline int32_t LookupEnum(int32_t enum_val, const int32_t *values,
+                          size_t num_values) {
+  if (!values) return enum_val;
+  for (size_t i = 0; i < num_values; i++) {
+    if (enum_val == values[i]) return static_cast<int32_t>(i);
+  }
+  return -1;  // Unknown enum value.
+}
+
+template<typename T> const char *EnumName(T tval, const TypeTable *type_table) {
+  if (!type_table || !type_table->names) return nullptr;
+  auto i = LookupEnum(static_cast<int32_t>(tval), type_table->values,
+                                  type_table->num_elems);
+  if (i >= 0 && i < static_cast<int32_t>(type_table->num_elems)) {
+    return type_table->names[i];
+  }
+  return nullptr;
+}
+
+void IterateObject(const uint8_t *obj, const TypeTable *type_table,
+                  IterationVisitor *visitor);
+
+inline void IterateValue(ElementaryType type, const uint8_t *val,
+                         const TypeTable *type_table,
+                         const uint8_t *prev_val,
+                         soffset_t vector_index,
+                         IterationVisitor *visitor) {
+  switch (type) {
+    case ET_UTYPE: {
+      auto tval = *reinterpret_cast<const uint8_t *>(val);
+      visitor->UType(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_BOOL: {
+      visitor->Bool(*reinterpret_cast<const uint8_t *>(val) != 0);
+      break;
+    }
+    case ET_CHAR: {
+      auto tval = *reinterpret_cast<const int8_t *>(val);
+      visitor->Char(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_UCHAR: {
+      auto tval = *reinterpret_cast<const uint8_t *>(val);
+      visitor->UChar(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_SHORT: {
+      auto tval = *reinterpret_cast<const int16_t *>(val);
+      visitor->Short(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_USHORT: {
+      auto tval = *reinterpret_cast<const uint16_t *>(val);
+      visitor->UShort(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_INT: {
+      auto tval = *reinterpret_cast<const int32_t *>(val);
+      visitor->Int(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_UINT: {
+      auto tval = *reinterpret_cast<const uint32_t *>(val);
+      visitor->UInt(tval, EnumName(tval, type_table));
+      break;
+    }
+    case ET_LONG: {
+      visitor->Long(*reinterpret_cast<const int64_t *>(val));
+      break;
+    }
+    case ET_ULONG: {
+      visitor->ULong(*reinterpret_cast<const uint64_t *>(val));
+      break;
+    }
+    case ET_FLOAT: {
+      visitor->Float(*reinterpret_cast<const float *>(val));
+      break;
+    }
+    case ET_DOUBLE: {
+      visitor->Double(*reinterpret_cast<const double *>(val));
+      break;
+    }
+    case ET_STRING: {
+      val += ReadScalar<uoffset_t>(val);
+      visitor->String(reinterpret_cast<const String *>(val));
+      break;
+    }
+    case ET_SEQUENCE: {
+      switch (type_table->st) {
+        case ST_TABLE:
+          val += ReadScalar<uoffset_t>(val);
+          IterateObject(val, type_table, visitor);
+          break;
+        case ST_STRUCT:
+          IterateObject(val, type_table, visitor);
+          break;
+        case ST_UNION: {
+          val += ReadScalar<uoffset_t>(val);
+          assert(prev_val);
+          auto union_type = *prev_val;  // Always a uint8_t.
+          if (vector_index >= 0) {
+            auto type_vec = reinterpret_cast<const Vector<uint8_t> *>(prev_val);
+            union_type = type_vec->Get(static_cast<uoffset_t>(vector_index));
+          }
+          auto type_code_idx = LookupEnum(union_type, type_table->values,
+                                          type_table->num_elems);
+          if (type_code_idx >= 0 && type_code_idx <
+              static_cast<int32_t>(type_table->num_elems)) {
+            auto type_code = type_table->type_codes[type_code_idx];
+            switch (type_code.base_type) {
+              case ET_SEQUENCE: {
+                auto ref = type_table->type_refs[type_code.sequence_ref]();
+                IterateObject(val, ref, visitor);
+                break;
+              }
+              case ET_STRING:
+                visitor->String(reinterpret_cast<const String *>(val));
+                break;
+              default:
+                visitor->Unknown(val);
+            }
+          } else {
+            visitor->Unknown(val);
+          }
+          break;
+        }
+        case ST_ENUM:
+          assert(false);
+          break;
+      }
+      break;
+    }
+    default: {
+      visitor->Unknown(val);
+      break;
+    }
+  }
+}
+
+inline void IterateObject(const uint8_t *obj, const TypeTable *type_table,
+                          IterationVisitor *visitor) {
+  visitor->StartSequence();
+  const uint8_t *prev_val = nullptr;
+  size_t set_idx = 0;
+  for (size_t i = 0; i < type_table->num_elems; i++) {
+    auto type_code = type_table->type_codes[i];
+    auto type = static_cast<ElementaryType>(type_code.base_type);
+    auto is_vector = type_code.is_vector != 0;
+    auto ref_idx = type_code.sequence_ref;
+    const TypeTable *ref = nullptr;
+    if (ref_idx >= 0) {
+      ref = type_table->type_refs[ref_idx]();
+    }
+    auto name = type_table->names ? type_table->names[i] : nullptr;
+    const uint8_t *val = nullptr;
+    if (type_table->st == ST_TABLE) {
+      val = reinterpret_cast<const Table *>(obj)->GetAddressOf(
+              FieldIndexToOffset(static_cast<voffset_t>(i)));
+    } else {
+      val = obj + type_table->values[i];
+    }
+    visitor->Field(i, set_idx, type, is_vector, ref, name, val);
+    if (val) {
+      set_idx++;
+      if (is_vector) {
+        val += ReadScalar<uoffset_t>(val);
+        auto vec = reinterpret_cast<const Vector<uint8_t> *>(val);
+        visitor->StartVector();
+        auto elem_ptr = vec->Data();
+        for (size_t j = 0; j < vec->size(); j++) {
+          visitor->Element(j, type, ref, elem_ptr);
+          IterateValue(type, elem_ptr, ref, prev_val, static_cast<soffset_t>(j),
+                       visitor);
+          elem_ptr += InlineSize(type, ref);
+        }
+        visitor->EndVector();
+      } else {
+        IterateValue(type, val, ref, prev_val, -1, visitor);
+      }
+    }
+    prev_val = val;
+  }
+  visitor->EndSequence();
+}
+
+inline void IterateFlatBuffer(const uint8_t *buffer,
+                              const TypeTable *type_table,
+                              IterationVisitor *callback) {
+  IterateObject(GetRoot<uint8_t>(buffer), type_table, callback);
+}
+
+// Outputting a Flatbuffer to a string. Tries to conform as close to JSON /
+// the output generated by idl_gen_text.cpp.
+
+struct ToStringVisitor : public IterationVisitor {
+  std::string s;
+  void StartSequence() { s += "{ "; }
+  void EndSequence() { s += " }"; }
+  void Field(size_t /*field_idx*/, size_t set_idx, ElementaryType /*type*/,
+             bool /*is_vector*/, const TypeTable * /*type_table*/,
+             const char *name, const uint8_t *val) {
+    if (!val) return;
+    if (set_idx) s += ", ";
+    if (name) { s += name; s += ": "; }
+  }
+  template<typename T> void Named(T x, const char *name) {
+    if (name) s+= name;
+    else s+= NumToString(x);
+  }
+  void UType(uint8_t x, const char *name) { Named(x, name); }
+  void Bool(bool x) { s+= x ? "true" : "false"; }
+  void Char(int8_t x, const char *name) { Named(x, name); }
+  void UChar(uint8_t x, const char *name) { Named(x, name); }
+  void Short(int16_t x, const char *name) { Named(x, name); }
+  void UShort(uint16_t x, const char *name) { Named(x, name); }
+  void Int(int32_t x, const char *name) { Named(x, name); }
+  void UInt(uint32_t x, const char *name) { Named(x, name); }
+  void Long(int64_t x) { s+= NumToString(x); }
+  void ULong(uint64_t x) { s+= NumToString(x); }
+  void Float(float x) { s+= NumToString(x); }
+  void Double(double x) { s+= NumToString(x); }
+  void String(const struct String *str) {
+    EscapeString(str->c_str(), str->size(), &s, true);
+  }
+  void Unknown(const uint8_t *) { s += "(?)"; }
+  void StartVector() { s += "[ "; }
+  void EndVector() { s += " ]"; }
+  void Element(size_t i, ElementaryType /*type*/,
+               const TypeTable * /*type_table*/, const uint8_t * /*val*/) {
+    if (i) s += ", ";
+  }
+};
+
+inline std::string FlatBufferToString(const uint8_t *buffer,
+                                      const TypeTable *type_table) {
+  ToStringVisitor tostring_visitor;
+  IterateFlatBuffer(buffer, type_table, &tostring_visitor);
+  return tostring_visitor.s;
+}
+
+}  // namespace flatbuffers
+
+#endif  // FLATBUFFERS_MINIREFLECT_H_
diff --git a/include/flatbuffers/reflection.h b/include/flatbuffers/reflection.h
index 6d8608a..ad5c456 100644
--- a/include/flatbuffers/reflection.h
+++ b/include/flatbuffers/reflection.h
@@ -30,6 +30,15 @@
 
 // ------------------------- GETTERS -------------------------
 
+inline bool IsScalar (reflection::BaseType t) { return t >= reflection::UType &&
+                                                       t <= reflection::Double; }
+inline bool IsInteger(reflection::BaseType t) { return t >= reflection::UType &&
+                                                       t <= reflection::ULong; }
+inline bool IsFloat  (reflection::BaseType t) { return t == reflection::Float ||
+                                                       t == reflection::Double; }
+inline bool IsLong   (reflection::BaseType t) { return t == reflection::Long ||
+                                                       t == reflection::ULong; }
+
 // Size of a basic type, don't use with structs.
 inline size_t GetTypeSize(reflection::BaseType base_type) {
   // This needs to correspond to the BaseType enum.
@@ -58,6 +67,18 @@
   return GetRoot<Table>(flatbuf);
 }
 
+// Get a field's default, if you know it's an integer, and its exact type.
+template<typename T> T GetFieldDefaultI(const reflection::Field &field) {
+  assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
+  return static_cast<T>(field.default_integer());
+}
+
+// Get a field's default, if you know it's floating point and its exact type.
+template<typename T> T GetFieldDefaultF(const reflection::Field &field) {
+  assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
+  return static_cast<T>(field.default_real());
+}
+
 // Get a field, if you know it's an integer, and its exact type.
 template<typename T> T GetFieldI(const Table &table,
                                  const reflection::Field &field) {
@@ -242,8 +263,19 @@
 // Set any scalar field, if you know its exact type.
 template<typename T> bool SetField(Table *table, const reflection::Field &field,
                                    T val) {
-  assert(sizeof(T) == GetTypeSize(field.type()->base_type()));
-  return table->SetField(field.offset(), val);
+  reflection::BaseType type = field.type()->base_type();
+  if (!IsScalar(type)) {
+    return false;
+  }
+  assert(sizeof(T) == GetTypeSize(type));
+  T def;
+  if (IsInteger(type)) {
+    def = GetFieldDefaultI<T>(field);
+  } else {
+    assert(IsFloat(type));
+    def = GetFieldDefaultF<T>(field);
+  }
+  return table->SetField(field.offset(), val, def);
 }
 
 // Raw helper functions used below: set any value in memory as a 64bit int, a
@@ -258,7 +290,7 @@
 inline bool SetAnyFieldI(Table *table, const reflection::Field &field,
                          int64_t val) {
   auto field_ptr = table->GetAddressOf(field.offset());
-  if (!field_ptr) return false;
+  if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field);
   SetAnyValueI(field.type()->base_type(), field_ptr, val);
   return true;
 }
@@ -267,7 +299,7 @@
 inline bool SetAnyFieldF(Table *table, const reflection::Field &field,
                          double val) {
   auto field_ptr = table->GetAddressOf(field.offset());
-  if (!field_ptr) return false;
+  if (!field_ptr) return val == GetFieldDefaultF<double>(field);
   SetAnyValueF(field.type()->base_type(), field_ptr, val);
   return true;
 }
@@ -329,12 +361,13 @@
  public:
   pointer_inside_vector(T *ptr, std::vector<U> &vec)
     : offset_(reinterpret_cast<uint8_t *>(ptr) -
-              reinterpret_cast<uint8_t *>(vec.data())),
+              reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))),
       vec_(vec) {}
 
   T *operator*() const {
     return reinterpret_cast<T *>(
-             reinterpret_cast<uint8_t *>(vec_.data()) + offset_);
+             reinterpret_cast<uint8_t *>(
+               flatbuffers::vector_data(vec_)) + offset_);
   }
   T *operator->() const {
     return operator*();
@@ -386,7 +419,6 @@
                          uoffset_t elem_size, std::vector<uint8_t> *flatbuf,
                          const reflection::Object *root_table = nullptr);
 
-#ifndef FLATBUFFERS_CPP98_STL
 template <typename T>
 void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val,
                   const Vector<T> *vec, std::vector<uint8_t> *flatbuf,
@@ -400,7 +432,7 @@
   // Set new elements to "val".
   for (int i = 0; i < delta_elem; i++) {
     auto loc = newelems + i * sizeof(T);
-    auto is_scalar = std::is_scalar<T>::value;
+    auto is_scalar = flatbuffers::is_scalar<T>::value;
     if (is_scalar) {
       WriteScalar(loc, val);
     } else {  // struct
@@ -408,7 +440,6 @@
     }
   }
 }
-#endif
 
 // Adds any new data (in the form of a new FlatBuffer) to an existing
 // FlatBuffer. This can be used when any of the above methods are not
diff --git a/include/flatbuffers/reflection_generated.h b/include/flatbuffers/reflection_generated.h
index 8379dcf..3bbab11 100644
--- a/include/flatbuffers/reflection_generated.h
+++ b/include/flatbuffers/reflection_generated.h
@@ -42,6 +42,29 @@
   Union = 16
 };
 
+inline BaseType (&EnumValuesBaseType())[17] {
+  static BaseType values[] = {
+    None,
+    UType,
+    Bool,
+    Byte,
+    UByte,
+    Short,
+    UShort,
+    Int,
+    UInt,
+    Long,
+    ULong,
+    Float,
+    Double,
+    String,
+    Vector,
+    Obj,
+    Union
+  };
+  return values;
+}
+
 inline const char **EnumNamesBaseType() {
   static const char *names[] = {
     "None",
@@ -113,7 +136,7 @@
   }
   TypeBuilder &operator=(const TypeBuilder &);
   flatbuffers::Offset<Type> Finish() {
-    const auto end = fbb_.EndTable(start_, 3);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Type>(end);
     return o;
   }
@@ -150,9 +173,9 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_KEY) &&
+           VerifyOffsetRequired(verifier, VT_KEY) &&
            verifier.Verify(key()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_VALUE) &&
+           VerifyOffset(verifier, VT_VALUE) &&
            verifier.Verify(value()) &&
            verifier.EndTable();
   }
@@ -173,7 +196,7 @@
   }
   KeyValueBuilder &operator=(const KeyValueBuilder &);
   flatbuffers::Offset<KeyValue> Finish() {
-    const auto end = fbb_.EndTable(start_, 2);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<KeyValue>(end);
     fbb_.Required(o, KeyValue::VT_KEY);
     return o;
@@ -204,7 +227,8 @@
   enum {
     VT_NAME = 4,
     VT_VALUE = 6,
-    VT_OBJECT = 8
+    VT_OBJECT = 8,
+    VT_UNION_TYPE = 10
   };
   const flatbuffers::String *name() const {
     return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -228,13 +252,18 @@
   const Object *object() const {
     return GetPointer<const Object *>(VT_OBJECT);
   }
+  const Type *union_type() const {
+    return GetPointer<const Type *>(VT_UNION_TYPE);
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffsetRequired(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
            VerifyField<int64_t>(verifier, VT_VALUE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_OBJECT) &&
+           VerifyOffset(verifier, VT_OBJECT) &&
            verifier.VerifyTable(object()) &&
+           VerifyOffset(verifier, VT_UNION_TYPE) &&
+           verifier.VerifyTable(union_type()) &&
            verifier.EndTable();
   }
 };
@@ -251,13 +280,16 @@
   void add_object(flatbuffers::Offset<Object> object) {
     fbb_.AddOffset(EnumVal::VT_OBJECT, object);
   }
+  void add_union_type(flatbuffers::Offset<Type> union_type) {
+    fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type);
+  }
   EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   EnumValBuilder &operator=(const EnumValBuilder &);
   flatbuffers::Offset<EnumVal> Finish() {
-    const auto end = fbb_.EndTable(start_, 3);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<EnumVal>(end);
     fbb_.Required(o, EnumVal::VT_NAME);
     return o;
@@ -268,9 +300,11 @@
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<flatbuffers::String> name = 0,
     int64_t value = 0,
-    flatbuffers::Offset<Object> object = 0) {
+    flatbuffers::Offset<Object> object = 0,
+    flatbuffers::Offset<Type> union_type = 0) {
   EnumValBuilder builder_(_fbb);
   builder_.add_value(value);
+  builder_.add_union_type(union_type);
   builder_.add_object(object);
   builder_.add_name(name);
   return builder_.Finish();
@@ -280,12 +314,14 @@
     flatbuffers::FlatBufferBuilder &_fbb,
     const char *name = nullptr,
     int64_t value = 0,
-    flatbuffers::Offset<Object> object = 0) {
+    flatbuffers::Offset<Object> object = 0,
+    flatbuffers::Offset<Type> union_type = 0) {
   return reflection::CreateEnumVal(
       _fbb,
       name ? _fbb.CreateString(name) : 0,
       value,
-      object);
+      object,
+      union_type);
 }
 
 struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
@@ -323,18 +359,18 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffsetRequired(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_VALUES) &&
+           VerifyOffsetRequired(verifier, VT_VALUES) &&
            verifier.Verify(values()) &&
            verifier.VerifyVectorOfTables(values()) &&
            VerifyField<uint8_t>(verifier, VT_IS_UNION) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_UNDERLYING_TYPE) &&
+           VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) &&
            verifier.VerifyTable(underlying_type()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
+           VerifyOffset(verifier, VT_ATTRIBUTES) &&
            verifier.Verify(attributes()) &&
            verifier.VerifyVectorOfTables(attributes()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
+           VerifyOffset(verifier, VT_DOCUMENTATION) &&
            verifier.Verify(documentation()) &&
            verifier.VerifyVectorOfStrings(documentation()) &&
            verifier.EndTable();
@@ -368,7 +404,7 @@
   }
   EnumBuilder &operator=(const EnumBuilder &);
   flatbuffers::Offset<Enum> Finish() {
-    const auto end = fbb_.EndTable(start_, 6);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Enum>(end);
     fbb_.Required(o, Enum::VT_NAME);
     fbb_.Required(o, Enum::VT_VALUES);
@@ -468,9 +504,9 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffsetRequired(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_TYPE) &&
+           VerifyOffsetRequired(verifier, VT_TYPE) &&
            verifier.VerifyTable(type()) &&
            VerifyField<uint16_t>(verifier, VT_ID) &&
            VerifyField<uint16_t>(verifier, VT_OFFSET) &&
@@ -479,10 +515,10 @@
            VerifyField<uint8_t>(verifier, VT_DEPRECATED) &&
            VerifyField<uint8_t>(verifier, VT_REQUIRED) &&
            VerifyField<uint8_t>(verifier, VT_KEY) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
+           VerifyOffset(verifier, VT_ATTRIBUTES) &&
            verifier.Verify(attributes()) &&
            verifier.VerifyVectorOfTables(attributes()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
+           VerifyOffset(verifier, VT_DOCUMENTATION) &&
            verifier.Verify(documentation()) &&
            verifier.VerifyVectorOfStrings(documentation()) &&
            verifier.EndTable();
@@ -531,7 +567,7 @@
   }
   FieldBuilder &operator=(const FieldBuilder &);
   flatbuffers::Offset<Field> Finish() {
-    const auto end = fbb_.EndTable(start_, 11);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Field>(end);
     fbb_.Required(o, Field::VT_NAME);
     fbb_.Required(o, Field::VT_TYPE);
@@ -634,18 +670,18 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffsetRequired(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_FIELDS) &&
+           VerifyOffsetRequired(verifier, VT_FIELDS) &&
            verifier.Verify(fields()) &&
            verifier.VerifyVectorOfTables(fields()) &&
            VerifyField<uint8_t>(verifier, VT_IS_STRUCT) &&
            VerifyField<int32_t>(verifier, VT_MINALIGN) &&
            VerifyField<int32_t>(verifier, VT_BYTESIZE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ATTRIBUTES) &&
+           VerifyOffset(verifier, VT_ATTRIBUTES) &&
            verifier.Verify(attributes()) &&
            verifier.VerifyVectorOfTables(attributes()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_DOCUMENTATION) &&
+           VerifyOffset(verifier, VT_DOCUMENTATION) &&
            verifier.Verify(documentation()) &&
            verifier.VerifyVectorOfStrings(documentation()) &&
            verifier.EndTable();
@@ -682,7 +718,7 @@
   }
   ObjectBuilder &operator=(const ObjectBuilder &);
   flatbuffers::Offset<Object> Finish() {
-    const auto end = fbb_.EndTable(start_, 7);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Object>(end);
     fbb_.Required(o, Object::VT_NAME);
     fbb_.Required(o, Object::VT_FIELDS);
@@ -755,17 +791,17 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_OBJECTS) &&
+           VerifyOffsetRequired(verifier, VT_OBJECTS) &&
            verifier.Verify(objects()) &&
            verifier.VerifyVectorOfTables(objects()) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_ENUMS) &&
+           VerifyOffsetRequired(verifier, VT_ENUMS) &&
            verifier.Verify(enums()) &&
            verifier.VerifyVectorOfTables(enums()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_IDENT) &&
+           VerifyOffset(verifier, VT_FILE_IDENT) &&
            verifier.Verify(file_ident()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_FILE_EXT) &&
+           VerifyOffset(verifier, VT_FILE_EXT) &&
            verifier.Verify(file_ext()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ROOT_TABLE) &&
+           VerifyOffset(verifier, VT_ROOT_TABLE) &&
            verifier.VerifyTable(root_table()) &&
            verifier.EndTable();
   }
@@ -795,7 +831,7 @@
   }
   SchemaBuilder &operator=(const SchemaBuilder &);
   flatbuffers::Offset<Schema> Finish() {
-    const auto end = fbb_.EndTable(start_, 5);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Schema>(end);
     fbb_.Required(o, Schema::VT_OBJECTS);
     fbb_.Required(o, Schema::VT_ENUMS);
diff --git a/include/flatbuffers/registry.h b/include/flatbuffers/registry.h
new file mode 100644
index 0000000..35771c1
--- /dev/null
+++ b/include/flatbuffers/registry.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_REGISTRY_H_
+#define FLATBUFFERS_REGISTRY_H_
+
+#include "flatbuffers/idl.h"
+
+namespace flatbuffers {
+
+// Convenience class to easily parse or generate text for arbitrary FlatBuffers.
+// Simply pre-populate it with all schema filenames that may be in use, and
+// This class will look them up using the file_identifier declared in the
+// schema.
+class Registry {
+ public:
+  // Call this for all schemas that may be in use. The identifier has
+  // a function in the generated code, e.g. MonsterIdentifier().
+  void Register(const char *file_identifier, const char *schema_path) {
+    Schema schema;
+    schema.path_ = schema_path;
+    schemas_[file_identifier] = schema;
+  }
+
+  // Generate text from an arbitrary FlatBuffer by looking up its
+  // file_identifier in the registry.
+  bool FlatBufferToText(const uint8_t *flatbuf, size_t len,
+                        std::string *dest) {
+    // Get the identifier out of the buffer.
+    // If the buffer is truncated, exit.
+    if (len < sizeof(uoffset_t) +
+              FlatBufferBuilder::kFileIdentifierLength) {
+      lasterror_ = "buffer truncated";
+      return false;
+    }
+    std::string ident(reinterpret_cast<const char *>(flatbuf) +
+                        sizeof(uoffset_t),
+                      FlatBufferBuilder::kFileIdentifierLength);
+    // Load and parse the schema.
+    Parser parser;
+    if (!LoadSchema(ident, &parser)) return false;
+    // Now we're ready to generate text.
+    if (!GenerateText(parser, flatbuf, dest)) {
+      lasterror_ = "unable to generate text for FlatBuffer binary";
+      return false;
+    }
+    return true;
+  }
+
+  // Converts a binary buffer to text using one of the schemas in the registry,
+  // use the file_identifier to indicate which.
+  // If DetachedBuffer::data() is null then parsing failed.
+  DetachedBuffer TextToFlatBuffer(const char *text,
+                                  const char *file_identifier) {
+    // Load and parse the schema.
+    Parser parser;
+    if (!LoadSchema(file_identifier, &parser)) return DetachedBuffer();
+    // Parse the text.
+    if (!parser.Parse(text)) {
+      lasterror_ = parser.error_;
+      return DetachedBuffer();
+    }
+    // We have a valid FlatBuffer. Detach it from the builder and return.
+    return parser.builder_.ReleaseBufferPointer();
+  }
+
+  // Modify any parsing / output options used by the other functions.
+  void SetOptions(const IDLOptions &opts) { opts_ = opts; }
+
+  // If schemas used contain include statements, call this function for every
+  // directory the parser should search them for.
+  void AddIncludeDirectory(const char *path) {
+    include_paths_.push_back(path);
+  }
+
+  // Returns a human readable error if any of the above functions fail.
+  const std::string &GetLastError() { return lasterror_; }
+
+ private:
+   bool LoadSchema(const std::string &ident, Parser *parser) {
+     // Find the schema, if not, exit.
+     auto it = schemas_.find(ident);
+     if (it == schemas_.end()) {
+       // Don't attach the identifier, since it may not be human readable.
+       lasterror_ = "identifier for this buffer not in the registry";
+       return false;
+     }
+     auto &schema = it->second;
+     // Load the schema from disk. If not, exit.
+     std::string schematext;
+     if (!LoadFile(schema.path_.c_str(), false, &schematext)) {
+       lasterror_ = "could not load schema: " + schema.path_;
+       return false;
+     }
+     // Parse schema.
+     parser->opts = opts_;
+     if (!parser->Parse(schematext.c_str(), vector_data(include_paths_),
+                        schema.path_.c_str())) {
+       lasterror_ = parser->error_;
+       return false;
+     }
+     return true;
+   }
+
+  struct Schema {
+    std::string path_;
+    // TODO(wvo) optionally cache schema file or parsed schema here.
+  };
+
+  std::string lasterror_;
+  IDLOptions opts_;
+  std::vector<const char *> include_paths_;
+  std::map<std::string, Schema> schemas_;
+};
+
+}  // namespace flatbuffers
+
+#endif  // FLATBUFFERS_REGISTRY_H_
diff --git a/include/flatbuffers/stl_emulation.h b/include/flatbuffers/stl_emulation.h
new file mode 100644
index 0000000..bacb224
--- /dev/null
+++ b/include/flatbuffers/stl_emulation.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright 2017 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef FLATBUFFERS_STL_EMULATION_H_
+#define FLATBUFFERS_STL_EMULATION_H_
+
+#include <string>
+#include <type_traits>
+#include <vector>
+#include <memory>
+#include <limits>
+
+#if defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
+  #define FLATBUFFERS_CPP98_STL
+#endif  // defined(_STLPORT_VERSION) && !defined(FLATBUFFERS_CPP98_STL)
+
+#if defined(FLATBUFFERS_CPP98_STL)
+  #include <cctype>
+#endif  // defined(FLATBUFFERS_CPP98_STL)
+
+// This header provides backwards compatibility for C++98 STLs like stlport.
+namespace flatbuffers {
+
+// Retrieve ::back() from a string in a way that is compatible with pre C++11
+// STLs (e.g stlport).
+inline char string_back(const std::string &value) {
+  return value[value.length() - 1];
+}
+
+// Helper method that retrieves ::data() from a vector in a way that is
+// compatible with pre C++11 STLs (e.g stlport).
+template <typename T> inline T *vector_data(std::vector<T> &vector) {
+  // In some debug environments, operator[] does bounds checking, so &vector[0]
+  // can't be used.
+  return &(*vector.begin());
+}
+
+template <typename T> inline const T *vector_data(
+    const std::vector<T> &vector) {
+  return &(*vector.begin());
+}
+
+template <typename T, typename V>
+inline void vector_emplace_back(std::vector<T> *vector, V &&data) {
+  #if defined(FLATBUFFERS_CPP98_STL)
+    vector->push_back(data);
+  #else
+    vector->emplace_back(std::forward<V>(data));
+  #endif  // defined(FLATBUFFERS_CPP98_STL)
+}
+
+#ifndef FLATBUFFERS_CPP98_STL
+  #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+    template <typename T>
+    using numeric_limits = std::numeric_limits<T>;
+  #else
+    template <typename T> class numeric_limits :
+      public std::numeric_limits<T> {};
+  #endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+#else
+  template <typename T> class numeric_limits :
+      public std::numeric_limits<T> {};
+
+  template <> class numeric_limits<unsigned long long> {
+   public:
+    static unsigned long long min() { return 0ULL; }
+    static unsigned long long max() { return ~0ULL; }
+  };
+
+  template <> class numeric_limits<long long> {
+   public:
+    static long long min() {
+      return static_cast<long long>(1ULL << ((sizeof(long long) << 3) - 1));
+    }
+    static long long max() {
+      return static_cast<long long>(
+          (1ULL << ((sizeof(long long) << 3) - 1)) - 1);
+    }
+  };
+#endif  // FLATBUFFERS_CPP98_STL
+
+#if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+  #ifndef FLATBUFFERS_CPP98_STL
+    template <typename T> using is_scalar = std::is_scalar<T>;
+    template <typename T, typename U> using is_same = std::is_same<T,U>;
+    template <typename T> using is_floating_point = std::is_floating_point<T>;
+    template <typename T> using is_unsigned = std::is_unsigned<T>;
+  #else
+    // Map C++ TR1 templates defined by stlport.
+    template <typename T> using is_scalar = std::tr1::is_scalar<T>;
+    template <typename T, typename U> using is_same = std::tr1::is_same<T,U>;
+    template <typename T> using is_floating_point =
+        std::tr1::is_floating_point<T>;
+    template <typename T> using is_unsigned = std::tr1::is_unsigned<T>;
+  #endif  // !FLATBUFFERS_CPP98_STL
+#else
+  // MSVC 2010 doesn't support C++11 aliases.
+  template <typename T> struct is_scalar : public std::is_scalar<T> {};
+  template <typename T, typename U> struct is_same : public std::is_same<T,U> {};
+  template <typename T> struct is_floating_point :
+        public std::is_floating_point<T> {};
+  template <typename T> struct is_unsigned : public std::is_unsigned<T> {};
+#endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+
+#ifndef FLATBUFFERS_CPP98_STL
+  #if !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+    template <class T> using unique_ptr = std::unique_ptr<T>;
+  #else
+    // MSVC 2010 doesn't support C++11 aliases.
+    // We're manually "aliasing" the class here as we want to bring unique_ptr
+    // into the flatbuffers namespace.  We have unique_ptr in the flatbuffers
+    // namespace we have a completely independent implemenation (see below)
+    // for C++98 STL implementations.
+    template <class T> class unique_ptr : public std::unique_ptr<T> {
+     public:
+      unique_ptr() {}
+      explicit unique_ptr(T* p) : std::unique_ptr<T>(p) {}
+      unique_ptr(std::unique_ptr<T>&& u) { *this = std::move(u); }
+      unique_ptr(unique_ptr&& u) { *this = std::move(u); }
+      unique_ptr& operator=(std::unique_ptr<T>&& u) {
+        std::unique_ptr<T>::reset(u.release());
+        return *this;
+      }
+      unique_ptr& operator=(unique_ptr&& u) {
+        std::unique_ptr<T>::reset(u.release());
+        return *this;
+      }
+      unique_ptr& operator=(T* p) {
+        return std::unique_ptr<T>::operator=(p);
+      }
+    };
+  #endif  // !(defined(_MSC_VER) && _MSC_VER <= 1700 /* MSVC2012 */)
+#else
+  // Very limited implementation of unique_ptr.
+  // This is provided simply to allow the C++ code generated from the default
+  // settings to function in C++98 environments with no modifications.
+  template <class T> class unique_ptr {
+   public:
+    typedef T element_type;
+
+    unique_ptr() : ptr_(nullptr) {}
+    explicit unique_ptr(T* p) : ptr_(p) {}
+    unique_ptr(unique_ptr&& u) : ptr_(nullptr) { reset(u.release()); }
+    unique_ptr(const unique_ptr& u) : ptr_(nullptr) {
+      reset(const_cast<unique_ptr*>(&u)->release());
+    }
+    ~unique_ptr() { reset(); }
+
+    unique_ptr& operator=(const unique_ptr& u) {
+      reset(const_cast<unique_ptr*>(&u)->release());
+      return *this;
+    }
+
+    unique_ptr& operator=(unique_ptr&& u) {
+      reset(u.release());
+      return *this;
+    }
+
+    unique_ptr& operator=(T* p) {
+      reset(p);
+      return *this;
+    }
+
+    const T& operator*() const { return *ptr_; }
+    T* operator->() const { return ptr_; }
+    T* get() const noexcept { return ptr_; }
+    explicit operator bool() const { return ptr_ != nullptr; }
+
+    // modifiers
+    T* release() {
+      T* value = ptr_;
+      ptr_ = nullptr;
+      return value;
+    }
+
+    void reset(T* p = nullptr) {
+      T* value = ptr_;
+      ptr_ = p;
+      if (value) delete value;
+    }
+
+    void swap(unique_ptr& u) {
+      T* temp_ptr = ptr_;
+      ptr_ = u.ptr_;
+      u.ptr_ = temp_ptr;
+    }
+
+   private:
+    T* ptr_;
+  };
+
+  template <class T> bool operator==(const unique_ptr<T>& x,
+                                     const unique_ptr<T>& y) {
+    return x.get() == y.get();
+  }
+
+  template <class T, class D> bool operator==(const unique_ptr<T>& x,
+                                              const D* y) {
+    return static_cast<D*>(x.get()) == y;
+  }
+
+  template <class T> bool operator==(const unique_ptr<T>& x, intptr_t y) {
+    return reinterpret_cast<intptr_t>(x.get()) == y;
+  }
+#endif  // !FLATBUFFERS_CPP98_STL
+
+}  // namespace flatbuffers
+
+#endif  // FLATBUFFERS_STL_EMULATION_H_
diff --git a/include/flatbuffers/util.h b/include/flatbuffers/util.h
index 2bd0ae0..6b7b7bc 100644
--- a/include/flatbuffers/util.h
+++ b/include/flatbuffers/util.h
@@ -40,7 +40,8 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/base.h"
+
 
 namespace flatbuffers {
 
@@ -59,6 +60,20 @@
 template<> inline std::string NumToString<unsigned char>(unsigned char t) {
   return NumToString(static_cast<int>(t));
 }
+#if defined(FLATBUFFERS_CPP98_STL)
+  template <> inline std::string NumToString<long long>(long long t) {
+    char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2
+    snprintf(buf, sizeof(buf), "%lld", t);
+    return std::string(buf);
+  }
+
+  template <> inline std::string NumToString<unsigned long long>(
+      unsigned long long t) {
+    char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1
+    snprintf(buf, sizeof(buf), "%llu", t);
+    return std::string(buf);
+  }
+#endif  // defined(FLATBUFFERS_CPP98_STL)
 
 // Special versions for floats/doubles.
 template<> inline std::string NumToString<double>(double t) {
@@ -71,9 +86,8 @@
   // Sadly, std::fixed turns "1" into "1.00000", so here we undo that.
   auto p = s.find_last_not_of('0');
   if (p != std::string::npos) {
-    s.resize(p + 1);  // Strip trailing zeroes.
-    if (s[s.size() - 1] == '.')
-      s.erase(s.size() - 1, 1);  // Strip '.' if a whole number.
+    // Strip trailing zeroes. If it is a whole number, keep one zero.
+    s.resize(p + (s[p] == '.' ? 2 : 1));
   }
   return s;
 }
@@ -157,16 +171,20 @@
   return SaveFile(name, buf.c_str(), buf.size(), binary);
 }
 
-// Functionality for minimalistic portable path handling:
+// Functionality for minimalistic portable path handling.
 
-static const char kPosixPathSeparator = '/';
-#ifdef _WIN32
-static const char kPathSeparator = '\\';
+// The functions below behave correctly regardless of whether posix ('/') or
+// Windows ('/' or '\\') separators are used.
+
+// Any new separators inserted are always posix.
+
+// We internally store paths in posix format ('/'). Paths supplied
+// by the user should go through PosixPath to ensure correct behavior
+// on Windows when paths are string-compared.
+
+static const char kPathSeparator = '/';
+static const char kPathSeparatorWindows = '\\';
 static const char *PathSeparatorSet = "\\/";  // Intentionally no ':'
-#else
-static const char kPathSeparator = kPosixPathSeparator;
-static const char *PathSeparatorSet = "/";
-#endif // _WIN32
 
 // Returns the path with the extension, if any, removed.
 inline std::string StripExtension(const std::string &filepath) {
@@ -197,13 +215,25 @@
 inline std::string ConCatPathFileName(const std::string &path,
                                       const std::string &filename) {
   std::string filepath = path;
-  if (path.length() && path[path.size() - 1] != kPathSeparator &&
-                       path[path.size() - 1] != kPosixPathSeparator)
-    filepath += kPathSeparator;
+  if (filepath.length()) {
+    char filepath_last_character = string_back(filepath);
+    if (filepath_last_character == kPathSeparatorWindows) {
+      filepath_last_character = kPathSeparator;
+    } else if (filepath_last_character != kPathSeparator) {
+      filepath += kPathSeparator;
+    }
+  }
   filepath += filename;
   return filepath;
 }
 
+// Replaces any '\\' separators with '/'
+inline std::string PosixPath(const char *path) {
+  std::string p = path;
+  std::replace(p.begin(), p.end(), '\\', '/');
+  return p;
+}
+
 // This function ensure a directory exists, by recursively
 // creating dirs for any parts of the path that don't exist yet.
 inline void EnsureDirExists(const std::string &filepath) {
@@ -345,6 +375,72 @@
   return wrapped;
 }
 
+inline bool EscapeString(const char *s, size_t length, std::string *_text,
+                         bool allow_non_utf8) {
+  std::string &text = *_text;
+  text += "\"";
+  for (uoffset_t i = 0; i < length; i++) {
+    char c = s[i];
+    switch (c) {
+      case '\n': text += "\\n"; break;
+      case '\t': text += "\\t"; break;
+      case '\r': text += "\\r"; break;
+      case '\b': text += "\\b"; break;
+      case '\f': text += "\\f"; break;
+      case '\"': text += "\\\""; break;
+      case '\\': text += "\\\\"; break;
+      default:
+        if (c >= ' ' && c <= '~') {
+          text += c;
+        } else {
+          // Not printable ASCII data. Let's see if it's valid UTF-8 first:
+          const char *utf8 = s + i;
+          int ucc = FromUTF8(&utf8);
+          if (ucc < 0) {
+            if (allow_non_utf8) {
+              text += "\\x";
+              text += IntToStringHex(static_cast<uint8_t>(c), 2);
+            } else {
+              // There are two cases here:
+              //
+              // 1) We reached here by parsing an IDL file. In that case,
+              // we previously checked for non-UTF-8, so we shouldn't reach
+              // here.
+              //
+              // 2) We reached here by someone calling GenerateText()
+              // on a previously-serialized flatbuffer. The data might have
+              // non-UTF-8 Strings, or might be corrupt.
+              //
+              // In both cases, we have to give up and inform the caller
+              // they have no JSON.
+              return false;
+            }
+          } else {
+            if (ucc <= 0xFFFF) {
+              // Parses as Unicode within JSON's \uXXXX range, so use that.
+              text += "\\u";
+              text += IntToStringHex(ucc, 4);
+            } else if (ucc <= 0x10FFFF) {
+              // Encode Unicode SMP values to a surrogate pair using two \u escapes.
+              uint32_t base = ucc - 0x10000;
+              auto high_surrogate = (base >> 10) + 0xD800;
+              auto low_surrogate = (base & 0x03FF) + 0xDC00;
+              text += "\\u";
+              text += IntToStringHex(high_surrogate, 4);
+              text += "\\u";
+              text += IntToStringHex(low_surrogate, 4);
+            }
+            // Skip past characters recognized.
+            i = static_cast<uoffset_t>(utf8 - s - 1);
+          }
+        }
+        break;
+    }
+  }
+  text += "\"";
+  return true;
+}
+
 }  // namespace flatbuffers
 
 #endif  // FLATBUFFERS_UTIL_H_
diff --git a/java/com/google/flatbuffers/FlatBufferBuilder.java b/java/com/google/flatbuffers/FlatBufferBuilder.java
index fd4b729..0214fd2 100644
--- a/java/com/google/flatbuffers/FlatBufferBuilder.java
+++ b/java/com/google/flatbuffers/FlatBufferBuilder.java
@@ -18,13 +18,13 @@
 
 import static com.google.flatbuffers.Constants.*;
 
-import java.nio.CharBuffer;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.*;
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
 import java.util.Arrays;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
 import java.nio.charset.Charset;
 
 /// @file
@@ -52,22 +52,34 @@
     boolean force_defaults = false; // False omits default values from the serialized data.
     CharsetEncoder encoder = utf8charset.newEncoder();
     ByteBuffer dst;
+    ByteBufferFactory bb_factory;   // Factory for allocating the internal buffer
     /// @endcond
 
+    /**
+     * Start with a buffer of size `initial_size`, then grow as required.
+     *
+     * @param initial_size The initial size of the internal buffer to use.
+     * @param bb_factory The factory to be used for allocating the internal buffer
+     */
+    public FlatBufferBuilder(int initial_size, ByteBufferFactory bb_factory) {
+        if (initial_size <= 0) initial_size = 1;
+        space = initial_size;
+        this.bb_factory = bb_factory;
+        bb = bb_factory.newByteBuffer(initial_size);
+    }
+
    /**
     * Start with a buffer of size `initial_size`, then grow as required.
     *
     * @param initial_size The initial size of the internal buffer to use.
     */
     public FlatBufferBuilder(int initial_size) {
-        if (initial_size <= 0) initial_size = 1;
-        space = initial_size;
-        bb = newByteBuffer(initial_size);
+        this(initial_size, new HeapByteBufferFactory());
     }
 
-   /**
-    * Start with a buffer of 1KiB, then grow as required.
-    */
+    /**
+     * Start with a buffer of 1KiB, then grow as required.
+     */
     public FlatBufferBuilder() {
         this(1024);
     }
@@ -78,9 +90,22 @@
      * to call {@link #dataBuffer()} to obtain the resulting encoded message.
      *
      * @param existing_bb The byte buffer to reuse.
+     * @param bb_factory The factory to be used for allocating a new internal buffer if
+     *                   the existing buffer needs to grow
+     */
+    public FlatBufferBuilder(ByteBuffer existing_bb, ByteBufferFactory bb_factory) {
+        init(existing_bb, bb_factory);
+    }
+
+    /**
+     * Alternative constructor allowing reuse of {@link ByteBuffer}s.  The builder
+     * can still grow the buffer as necessary.  User classes should make sure
+     * to call {@link #dataBuffer()} to obtain the resulting encoded message.
+     *
+     * @param existing_bb The byte buffer to reuse.
      */
     public FlatBufferBuilder(ByteBuffer existing_bb) {
-        init(existing_bb);
+        init(existing_bb, new HeapByteBufferFactory());
     }
 
     /**
@@ -89,9 +114,12 @@
      * objects that have been allocated for temporary storage.
      *
      * @param existing_bb The byte buffer to reuse.
+     * @param bb_factory The factory to be used for allocating a new internal buffer if
+     *                   the existing buffer needs to grow
      * @return Returns `this`.
      */
-    public FlatBufferBuilder init(ByteBuffer existing_bb){
+    public FlatBufferBuilder init(ByteBuffer existing_bb, ByteBufferFactory bb_factory){
+        this.bb_factory = bb_factory;
         bb = existing_bb;
         bb.clear();
         bb.order(ByteOrder.LITTLE_ENDIAN);
@@ -106,17 +134,53 @@
         return this;
     }
 
-    /// @cond FLATBUFFERS_INTERNAL
     /**
-     * Create a `ByteBuffer` with a given capacity.
+     * An interface that provides a user of the FlatBufferBuilder class the ability to specify
+     * the method in which the internal buffer gets allocated. This allows for alternatives
+     * to the default behavior, which is to allocate memory for a new byte-array
+     * backed `ByteBuffer` array inside the JVM.
      *
-     * @param capacity The size of the `ByteBuffer` to allocate.
-     * @return Returns the new `ByteBuffer` that was allocated.
+     * The FlatBufferBuilder class contains the HeapByteBufferFactory class to
+     * preserve the default behavior in the event that the user does not provide
+     * their own implementation of this interface.
      */
-    static ByteBuffer newByteBuffer(int capacity) {
-        ByteBuffer newbb = ByteBuffer.allocate(capacity);
-        newbb.order(ByteOrder.LITTLE_ENDIAN);
-        return newbb;
+    public interface ByteBufferFactory {
+        /**
+         * Create a `ByteBuffer` with a given capacity.
+         *
+         * @param capacity The size of the `ByteBuffer` to allocate.
+         * @return Returns the new `ByteBuffer` that was allocated.
+         */
+        ByteBuffer newByteBuffer(int capacity);
+    }
+
+    /**
+     * An implementation of the ByteBufferFactory interface that is used when
+     * one is not provided by the user.
+     *
+     * Allocate memory for a new byte-array backed `ByteBuffer` array inside the JVM.
+     */
+    public static final class HeapByteBufferFactory implements ByteBufferFactory {
+        @Override
+        public ByteBuffer newByteBuffer(int capacity) {
+            return ByteBuffer.allocate(capacity).order(ByteOrder.LITTLE_ENDIAN);
+        }
+    }
+
+    /**
+     * Reset the FlatBufferBuilder by purging all data that it holds.
+     */
+    public void clear(){
+        space = bb.capacity();
+        bb.clear();
+        minalign = 1;
+        while(vtable_in_use > 0) vtable[--vtable_in_use] = 0;
+        vtable_in_use = 0;
+        nested = false;
+        finished = false;
+        object_start = 0;
+        num_vtables = 0;
+        vector_num_elems = 0;
     }
 
     /**
@@ -124,16 +188,17 @@
      * end of the new buffer (since we build the buffer backwards).
      *
      * @param bb The current buffer with the existing data.
+     * @param bb_factory The factory to be used for allocating the new internal buffer
      * @return A new byte buffer with the old data copied copied to it.  The data is
      * located at the end of the buffer.
      */
-    static ByteBuffer growByteBuffer(ByteBuffer bb) {
+    static ByteBuffer growByteBuffer(ByteBuffer bb, ByteBufferFactory bb_factory) {
         int old_buf_size = bb.capacity();
         if ((old_buf_size & 0xC0000000) != 0)  // Ensure we don't grow beyond what fits in an int.
             throw new AssertionError("FlatBuffers: cannot grow buffer beyond 2 gigabytes.");
         int new_buf_size = old_buf_size << 1;
         bb.position(0);
-        ByteBuffer nbb = newByteBuffer(new_buf_size);
+        ByteBuffer nbb = bb_factory.newByteBuffer(new_buf_size);
         nbb.position(new_buf_size - old_buf_size);
         nbb.put(bb);
         return nbb;
@@ -176,7 +241,7 @@
         // Reallocate the buffer if needed.
         while (space < align_size + size + additional_bytes) {
             int old_buf_size = bb.capacity();
-            bb = growByteBuffer(bb);
+            bb = growByteBuffer(bb, bb_factory);
             space += bb.capacity() - old_buf_size;
         }
         pad(align_size);
@@ -413,7 +478,7 @@
         obj.sortTables(offsets, bb);
         return createVectorOfTables(offsets);
     }
-	
+
    /**
     * Encode the string `s` in the buffer using UTF-8.  If {@code s} is
     * already a {@link CharBuffer}, this method is allocation free.
@@ -679,7 +744,11 @@
         addInt(0);
         int vtableloc = offset();
         // Write out the current vtable.
-        for (int i = vtable_in_use - 1; i >= 0 ; i--) {
+        int i = vtable_in_use - 1;
+        // Trim trailing zeroes.
+        for (; i >= 0 && vtable[i] == 0; i--) {}
+        int trimmed_size = i + 1;
+        for (; i >= 0 ; i--) {
             // Offset relative to the start of the table.
             short off = (short)(vtable[i] != 0 ? vtableloc - vtable[i] : 0);
             addShort(off);
@@ -687,12 +756,12 @@
 
         final int standard_fields = 2; // The fields below:
         addShort((short)(vtableloc - object_start));
-        addShort((short)((vtable_in_use + standard_fields) * SIZEOF_SHORT));
+        addShort((short)((trimmed_size + standard_fields) * SIZEOF_SHORT));
 
         // Search for an existing vtable that matches the current one.
         int existing_vtable = 0;
         outer_loop:
-        for (int i = 0; i < num_vtables; i++) {
+        for (i = 0; i < num_vtables; i++) {
             int vt1 = bb.capacity() - vtables[i];
             int vt2 = space;
             short len = bb.getShort(vt1);
@@ -837,6 +906,41 @@
     public byte[] sizedByteArray() {
         return sizedByteArray(space, bb.capacity() - space);
     }
+
+    /**
+     * A utility function to return an InputStream to the ByteBuffer data
+     *
+     * @return An InputStream that starts at the beginning of the ByteBuffer data
+     *         and can read to the end of it.
+     */
+    public InputStream sizedInputStream() {
+        finished();
+        ByteBuffer duplicate = bb.duplicate();
+        duplicate.position(space);
+        duplicate.limit(bb.capacity());
+        return new ByteBufferBackedInputStream(duplicate);
+    }
+
+    /**
+     * A class that allows a user to create an InputStream from a ByteBuffer.
+     */
+    static class ByteBufferBackedInputStream extends InputStream {
+
+        ByteBuffer buf;
+
+        public ByteBufferBackedInputStream(ByteBuffer buf) {
+            this.buf = buf;
+        }
+
+        public int read() throws IOException {
+            try {
+                return buf.get() & 0xFF;
+            } catch(BufferUnderflowException e) {
+                return -1;
+            }
+        }
+    }
+
 }
 
 /// @}
diff --git a/java/com/google/flatbuffers/Table.java b/java/com/google/flatbuffers/Table.java
index b853842..cc18d4f 100644
--- a/java/com/google/flatbuffers/Table.java
+++ b/java/com/google/flatbuffers/Table.java
@@ -68,7 +68,7 @@
   }
 
   protected static int __offset(int vtable_offset, int offset, ByteBuffer bb) {
-    int vtable = bb.array().length - offset;
+    int vtable = bb.capacity() - offset;
     return bb.getShort(vtable + vtable_offset - bb.getInt(vtable)) + vtable;
   }
 
@@ -245,10 +245,9 @@
     int startPos_1 = offset_1 + SIZEOF_INT;
     int startPos_2 = offset_2 + SIZEOF_INT;
     int len = Math.min(len_1, len_2);
-    byte[] bbArray = bb.array();
     for(int i = 0; i < len; i++) {
-      if (bbArray[i + startPos_1] != bbArray[i + startPos_2])
-        return bbArray[i + startPos_1] - bbArray[i + startPos_2];
+      if (bb.get(i + startPos_1) != bb.get(i + startPos_2))
+        return bb.get(i + startPos_1) - bb.get(i + startPos_2);
     }
     return len_1 - len_2;
   }
@@ -266,10 +265,9 @@
     int len_2 = key.length;
     int startPos_1 = offset_1 + Constants.SIZEOF_INT;
     int len = Math.min(len_1, len_2);
-    byte[] bbArray = bb.array();
     for (int i = 0; i < len; i++) {
-      if (bbArray[i + startPos_1] != key[i])
-        return bbArray[i + startPos_1] - key[i];
+      if (bb.get(i + startPos_1) != key[i])
+        return bb.get(i + startPos_1) - key[i];
     }
     return len_1 - len_2;
   }
diff --git a/js/flatbuffers.js b/js/flatbuffers.js
index 3ea1adf..4c2bf52 100644
--- a/js/flatbuffers.js
+++ b/js/flatbuffers.js
@@ -115,7 +115,7 @@
  * @returns {number}
  */
 flatbuffers.Long.prototype.toFloat64 = function() {
-  return this.low + this.high * 0x100000000;
+  return (this.low >>> 0) + this.high * 0x100000000;
 };
 
 /**
@@ -604,23 +604,28 @@
   this.addInt32(0);
   var vtableloc = this.offset();
 
+  // Trim trailing zeroes.
+  var i = this.vtable_in_use - 1;
+  for (; i >= 0 && this.vtable[i] == 0; i--) {}
+  var trimmed_size = i + 1;
+
   // Write out the current vtable.
-  for (var i = this.vtable_in_use - 1; i >= 0; i--) {
+  for (; i >= 0; i--) {
     // Offset relative to the start of the table.
     this.addInt16(this.vtable[i] != 0 ? vtableloc - this.vtable[i] : 0);
   }
 
   var standard_fields = 2; // The fields below:
   this.addInt16(vtableloc - this.object_start);
-  this.addInt16((this.vtable_in_use + standard_fields) * flatbuffers.SIZEOF_SHORT);
+  var len = (trimmed_size + standard_fields) * flatbuffers.SIZEOF_SHORT;
+  this.addInt16(len);
 
   // Search for an existing vtable that matches the current one.
   var existing_vtable = 0;
+  var vt1 = this.space;
 outer_loop:
-  for (var i = 0; i < this.vtables.length; i++) {
-    var vt1 = this.bb.capacity() - this.vtables[i];
-    var vt2 = this.space;
-    var len = this.bb.readInt16(vt1);
+  for (i = 0; i < this.vtables.length; i++) {
+    var vt2 = this.bb.capacity() - this.vtables[i];
     if (len == this.bb.readInt16(vt2)) {
       for (var j = flatbuffers.SIZEOF_SHORT; j < len; j += flatbuffers.SIZEOF_SHORT) {
         if (this.bb.readInt16(vt1 + j) != this.bb.readInt16(vt2 + j)) {
@@ -944,9 +949,17 @@
 
 /**
  * @param {number} offset
- * @param {number} value
+ * @param {number|boolean} value
  */
 flatbuffers.ByteBuffer.prototype.writeInt8 = function(offset, value) {
+  this.bytes_[offset] = /** @type {number} */(value);
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint8 = function(offset, value) {
   this.bytes_[offset] = value;
 };
 
@@ -963,6 +976,15 @@
  * @param {number} offset
  * @param {number} value
  */
+flatbuffers.ByteBuffer.prototype.writeUint16 = function(offset, value) {
+    this.bytes_[offset] = value;
+    this.bytes_[offset + 1] = value >> 8;
+};
+
+/**
+ * @param {number} offset
+ * @param {number} value
+ */
 flatbuffers.ByteBuffer.prototype.writeInt32 = function(offset, value) {
   this.bytes_[offset] = value;
   this.bytes_[offset + 1] = value >> 8;
@@ -972,6 +994,17 @@
 
 /**
  * @param {number} offset
+ * @param {number} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint32 = function(offset, value) {
+    this.bytes_[offset] = value;
+    this.bytes_[offset + 1] = value >> 8;
+    this.bytes_[offset + 2] = value >> 16;
+    this.bytes_[offset + 3] = value >> 24;
+};
+
+/**
+ * @param {number} offset
  * @param {flatbuffers.Long} value
  */
 flatbuffers.ByteBuffer.prototype.writeInt64 = function(offset, value) {
@@ -981,6 +1014,15 @@
 
 /**
  * @param {number} offset
+ * @param {flatbuffers.Long} value
+ */
+flatbuffers.ByteBuffer.prototype.writeUint64 = function(offset, value) {
+    this.writeUint32(offset, value.low);
+    this.writeUint32(offset + 4, value.high);
+};
+
+/**
+ * @param {number} offset
  * @param {number} value
  */
 flatbuffers.ByteBuffer.prototype.writeFloat32 = function(offset, value) {
diff --git a/net/FlatBuffers/ByteBuffer.cs b/net/FlatBuffers/ByteBuffer.cs
old mode 100755
new mode 100644
diff --git a/net/FlatBuffers/FlatBufferBuilder.cs b/net/FlatBuffers/FlatBufferBuilder.cs
index b6701df..90627fd 100644
--- a/net/FlatBuffers/FlatBufferBuilder.cs
+++ b/net/FlatBuffers/FlatBufferBuilder.cs
@@ -500,7 +500,11 @@
             AddInt((int)0);
             var vtableloc = Offset;
             // Write out the current vtable.
-            for (int i = _vtableSize - 1; i >= 0 ; i--) {
+            int i = _vtableSize - 1;
+            // Trim trailing zeroes.
+            for (; i >= 0 && _vtable[i] == 0; i--) {}
+            int trimmedSize = i + 1;
+            for (; i >= 0 ; i--) {
                 // Offset relative to the start of the table.
                 short off = (short)(_vtable[i] != 0
                                         ? vtableloc - _vtable[i]
@@ -513,12 +517,12 @@
 
             const int standardFields = 2; // The fields below:
             AddShort((short)(vtableloc - _objectStart));
-            AddShort((short)((_vtableSize + standardFields) *
+            AddShort((short)((trimmedSize + standardFields) *
                              sizeof(short)));
 
             // Search for an existing vtable that matches the current one.
             int existingVtable = 0;
-            for (int i = 0; i < _numVtables; i++) {
+            for (i = 0; i < _numVtables; i++) {
                 int vt1 = _bb.Length - _vtables[i];
                 int vt2 = _space;
                 short len = _bb.GetShort(vt1);
diff --git a/package.json b/package.json
index 070d907..65169c0 100644
--- a/package.json
+++ b/package.json
@@ -1,15 +1,18 @@
 {
   "name": "flatbuffers",
-  "version": "1.6.0",
+  "version": "1.8.0",
   "description": "Memory Efficient Serialization Library",
-  "files": ["js/flatbuffers.js"],
-  "main": "js/flatbuffers.js",
+  "files": ["js/flatbuffers.js", "js/flatbuffers.mjs"],
+  "main": "js/flatbuffers",
+  "module": "js/flatbuffers.mjs",
   "directories": {
     "doc": "docs",
     "test": "tests"
   },
   "scripts": {
-    "test": "tests/JavaScriptTest.sh"
+    "test": "tests/JavaScriptTest.sh",
+    "append-esm-export": "sed \"s/this.flatbuffers = flatbuffers;/export { flatbuffers };/\" js/flatbuffers.js >> js/flatbuffers.mjs",
+    "prepublishOnly": "npm run append-esm-export"
   },
   "repository": {
     "type": "git",
diff --git a/php/FlatbufferBuilder.php b/php/FlatbufferBuilder.php
index 5c18bf4..925b438 100644
--- a/php/FlatbufferBuilder.php
+++ b/php/FlatbufferBuilder.php
@@ -596,7 +596,7 @@
         if (function_exists('mb_detect_encoding')) {
             return (bool) mb_detect_encoding($bytes, 'UTF-8', true);
         }
-    
+
         $len = strlen($bytes);
         if ($len < 1) {
             /* NOTE: always return 1 when passed string is null */
@@ -812,14 +812,18 @@
         $this->addInt(0);
         $vtableloc = $this->offset();
 
-        for ($i = $this->vtable_in_use -1; $i >= 0; $i--) {
+        $i = $this->vtable_in_use -1;
+        // Trim trailing zeroes.
+        for (; $i >= 0 && $this->vtable[$i] == 0; $i--) {}
+        $trimmed_size = $i + 1;
+        for (; $i >= 0; $i--) {
             $off = ($this->vtable[$i] != 0) ? $vtableloc - $this->vtable[$i] : 0;
             $this->addShort($off);
         }
 
         $standard_fields = 2; // the fields below
         $this->addShort($vtableloc - $this->object_start);
-        $this->addShort(($this->vtable_in_use + $standard_fields) * Constants::SIZEOF_SHORT);
+        $this->addShort(($trimmed_size + $standard_fields) * Constants::SIZEOF_SHORT);
 
         // search for an existing vtable that matches the current one.
         $existing_vtable = 0;
diff --git a/php/Struct.php b/php/Struct.php
index 94e712b..cd7652e 100644
--- a/php/Struct.php
+++ b/php/Struct.php
@@ -28,4 +28,14 @@
      * @var ByteBuffer $bb
      */
     protected $bb;
+
+    public function setByteBufferPos($pos)
+    {
+        $this->bb_pos = $pos;
+    }
+
+    public function setByteBuffer($bb)
+    {
+        $this->bb = $bb;
+    }
 }
diff --git a/php/Table.php b/php/Table.php
index 6f917c1..bf6fe21 100644
--- a/php/Table.php
+++ b/php/Table.php
@@ -32,6 +32,16 @@
     {
     }
 
+    public function setByteBufferPos($pos)
+    {
+        $this->bb_pos = $pos;
+    }
+
+    public function setByteBuffer($bb)
+    {
+        $this->bb = $bb;
+    }
+
     /**
      * returns actual vtable offset
      *
@@ -107,8 +117,8 @@
     protected function __union($table, $offset)
     {
         $offset += $this->bb_pos;
-        $table->bb_pos = $offset + $this->bb->getInt($offset);
-        $table->bb = $this->bb;
+        $table->setByteBufferPos($offset + $this->bb->getInt($offset));
+        $table->setByteBuffer($this->bb);
         return $table;
     }
 
diff --git a/pom.xml b/pom.xml
index a4f74bf..74de441 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,17 +5,20 @@
   <modelVersion>4.0.0</modelVersion>
   <groupId>com.google.flatbuffers</groupId>
   <artifactId>flatbuffers-java</artifactId>
-  <version>1.6.0-SNAPSHOT</version>
+  <version>1.8.0</version>
   <packaging>bundle</packaging>
   <name>FlatBuffers Java API</name>
   <description>
     Memory Efficient Serialization Library
   </description>
-
+  <developers>
+    <developer>
+      <name>Wouter van Oortmerssen</name>
+    </developer>
+  </developers>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>
-
   <url>https://github.com/google/flatbuffers</url>
   <licenses>
     <license>
@@ -32,6 +35,12 @@
   </scm>
   <dependencies>
   </dependencies>
+  <distributionManagement>
+    <snapshotRepository>
+      <id>ossrh</id>
+      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
+    </snapshotRepository>
+  </distributionManagement>
   <build>
     <sourceDirectory>java</sourceDirectory>
     <plugins>
@@ -84,6 +93,42 @@
         <version>3.0.1</version>
         <extensions>true</extensions>
       </plugin>
+      <plugin>
+        <groupId>org.sonatype.plugins</groupId>
+        <artifactId>nexus-staging-maven-plugin</artifactId>
+        <version>1.6.7</version>
+        <extensions>true</extensions>
+        <configuration>
+          <serverId>ossrh</serverId>
+          <nexusUrl>https://oss.sonatype.org/</nexusUrl>
+          <autoReleaseAfterClose>true</autoReleaseAfterClose>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-gpg-plugin</artifactId>
+        <version>1.5</version>
+        <executions>
+          <execution>
+            <id>sign-artifacts</id>
+            <phase>verify</phase>
+            <goals>
+              <goal>sign</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-release-plugin</artifactId>
+        <version>2.5.3</version>
+        <configuration>
+          <autoVersionSubmodules>true</autoVersionSubmodules>
+          <useReleaseProfile>false</useReleaseProfile>
+          <releaseProfiles>release</releaseProfiles>
+          <goals>deploy</goals>
+        </configuration>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py
index 552d0e2..a21f361 100644
--- a/python/flatbuffers/builder.py
+++ b/python/flatbuffers/builder.py
@@ -193,6 +193,10 @@
         objectOffset = self.Offset()
         existingVtable = None
 
+        # Trim trailing 0 offsets.
+        while self.current_vtable and self.current_vtable[-1] == 0:
+            self.current_vtable.pop()
+
         # Search backwards through existing vtables, because similar vtables
         # are likely to have been recently appended. See
         # BenchmarkVtableDeduplication for a case in which this heuristic
@@ -417,6 +421,27 @@
 
         return self.EndVector(len(x))
 
+    def CreateByteVector(self, x):
+        """CreateString writes a byte vector."""
+
+        self.assertNotNested()
+        ## @cond FLATBUFFERS_INTERNAL
+        self.nested = True
+        ## @endcond
+
+        if not isinstance(x, compat.binary_types):
+            raise TypeError("non-byte vector passed to CreateByteVector")
+
+        self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth)
+
+        l = UOffsetTFlags.py_type(len(x))
+        ## @cond FLATBUFFERS_INTERNAL
+        self.head = UOffsetTFlags.py_type(self.Head() - l)
+        ## @endcond
+        self.Bytes[self.Head():self.Head()+l] = x
+
+        return self.EndVector(len(x))
+
     ## @cond FLATBUFFERS_INTERNAL
     def assertNested(self):
         """
diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py
index e031535..2fc9cca 100644
--- a/python/flatbuffers/compat.py
+++ b/python/flatbuffers/compat.py
@@ -12,9 +12,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-""" A tiny version of `six` to help with backwards compability. """
+""" A tiny version of `six` to help with backwards compability. Also includes
+ compatibility helpers for numpy. """
 
 import sys
+import imp
 
 PY2 = sys.version_info[0] == 2
 PY26 = sys.version_info[0:2] == (2, 6)
@@ -43,4 +45,37 @@
         memoryview_type = memoryview
         struct_bool_decl = "?"
 
+# Helper functions to facilitate making numpy optional instead of required
+
+def import_numpy():
+    """
+    Returns the numpy module if it exists on the system,
+    otherwise returns None.
+    """
+    try:
+        imp.find_module('numpy')
+        numpy_exists = True
+    except ImportError:
+        numpy_exists = False
+
+    if numpy_exists:
+        # We do this outside of try/except block in case numpy exists
+        # but is not installed correctly. We do not want to catch an
+        # incorrect installation which would manifest as an
+        # ImportError.
+        import numpy as np
+    else:
+        np = None
+
+    return np
+
+
+class NumpyRequiredForThisFeature(RuntimeError):
+    """
+    Error raised when user tries to use a feature that
+    requires numpy without having numpy installed.
+    """
+    pass
+
+
 # NOTE: Future Jython support may require code here (look at `six`).
diff --git a/python/flatbuffers/encode.py b/python/flatbuffers/encode.py
index 1aa9230..3a330dd 100644
--- a/python/flatbuffers/encode.py
+++ b/python/flatbuffers/encode.py
@@ -15,13 +15,26 @@
 from . import number_types as N
 from . import packer
 from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
 
+np = import_numpy()
 
 def Get(packer_type, buf, head):
-    """ Get decodes a value at buf[head:] using `packer_type`. """
+    """ Get decodes a value at buf[head] using `packer_type`. """
     return packer_type.unpack_from(memoryview_type(buf), head)[0]
 
 
+def GetVectorAsNumpy(numpy_type, buf, count, offset):
+    """ GetVecAsNumpy decodes values starting at buf[head] as
+    `numpy_type`, where `numpy_type` is a numpy dtype. """
+    if np is not None:
+        # TODO: could set .flags.writeable = False to make users jump through
+        #       hoops before modifying...
+        return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
+
+
 def Write(packer_type, buf, head, n):
-    """ Write encodes `n` at buf[head:] using `packer_type`. """
+    """ Write encodes `n` at buf[head] using `packer_type`. """
     packer_type.pack_into(buf, head, n)
diff --git a/python/flatbuffers/number_types.py b/python/flatbuffers/number_types.py
index a9605de..47942ff 100644
--- a/python/flatbuffers/number_types.py
+++ b/python/flatbuffers/number_types.py
@@ -16,7 +16,9 @@
 import struct
 
 from . import packer
+from .compat import import_numpy, NumpyRequiredForThisFeature
 
+np = import_numpy()
 
 # For reference, see:
 # https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
@@ -170,3 +172,10 @@
     packed = struct.pack("<1Q", n)
     (unpacked,) = struct.unpack("<1d", packed)
     return unpacked
+
+
+def to_numpy_type(number_type):
+    if np is not None:
+        return np.dtype(number_type.name).newbyteorder('<')
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
diff --git a/python/flatbuffers/table.py b/python/flatbuffers/table.py
index 6cffe4c..adc76ca 100644
--- a/python/flatbuffers/table.py
+++ b/python/flatbuffers/table.py
@@ -101,6 +101,18 @@
             return d
         return self.Get(validator_flags, self.Pos + off)
 
+    def GetVectorAsNumpy(self, flags, off):
+        """
+        GetVectorAsNumpy returns the vector that starts at `Vector(off)`
+        as a numpy array with the type specified by `flags`. The array is
+        a `view` into Bytes, so modifying the returned array will
+        modify Bytes in place.
+        """
+        offset = self.Vector(off)
+        length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
+        numpy_dtype = N.to_numpy_type(flags)
+        return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
+
     def GetVOffsetTSlot(self, slot, d):
         """
         GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
diff --git a/readme.md b/readme.md
old mode 100755
new mode 100644
index 8d05c31..a7c0e93
--- a/readme.md
+++ b/readme.md
@@ -54,6 +54,6 @@
    [`flatbuffers` tag]: https://stackoverflow.com/questions/tagged/flatbuffers
    [FlatBuffers Google Group]: https://groups.google.com/forum/#!forum/flatbuffers
    [FlatBuffers Issues Tracker]: http://github.com/google/flatbuffers/issues
-   [stackoverflow.com]: http://www.stackoverflow.com
+   [stackoverflow.com]: http://stackoverflow.com/search?q=flatbuffers
    [landing page]: http://google.github.io/flatbuffers
    [LICENSE]: https://github.com/google/flatbuffers/blob/master/LICENSE.txt
diff --git a/reflection/reflection.fbs b/reflection/reflection.fbs
index 76ccf85..ea41891 100644
--- a/reflection/reflection.fbs
+++ b/reflection/reflection.fbs
@@ -42,7 +42,8 @@
 table EnumVal {
     name:string (required);
     value:long (key);
-    object:Object;  // Only if part of a union.
+    object:Object;  // Will be deprecated in favor of union_type in the future.
+    union_type:Type;
 }
 
 table Enum {
diff --git a/samples/SampleBinary.cs b/samples/SampleBinary.cs
index 16128c4..d07caf7 100644
--- a/samples/SampleBinary.cs
+++ b/samples/SampleBinary.cs
@@ -81,22 +81,19 @@
     Assert(monster.Color == Color.Red, "monster.Color", Convert.ToString(monster.Color),
            Convert.ToString(Color.Red));
 
-    // C# also allows you to use performance-enhanced methods to fill an object that has already
-    // been created. These functions are prefixed with "Get". For example: `monster.GetPos()`.
-    var myAlreadyCreatedVector = new Vec3();
-    monster.GetPos(myAlreadyCreatedVector); // Instead of `var myNewVec3 = monster.Pos`.
-    Assert(myAlreadyCreatedVector.X == 1.0f, "myAlreadyCreatedVector.X",
-           Convert.ToString(myAlreadyCreatedVector.X), Convert.ToString(1.0f));
-    Assert(myAlreadyCreatedVector.Y == 2.0f, "myAlreadyCreatedVector.Y",
-           Convert.ToString(myAlreadyCreatedVector.Y), Convert.ToString(2.0f));
-    Assert(myAlreadyCreatedVector.Z == 3.0f, "myAlreadyCreatedVector.Z",
-           Convert.ToString(myAlreadyCreatedVector.Z), Convert.ToString(3.0f));
+    var vec = monster.Pos.Value;
+    Assert(vec.X == 1.0f, "vec.X",
+           Convert.ToString(vec.X), Convert.ToString(1.0f));
+    Assert(vec.Y == 2.0f, "vec.Y",
+           Convert.ToString(vec.Y), Convert.ToString(2.0f));
+    Assert(vec.Z == 3.0f, "vec.Z",
+           Convert.ToString(vec.Z), Convert.ToString(3.0f));
 
     // Get and test the `Inventory` FlatBuffer `vector`.
     for (int i = 0; i < monster.InventoryLength; i++)
     {
-      Assert(monster.GetInventory(i) == i, "monster.GetInventory",
-             Convert.ToString(monster.GetInventory(i)), Convert.ToString(i));
+      Assert(monster.Inventory(i) == i, "monster.Inventory",
+             Convert.ToString(monster.Inventory(i)), Convert.ToString(i));
     }
 
     // Get and test the `Weapons` FlatBuffer `vector` of `table`s.
@@ -104,17 +101,17 @@
     var expectedWeaponDamages = new short[] {3, 5};
     for (int i = 0; i < monster.WeaponsLength; i++)
     {
-      Assert(monster.GetWeapons(i).Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
-             "monster.GetWeapons", monster.GetWeapons(i).Name, expectedWeaponNames[i]);
-      Assert(monster.GetWeapons(i).Damage == expectedWeaponDamages[i], "monster.GetWeapons",
-             Convert.ToString(monster.GetWeapons(i).Damage),
+      Assert(monster.Weapons(i).Value.Name.Equals(expectedWeaponNames[i], StringComparison.Ordinal),
+             "monster.Weapons", monster.Weapons(i).Value.Name, expectedWeaponNames[i]);
+      Assert(monster.Weapons(i).Value.Damage == expectedWeaponDamages[i], "monster.GetWeapons",
+             Convert.ToString(monster.Weapons(i).Value.Damage),
              Convert.ToString(expectedWeaponDamages[i]));
     }
 
     // Get and test the `Equipped` FlatBuffer `union`.
     Assert(monster.EquippedType == Equipment.Weapon, "monster.EquippedType",
            Convert.ToString(monster.EquippedType), Convert.ToString(Equipment.Weapon));
-    var equipped = (Weapon)monster.GetEquipped(new Weapon());
+    var equipped = monster.Equipped<Weapon>().Value;
     Assert(equipped.Name.Equals("Axe", StringComparison.Ordinal), "equipped.Name", equipped.Name,
            "Axe");
     Assert(equipped.Damage == 5, "equipped.Damage", Convert.ToString(equipped.Damage),
diff --git a/samples/android/AndroidManifest.xml b/samples/android/AndroidManifest.xml
old mode 100755
new mode 100644
index 0fa3dcf..352e0fa
--- a/samples/android/AndroidManifest.xml
+++ b/samples/android/AndroidManifest.xml
@@ -17,17 +17,14 @@
  -->
 <!-- BEGIN_INCLUDE(manifest) -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.samples.FlatBufferSample"
-        android:versionCode="1"
-        android:versionName="1.0">
+          package="com.samples.FlatBufferSample">
 
     <uses-feature android:glEsVersion="0x00020000"></uses-feature>
-    <!-- This is the platform API where NativeActivity was introduced. -->
-    <uses-sdk android:minSdkVersion="9" />
 
     <!-- This .apk has no Java code itself, so set hasCode to false. -->
-    <application android:label="@string/app_name" android:hasCode="false">
-
+    <application android:label="@string/app_name"
+                 android:hasCode="false"
+                 android:allowBackup="false">
         <!-- Our activity is the built-in NativeActivity framework class.
              This will take care of integrating with our NDK code. -->
         <activity android:name="android.app.NativeActivity"
diff --git a/samples/android/build.gradle b/samples/android/build.gradle
new file mode 100644
index 0000000..e6af6d6
--- /dev/null
+++ b/samples/android/build.gradle
@@ -0,0 +1,108 @@
+// Copyright (c) 2017 Google, Inc.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty.  In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+buildscript {
+  repositories {
+    jcenter()
+  }
+  dependencies {
+    classpath 'com.android.tools.build:gradle:2.3.0'
+  }
+}
+
+allprojects {
+  repositories {
+    jcenter()
+  }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+  compileSdkVersion 25
+  buildToolsVersion '25.0.2'
+
+  sourceSets {
+    main {
+      manifest.srcFile 'AndroidManifest.xml'
+      res.srcDirs = ['res']
+    }
+  }
+
+  externalNativeBuild {
+    ndkBuild {
+      path "jni/Android.mk"
+    }
+  }
+
+  defaultConfig {
+    applicationId 'com.samples.FlatBufferSample'
+    // This is the platform API where NativeActivity was introduced.
+    minSdkVersion 9
+    targetSdkVersion 25
+    versionCode 1
+    versionName "1.0"
+
+    buildTypes {
+      release {
+        minifyEnabled false
+      }
+    }
+
+    externalNativeBuild {
+      ndkBuild {
+        targets "FlatBufferSample"
+        arguments "-j" + Runtime.getRuntime().availableProcessors()
+        abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
+      }
+    }
+  }
+
+  lintOptions {
+    abortOnError false
+  }
+
+  // Build with each STL variant.
+  productFlavors {
+    stlport {
+      applicationIdSuffix ".stlport"
+      versionNameSuffix "-stlport"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=stlport_static"
+        }
+      }
+    }
+    gnustl {
+      applicationIdSuffix ".gnustl"
+      versionNameSuffix "-gnustl"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=gnustl_static"
+        }
+      }
+    }
+    libcpp {
+      applicationIdSuffix ".libcpp"
+      versionNameSuffix "-libcpp"
+      externalNativeBuild {
+        ndkBuild {
+          arguments "APP_STL=c++_static"
+        }
+      }
+    }
+  }
+}
diff --git a/samples/android/build_apk.sh b/samples/android/build_apk.sh
deleted file mode 100755
index 1b9f4a4..0000000
--- a/samples/android/build_apk.sh
+++ /dev/null
@@ -1,511 +0,0 @@
-#!/bin/bash -eu
-#
-# Copyright (c) 2013 Google, Inc.
-#
-# This software is provided 'as-is', without any express or implied
-# warranty.  In no event will the authors be held liable for any damages
-# arising from the use of this software.
-# Permission is granted to anyone to use this software for any purpose,
-# including commercial applications, and to alter it and redistribute it
-# freely, subject to the following restrictions:
-# 1. The origin of this software must not be misrepresented; you must not
-# claim that you wrote the original software. If you use this software
-# in a product, an acknowledgment in the product documentation would be
-# appreciated but is not required.
-# 2. Altered source versions must be plainly marked as such, and must not be
-# misrepresented as being the original software.
-# 3. This notice may not be removed or altered from any source distribution.
-#
-# Build, deploy, debug / execute a native Android package based upon
-# NativeActivity.
-
-declare -r script_directory=$(dirname $0)
-declare -r android_root=${script_directory}/../../../../../../
-declare -r script_name=$(basename $0)
-declare -r android_manifest=AndroidManifest.xml
-declare -r os_name=$(uname -s)
-
-# Minimum Android target version supported by this project.
-: ${BUILDAPK_ANDROID_TARGET_MINVERSION:=10}
-# Directory containing the Android SDK
-# (http://developer.android.com/sdk/index.html).
-: ${ANDROID_SDK_HOME:=}
-# Directory containing the Android NDK
-# (http://developer.android.com/tools/sdk/ndk/index.html).
-: ${NDK_HOME:=}
-
-# Display script help and exit.
-usage() {
-  echo "
-Build the Android package in the current directory and deploy it to a
-connected device.
-
-Usage: ${script_name} \\
-         [ADB_DEVICE=serial_number] [BUILD=0] [DEPLOY=0] [RUN_DEBUGGER=1] \
-         [LAUNCH=0] [SWIG_BIN=swig_binary_directory] [SWIG_LIB=swig_include_directory] [ndk-build arguments ...]
-
-ADB_DEVICE=serial_number:
-  serial_number specifies the device to deploy the built apk to if multiple
-  Android devices are connected to the host.
-BUILD=0:
-  Disables the build of the package.
-DEPLOY=0:
-  Disables the deployment of the built apk to the Android device.
-RUN_DEBUGGER=1:
-  Launches the application in gdb after it has been deployed.  To debug in
-  gdb, NDK_DEBUG=1 must also be specified on the command line to build a
-  debug apk.
-LAUNCH=0:
-  Disable the launch of the apk on the Android device.
-SWIG_BIN=swig_binary_directory:
-  The directory where the SWIG binary lives. No need to set this if SWIG is
-  installed and point to from your PATH variable.
-SWIG_LIB=swig_include_directory:
-  The directory where SWIG shared include files are, usually obtainable from
-  commandline with \"swig -swiglib\". No need to set this if SWIG is installed
-  and point to from your PATH variable.
-ndk-build arguments...:
-  Additional arguments for ndk-build.  See ndk-build -h for more information.
-" >&2
-  exit 1
-}
-
-# Get the number of CPU cores present on the host.
-get_number_of_cores() {
-  case ${os_name} in
-    Darwin)
-      sysctl hw.ncpu | awk '{ print $2 }'
-      ;;
-    CYGWIN*|Linux)
-      awk '/^processor/ { n=$3 } END { print n + 1 }' /proc/cpuinfo
-      ;;
-    *)
-      echo 1
-      ;;
-  esac
-}
-
-# Get the package name from an AndroidManifest.xml file.
-get_package_name_from_manifest() {
-  xmllint --xpath 'string(/manifest/@package)' "${1}"
-}
-
-# Get the library name from an AndroidManifest.xml file.
-get_library_name_from_manifest() {
-  echo "\
-setns android=http://schemas.android.com/apk/res/android
-xpath string(/manifest/application/activity\
-[@android:name=\"android.app.NativeActivity\"]/meta-data\
-[@android:name=\"android.app.lib_name\"]/@android:value)" |
-  xmllint --shell "${1}" | awk '/Object is a string/ { print $NF }'
-}
-
-# Get the number of Android devices connected to the system.
-get_number_of_devices_connected() {
-  adb devices -l | \
-    awk '/^..*$/ { if (p) { print $0 } }
-         /List of devices attached/ { p = 1 }' | \
-    wc -l
-  return ${PIPESTATUS[0]}
-}
-
-# Kill a process and its' children.  This is provided for cygwin which
-# doesn't ship with pkill.
-kill_process_group() {
-  local parent_pid="${1}"
-  local child_pid=
-  for child_pid in $(ps -f | \
-                     awk '{ if ($3 == '"${parent_pid}"') { print $2 } }'); do
-    kill_process_group "${child_pid}"
-  done
-  kill "${parent_pid}" 2>/dev/null
-}
-
-# Find and run "adb".
-adb() {
-  local adb_path=
-  for path in "$(which adb 2>/dev/null)" \
-              "${ANDROID_SDK_HOME}/sdk/platform-tools/adb" \
-              "${android_root}/prebuilts/sdk/platform-tools/adb"; do
-    if [[ -e "${path}" ]]; then
-      adb_path="${path}"
-      break
-    fi
-  done
-  if [[ "${adb_path}" == "" ]]; then
-    echo -e "Unable to find adb." \
-           "\nAdd the Android ADT sdk/platform-tools directory to the" \
-           "PATH." >&2
-    exit 1
-  fi
-  "${adb_path}" "$@"
-}
-
-# Find and run "android".
-android() {
-  local android_executable=android
-  if echo "${os_name}" | grep -q CYGWIN; then
-    android_executable=android.bat
-  fi
-  local android_path=
-  for path in "$(which ${android_executable})" \
-              "${ANDROID_SDK_HOME}/sdk/tools/${android_executable}" \
-              "${android_root}/prebuilts/sdk/tools/${android_executable}"; do
-    if [[ -e "${path}" ]]; then
-      android_path="${path}"
-      break
-    fi
-  done
-  if [[ "${android_path}" == "" ]]; then
-    echo -e "Unable to find android tool." \
-           "\nAdd the Android ADT sdk/tools directory to the PATH." >&2
-    exit 1
-  fi
-  # Make sure ant is installed.
-  if [[ "$(which ant)" == "" ]]; then
-    echo -e "Unable to find ant." \
-            "\nPlease install ant and add to the PATH." >&2
-    exit 1
-  fi
-
-  "${android_path}" "$@"
-}
-
-# Find and run "ndk-build"
-ndkbuild() {
-  local ndkbuild_path=
-  for path in "$(which ndk-build 2>/dev/null)" \
-              "${NDK_HOME}/ndk-build" \
-              "${android_root}/prebuilts/ndk/current/ndk-build"; do
-    if [[ -e "${path}" ]]; then
-      ndkbuild_path="${path}"
-      break
-    fi
-  done
-  if [[ "${ndkbuild_path}" == "" ]]; then
-    echo -e "Unable to find ndk-build." \
-            "\nAdd the Android NDK directory to the PATH." >&2
-    exit 1
-  fi
-  "${ndkbuild_path}" "$@"
-}
-
-# Get file modification time of $1 in seconds since the epoch.
-stat_mtime() {
-  local filename="${1}"
-  case ${os_name} in
-    Darwin) stat -f%m "${filename}" 2>/dev/null || echo 0 ;;
-    *) stat -c%Y "${filename}" 2>/dev/null || echo 0 ;;
-  esac
-}
-
-# Build the native (C/C++) build targets in the current directory.
-build_native_targets() {
-  # Save the list of output modules in the install directory so that it's
-  # possible to restore their timestamps after the build is complete.  This
-  # works around a bug in ndk/build/core/setup-app.mk which results in the
-  # unconditional execution of the clean-installed-binaries rule.
-  restore_libraries="$(find libs -type f 2>/dev/null | \
-                       sed -E 's@^libs/(.*)@\1@')"
-
-  # Build native code.
-  ndkbuild -j$(get_number_of_cores) "$@"
-
-  # Restore installed libraries.
-  # Obviously this is a nasty hack (along with ${restore_libraries} above) as
-  # it assumes it knows where the NDK will be placing output files.
-  (
-    IFS=$'\n'
-    for libpath in ${restore_libraries}; do
-      source_library="obj/local/${libpath}"
-      target_library="libs/${libpath}"
-      if [[ -e "${source_library}" ]]; then
-        cp -a "${source_library}" "${target_library}"
-      fi
-    done
-  )
-}
-
-# Select the oldest installed android build target that is at least as new as
-# BUILDAPK_ANDROID_TARGET_MINVERSION.  If a suitable build target isn't found,
-# this function prints an error message and exits with an error.
-select_android_build_target() {
-  local -r android_targets_installed=$( \
-    android list targets | \
-    awk -F'"' '/^id:.*android/ { print $2 }')
-  local android_build_target=
-  for android_target in $(echo "${android_targets_installed}" | \
-                          awk -F- '{ print $2 }' | sort -n); do
-    local isNumber='^[0-9]+$'
-    # skip preview API releases e.g. 'android-L'
-    if [[ $android_target =~ $isNumber ]]; then
-      if [[ $((android_target)) -ge \
-          $((BUILDAPK_ANDROID_TARGET_MINVERSION)) ]]; then
-        android_build_target="android-${android_target}"
-        break
-      fi
-    # else
-      # The API version is a letter, so skip it.
-    fi
-  done
-  if [[ "${android_build_target}" == "" ]]; then
-    echo -e \
-      "Found installed Android targets:" \
-      "$(echo ${android_targets_installed} | sed 's/ /\n  /g;s/^/\n  /;')" \
-      "\nAndroid SDK platform" \
-      "android-$((BUILDAPK_ANDROID_TARGET_MINVERSION))" \
-      "must be installed to build this project." \
-      "\nUse the \"android\" application to install API" \
-      "$((BUILDAPK_ANDROID_TARGET_MINVERSION)) or newer." >&2
-    exit 1
-  fi
-  echo "${android_build_target}"
-}
-
-# Sign unsigned apk $1 and write the result to $2 with key store file $3 and
-# password $4.
-# If a key store file $3 and password $4 aren't specified, a temporary
-# (60 day) key is generated and used to sign the package.
-sign_apk() {
-  local unsigned_apk="${1}"
-  local signed_apk="${2}"
-  if [[ $(stat_mtime "${unsigned_apk}") -gt \
-          $(stat_mtime "${signed_apk}") ]]; then
-    local -r key_alias=$(basename ${signed_apk} .apk)
-    local keystore="${3}"
-    local key_password="${4}"
-    [[ "${keystore}" == "" ]] && keystore="${unsigned_apk}.keystore"
-    [[ "${key_password}" == "" ]] && \
-      key_password="${key_alias}123456"
-    if [[ ! -e ${keystore} ]]; then
-      keytool -genkey -v -dname "cn=, ou=${key_alias}, o=fpl" \
-        -storepass ${key_password} \
-        -keypass ${key_password} -keystore ${keystore} \
-        -alias ${key_alias} -keyalg RSA -keysize 2048 -validity 60
-    fi
-    cp "${unsigned_apk}" "${signed_apk}"
-    jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
-      -keystore ${keystore} -storepass ${key_password} \
-      -keypass ${key_password} "${signed_apk}" ${key_alias}
-  fi
-}
-
-# Build the apk $1 for package filename $2 in the current directory using the
-# ant build target $3.
-build_apk() {
-  local -r output_apk="${1}"
-  local -r package_filename="${2}"
-  local -r ant_target="${3}"
-  # Get the list of installed android targets and select the oldest target
-  # that is at least as new as BUILDAPK_ANDROID_TARGET_MINVERSION.
-  local -r android_build_target=$(select_android_build_target)
-  [[ "${android_build_target}" == "" ]] && exit 1
-  echo "Building ${output_apk} for target ${android_build_target}" >&2
-
-  # Create / update build.xml and local.properties files.
-  if [[ $(stat_mtime "${android_manifest}") -gt \
-          $(stat_mtime build.xml) ]]; then
-    android update project --target "${android_build_target}" \
-                           -n ${package_filename} --path .
-  fi
-
-  # Use ant to build the apk.
-  ant -quiet ${ant_target}
-
-  # Sign release apks with a temporary key as these packages will not be
-  # redistributed.
-  local unsigned_apk="bin/${package_filename}-${ant_target}-unsigned.apk"
-  if [[ "${ant_target}" == "release" ]]; then
-    sign_apk "${unsigned_apk}" "${output_apk}" "" ""
-  fi
-}
-
-# Uninstall package $1 and install apk $2 on device $3 where $3 is "-s device"
-# or an empty string.  If $3 is an empty string adb will fail when multiple
-# devices are connected to the host system.
-install_apk() {
-  local -r uninstall_package_name="${1}"
-  local -r install_apk="${2}"
-  local -r adb_device="${3}"
-  # Uninstall the package if it's already installed.
-  adb ${adb_device} uninstall "${uninstall_package_name}" 1>&2 > /dev/null || \
-    true # no error check
-
-  # Install the apk.
-  # NOTE: The following works around adb not returning an error code when
-  # it fails to install an apk.
-  echo "Install ${install_apk}" >&2
-  local -r adb_install_result=$(adb ${adb_device} install "${install_apk}")
-  echo "${adb_install_result}"
-  if echo "${adb_install_result}" | grep -qF 'Failure ['; then
-    exit 1
-  fi
-}
-
-# Launch previously installed package $1 on device $2.
-# If $2 is an empty string adb will fail when multiple devices are connected
-# to the host system.
-launch_package() {
-  (
-    # Determine the SDK version of Android on the device.
-    local -r android_sdk_version=$(
-      adb ${adb_device} shell cat system/build.prop | \
-      awk -F= '/ro.build.version.sdk/ {
-                 v=$2; sub(/[ \r\n]/, "", v); print v
-               }')
-
-    # Clear logs from previous runs.
-    # Note that logcat does not just 'tail' the logs, it dumps the entire log
-    # history.
-    adb ${adb_device} logcat -c
-
-    local finished_msg='Displayed '"${package_name}"
-    local timeout_msg='Activity destroy timeout.*'"${package_name}"
-    # Maximum time to wait before stopping log monitoring.  0 = infinity.
-    local launch_timeout=0
-    # If this is a Gingerbread device, kill log monitoring after 10 seconds.
-    if [[ $((android_sdk_version)) -le 10 ]]; then
-      launch_timeout=10
-    fi
-    # Display logcat in the background.
-    # Stop displaying the log when the app launch / execution completes or the
-    # logcat
-    (
-      adb ${adb_device} logcat | \
-        awk "
-          {
-            print \$0
-          }
-
-          /ActivityManager.*: ${finished_msg}/ {
-            exit 0
-          }
-
-          /ActivityManager.*: ${timeout_msg}/ {
-            exit 0
-          }" &
-      adb_logcat_pid=$!;
-      if [[ $((launch_timeout)) -gt 0 ]]; then
-        sleep $((launch_timeout));
-        kill ${adb_logcat_pid};
-      else
-        wait ${adb_logcat_pid};
-      fi
-    ) &
-    logcat_pid=$!
-    # Kill adb logcat if this shell exits.
-    trap "kill_process_group ${logcat_pid}" SIGINT SIGTERM EXIT
-
-    # If the SDK is newer than 10, "am" supports stopping an activity.
-    adb_stop_activity=
-    if [[ $((android_sdk_version)) -gt 10 ]]; then
-      adb_stop_activity=-S
-    fi
-
-    # Launch the activity and wait for it to complete.
-    adb ${adb_device} shell am start ${adb_stop_activity} -n \
-      ${package_name}/android.app.NativeActivity
-
-    wait "${logcat_pid}"
-  )
-}
-
-# See usage().
-main() {
-  # Parse arguments for this script.
-  local adb_device=
-  local ant_target=release
-  local disable_deploy=0
-  local disable_build=0
-  local run_debugger=0
-  local launch=1
-  local build_package=1
-  for opt; do
-    case ${opt} in
-      # NDK_DEBUG=0 tells ndk-build to build this as debuggable but to not
-      # modify the underlying code whereas NDK_DEBUG=1 also builds as debuggable
-      # but does modify the code
-      NDK_DEBUG=1) ant_target=debug ;;
-      NDK_DEBUG=0) ant_target=debug ;;
-      ADB_DEVICE*) adb_device="$(\
-        echo "${opt}" | sed -E 's/^ADB_DEVICE=([^ ]+)$/-s \1/;t;s/.*//')" ;;
-      BUILD=0) disable_build=1 ;;
-      DEPLOY=0) disable_deploy=1 ;;
-      RUN_DEBUGGER=1) run_debugger=1 ;;
-      LAUNCH=0) launch=0 ;;
-      clean) build_package=0 disable_deploy=1 launch=0 ;;
-      -h|--help|help) usage ;;
-    esac
-  done
-
-  # If a target device hasn't been specified and multiple devices are connected
-  # to the host machine, display an error.
-  local -r devices_connected=$(get_number_of_devices_connected)
-  if [[ "${adb_device}" == "" && $((devices_connected)) -gt 1 && \
-        ($((disable_deploy)) -eq 0 || $((launch)) -ne 0 || \
-         $((run_debugger)) -ne 0) ]]; then
-    if [[ $((disable_deploy)) -ne 0 ]]; then
-      echo "Deployment enabled, disable using DEPLOY=0" >&2
-    fi
-    if [[ $((launch)) -ne 0 ]]; then
-     echo "Launch enabled." >&2
-    fi
-    if [[ $((disable_deploy)) -eq 0 ]]; then
-      echo "Deployment enabled." >&2
-    fi
-    if [[ $((run_debugger)) -ne 0 ]]; then
-      echo "Debugger launch enabled." >&2
-    fi
-    echo "
-Multiple Android devices are connected to this host.  Either disable deployment
-and execution of the built .apk using:
-  \"${script_name} DEPLOY=0 LAUNCH=0\"
-
-or specify a device to deploy to using:
-  \"${script_name} ADB_DEVICE=\${device_serial}\".
-
-The Android devices connected to this machine are:
-$(adb devices -l)
-" >&2
-    exit 1
-  fi
-
-  if [[ $((disable_build)) -eq 0 ]]; then
-    # Build the native target.
-    build_native_targets "$@"
-  fi
-
-  # Get the package name from the manifest.
-  local -r package_name=$(get_package_name_from_manifest "${android_manifest}")
-  if [[ "${package_name}" == "" ]]; then
-    echo -e "No package name specified in ${android_manifest},"\
-            "skipping apk build, deploy"
-            "\nand launch steps." >&2
-    exit 0
-  fi
-  local -r package_basename=${package_name/*./}
-  local package_filename=$(get_library_name_from_manifest ${android_manifest})
-  [[ "${package_filename}" == "" ]] && package_filename="${package_basename}"
-
-  # Output apk name.
-  local -r output_apk="bin/${package_filename}-${ant_target}.apk"
-
-  if [[ $((disable_build)) -eq 0 && $((build_package)) -eq 1 ]]; then
-    # Build the apk.
-    build_apk "${output_apk}" "${package_filename}" "${ant_target}"
-  fi
-
-  # Deploy to the device.
-  if [[ $((disable_deploy)) -eq 0 ]]; then
-    install_apk "${package_name}" "${output_apk}" "${adb_device}"
-  fi
-
-  if [[ "${ant_target}" == "debug" && $((run_debugger)) -eq 1 ]]; then
-    # Start debugging.
-    ndk-gdb ${adb_device} --start
-  elif [[ $((launch)) -eq 1 ]]; then
-    launch_package "${package_name}" "${adb_device}"
-  fi
-}
-
-main "$@"
diff --git a/samples/android/gradle/wrapper/gradle-wrapper.jar b/samples/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..b4163b8
--- /dev/null
+++ b/samples/android/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/samples/android/gradle/wrapper/gradle-wrapper.properties b/samples/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..1e1168c
--- /dev/null
+++ b/samples/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Mon Jun 19 11:54:59 PDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/samples/android/gradlew b/samples/android/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/samples/android/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+    echo "$*"
+}
+
+die () {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+  NONSTOP* )
+    nonstop=true
+    ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+    JAVACMD=`cygpath --unix "$JAVACMD"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Escape application args
+save () {
+    for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+    echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+  cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/samples/android/gradlew.bat b/samples/android/gradlew.bat
new file mode 100644
index 0000000..f955316
--- /dev/null
+++ b/samples/android/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem  Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/samples/android/jni/Android.mk b/samples/android/jni/Android.mk
old mode 100755
new mode 100644
index 6f22d28..917c2f9
--- a/samples/android/jni/Android.mk
+++ b/samples/android/jni/Android.mk
@@ -38,7 +38,7 @@
 LOCAL_SRC_FILES := main.cpp
 
 LOCAL_CPPFLAGS := -std=c++11 -fexceptions -Wall -Wno-literal-suffix
-LOCAL_LDLIBS := -llog -landroid
+LOCAL_LDLIBS := -llog -landroid -latomic
 LOCAL_ARM_MODE := arm
 LOCAL_STATIC_LIBRARIES := android_native_app_glue flatbuffers
 
diff --git a/samples/android/jni/Application.mk b/samples/android/jni/Application.mk
old mode 100755
new mode 100644
index 2fc9c73..ca9e800
--- a/samples/android/jni/Application.mk
+++ b/samples/android/jni/Application.mk
@@ -13,10 +13,8 @@
 # 2. Altered source versions must be plainly marked as such, and must not be
 # misrepresented as being the original software.
 # 3. This notice may not be removed or altered from any source distribution.
-APP_PLATFORM := android-10
+APP_PLATFORM := android-9
 APP_PROJECT_PATH := $(call my-dir)/..
-APP_STL := gnustl_static
-
+APP_STL ?= stlport_static
 APP_ABI := armeabi-v7a
-
 APP_CPPFLAGS += -std=c++11
diff --git a/samples/android/res/values/strings.xml b/samples/android/res/values/strings.xml
old mode 100755
new mode 100644
diff --git a/samples/android_sample.sh b/samples/android_sample.sh
index ead8fd8..53633ac 100755
--- a/samples/android_sample.sh
+++ b/samples/android_sample.sh
@@ -29,8 +29,7 @@
 
 # Execute `build_apk.sh` to build and run the android app.
 cd android
-./build_apk.sh
+./gradlew build
 
-# Cleanup the temporary files.
-rm build.xml local.properties proguard-project.txt project.properties
-rm -rf bin libs obj
+
+
diff --git a/samples/monster.fbs b/samples/monster.fbs
old mode 100755
new mode 100644
diff --git a/samples/monster_generated.h b/samples/monster_generated.h
index 4a12b0a..4c31d5e 100644
--- a/samples/monster_generated.h
+++ b/samples/monster_generated.h
@@ -25,6 +25,15 @@
   Color_MAX = Color_Blue
 };
 
+inline Color (&EnumValuesColor())[3] {
+  static Color values[] = {
+    Color_Red,
+    Color_Green,
+    Color_Blue
+  };
+  return values;
+}
+
 inline const char **EnumNamesColor() {
   static const char *names[] = {
     "Red",
@@ -47,6 +56,14 @@
   Equipment_MAX = Equipment_Weapon
 };
 
+inline Equipment (&EnumValuesEquipment())[2] {
+  static Equipment values[] = {
+    Equipment_NONE,
+    Equipment_Weapon
+  };
+  return values;
+}
+
 inline const char **EnumNamesEquipment() {
   static const char *names[] = {
     "NONE",
@@ -71,32 +88,42 @@
 
 struct EquipmentUnion {
   Equipment type;
-  flatbuffers::NativeTable *table;
+  void *value;
 
-  EquipmentUnion() : type(Equipment_NONE), table(nullptr) {}
-  EquipmentUnion(EquipmentUnion&& u):
-    type(std::move(u.type)), table(std::move(u.table)) {}
-  EquipmentUnion(const EquipmentUnion &);
-  EquipmentUnion &operator=(const EquipmentUnion &);
+  EquipmentUnion() : type(Equipment_NONE), value(nullptr) {}
+  EquipmentUnion(EquipmentUnion&& u) FLATBUFFERS_NOEXCEPT :
+    type(Equipment_NONE), value(nullptr)
+    { std::swap(type, u.type); std::swap(value, u.value); }
+  EquipmentUnion(const EquipmentUnion &) FLATBUFFERS_NOEXCEPT;
+  EquipmentUnion &operator=(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT
+    { EquipmentUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+  EquipmentUnion &operator=(EquipmentUnion &&u) FLATBUFFERS_NOEXCEPT
+    { std::swap(type, u.type); std::swap(value, u.value); return *this; }
   ~EquipmentUnion() { Reset(); }
 
   void Reset();
 
+#ifndef FLATBUFFERS_CPP98_STL
   template <typename T>
-  void Set(T&& value) {
+  void Set(T&& val) {
     Reset();
     type = EquipmentTraits<typename T::TableType>::enum_value;
     if (type != Equipment_NONE) {
-      table = new T(std::forward<T>(value));
+      value = new T(std::forward<T>(val));
     }
   }
+#endif  // FLATBUFFERS_CPP98_STL
 
-  static flatbuffers::NativeTable *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
+  static void *UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver);
   flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
 
   WeaponT *AsWeapon() {
     return type == Equipment_Weapon ?
-      reinterpret_cast<WeaponT *>(table) : nullptr;
+      reinterpret_cast<WeaponT *>(value) : nullptr;
+  }
+  const WeaponT *AsWeapon() const {
+    return type == Equipment_Weapon ?
+      reinterpret_cast<const WeaponT *>(value) : nullptr;
   }
 };
 
@@ -113,9 +140,6 @@
   Vec3() {
     memset(this, 0, sizeof(Vec3));
   }
-  Vec3(const Vec3 &_o) {
-    memcpy(this, &_o, sizeof(Vec3));
-  }
   Vec3(float _x, float _y, float _z)
       : x_(flatbuffers::EndianScalar(_x)),
         y_(flatbuffers::EndianScalar(_y)),
@@ -144,13 +168,13 @@
 
 struct MonsterT : public flatbuffers::NativeTable {
   typedef Monster TableType;
-  std::unique_ptr<Vec3> pos;
+  flatbuffers::unique_ptr<Vec3> pos;
   int16_t mana;
   int16_t hp;
   std::string name;
   std::vector<uint8_t> inventory;
   Color color;
-  std::vector<std::unique_ptr<WeaponT>> weapons;
+  std::vector<flatbuffers::unique_ptr<WeaponT>> weapons;
   EquipmentUnion equipped;
   MonsterT()
       : mana(150),
@@ -182,13 +206,13 @@
     return GetField<int16_t>(VT_MANA, 150);
   }
   bool mutate_mana(int16_t _mana) {
-    return SetField(VT_MANA, _mana);
+    return SetField<int16_t>(VT_MANA, _mana, 150);
   }
   int16_t hp() const {
     return GetField<int16_t>(VT_HP, 100);
   }
   bool mutate_hp(int16_t _hp) {
-    return SetField(VT_HP, _hp);
+    return SetField<int16_t>(VT_HP, _hp, 100);
   }
   const flatbuffers::String *name() const {
     return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -206,7 +230,7 @@
     return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
   }
   bool mutate_color(Color _color) {
-    return SetField(VT_COLOR, static_cast<int8_t>(_color));
+    return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
   }
   const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *weapons() const {
     return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<Weapon>> *>(VT_WEAPONS);
@@ -218,11 +242,15 @@
     return static_cast<Equipment>(GetField<uint8_t>(VT_EQUIPPED_TYPE, 0));
   }
   bool mutate_equipped_type(Equipment _equipped_type) {
-    return SetField(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type));
+    return SetField<uint8_t>(VT_EQUIPPED_TYPE, static_cast<uint8_t>(_equipped_type), 0);
   }
   const void *equipped() const {
     return GetPointer<const void *>(VT_EQUIPPED);
   }
+  template<typename T> const T *equipped_as() const;
+  const Weapon *equipped_as_Weapon() const {
+    return equipped_type() == Equipment_Weapon ? static_cast<const Weapon *>(equipped()) : nullptr;
+  }
   void *mutable_equipped() {
     return GetPointer<void *>(VT_EQUIPPED);
   }
@@ -231,16 +259,16 @@
            VerifyField<Vec3>(verifier, VT_POS) &&
            VerifyField<int16_t>(verifier, VT_MANA) &&
            VerifyField<int16_t>(verifier, VT_HP) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffset(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) &&
+           VerifyOffset(verifier, VT_INVENTORY) &&
            verifier.Verify(inventory()) &&
            VerifyField<int8_t>(verifier, VT_COLOR) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_WEAPONS) &&
+           VerifyOffset(verifier, VT_WEAPONS) &&
            verifier.Verify(weapons()) &&
            verifier.VerifyVectorOfTables(weapons()) &&
            VerifyField<uint8_t>(verifier, VT_EQUIPPED_TYPE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_EQUIPPED) &&
+           VerifyOffset(verifier, VT_EQUIPPED) &&
            VerifyEquipment(verifier, equipped(), equipped_type()) &&
            verifier.EndTable();
   }
@@ -249,6 +277,10 @@
   static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 };
 
+template<> inline const Weapon *Monster::equipped_as<Weapon>() const {
+  return equipped_as_Weapon();
+}
+
 struct MonsterBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
@@ -279,13 +311,13 @@
   void add_equipped(flatbuffers::Offset<void> equipped) {
     fbb_.AddOffset(Monster::VT_EQUIPPED, equipped);
   }
-  MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   MonsterBuilder &operator=(const MonsterBuilder &);
   flatbuffers::Offset<Monster> Finish() {
-    const auto end = fbb_.EndTable(start_, 10);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Monster>(end);
     return o;
   }
@@ -366,11 +398,11 @@
     return GetField<int16_t>(VT_DAMAGE, 0);
   }
   bool mutate_damage(int16_t _damage) {
-    return SetField(VT_DAMAGE, _damage);
+    return SetField<int16_t>(VT_DAMAGE, _damage, 0);
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffset(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
            VerifyField<int16_t>(verifier, VT_DAMAGE) &&
            verifier.EndTable();
@@ -389,13 +421,13 @@
   void add_damage(int16_t damage) {
     fbb_.AddElement<int16_t>(Weapon::VT_DAMAGE, damage, 0);
   }
-  WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit WeaponBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   WeaponBuilder &operator=(const WeaponBuilder &);
   flatbuffers::Offset<Weapon> Finish() {
-    const auto end = fbb_.EndTable(start_, 2);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Weapon>(end);
     return o;
   }
@@ -432,15 +464,15 @@
 inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
   (void)_o;
   (void)_resolver;
-  { auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
+  { auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<Vec3>(new Vec3(*_e)); };
   { auto _e = mana(); _o->mana = _e; };
   { auto _e = hp(); _o->hp = _e; };
   { auto _e = name(); if (_e) _o->name = _e->str(); };
-  { auto _e = inventory(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } };
+  { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
   { auto _e = color(); _o->color = _e; };
-  { auto _e = weapons(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons.push_back(std::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver))); } };
+  { auto _e = weapons(); if (_e) { _o->weapons.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->weapons[_i] = flatbuffers::unique_ptr<WeaponT>(_e->Get(_i)->UnPack(_resolver)); } } };
   { auto _e = equipped_type(); _o->equipped.type = _e; };
-  { auto _e = equipped(); if (_e) _o->equipped.table = EquipmentUnion::UnPack(_e, equipped_type(),_resolver); };
+  { auto _e = equipped(); if (_e) _o->equipped.value = EquipmentUnion::UnPack(_e, equipped_type(), _resolver); };
 }
 
 inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -450,13 +482,14 @@
 inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   auto _pos = _o->pos ? _o->pos.get() : 0;
   auto _mana = _o->mana;
   auto _hp = _o->hp;
-  auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
+  auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
   auto _inventory = _o->inventory.size() ? _fbb.CreateVector(_o->inventory) : 0;
   auto _color = _o->color;
-  auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>>(_o->weapons.size(), [&](size_t i) { return CreateWeapon(_fbb, _o->weapons[i].get(), _rehasher); }) : 0;
+  auto _weapons = _o->weapons.size() ? _fbb.CreateVector<flatbuffers::Offset<Weapon>> (_o->weapons.size(), [](size_t i, _VectorArgs *__va) { return CreateWeapon(*__va->__fbb, __va->__o->weapons[i].get(), __va->__rehasher); }, &_va ) : 0;
   auto _equipped_type = _o->equipped.type;
   auto _equipped = _o->equipped.Pack(_fbb);
   return MyGame::Sample::CreateMonster(
@@ -492,7 +525,8 @@
 inline flatbuffers::Offset<Weapon> CreateWeapon(flatbuffers::FlatBufferBuilder &_fbb, const WeaponT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
-  auto _name = _o->name.size() ? _fbb.CreateString(_o->name) : 0;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const WeaponT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _name = _o->name.empty() ? 0 : _fbb.CreateString(_o->name);
   auto _damage = _o->damage;
   return MyGame::Sample::CreateWeapon(
       _fbb,
@@ -524,7 +558,7 @@
   return true;
 }
 
-inline flatbuffers::NativeTable *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
+inline void *EquipmentUnion::UnPack(const void *obj, Equipment type, const flatbuffers::resolver_function_t *resolver) {
   switch (type) {
     case Equipment_Weapon: {
       auto ptr = reinterpret_cast<const Weapon *>(obj);
@@ -537,26 +571,151 @@
 inline flatbuffers::Offset<void> EquipmentUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
   switch (type) {
     case Equipment_Weapon: {
-      auto ptr = reinterpret_cast<const WeaponT *>(table);
+      auto ptr = reinterpret_cast<const WeaponT *>(value);
       return CreateWeapon(_fbb, ptr, _rehasher).Union();
     }
     default: return 0;
   }
 }
 
+inline EquipmentUnion::EquipmentUnion(const EquipmentUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+  switch (type) {
+    case Equipment_Weapon: {
+      value = new WeaponT(*reinterpret_cast<WeaponT *>(u.value));
+      break;
+    }
+    default:
+      break;
+  }
+}
+
 inline void EquipmentUnion::Reset() {
   switch (type) {
     case Equipment_Weapon: {
-      auto ptr = reinterpret_cast<WeaponT *>(table);
+      auto ptr = reinterpret_cast<WeaponT *>(value);
       delete ptr;
       break;
     }
     default: break;
   }
-  table = nullptr;
+  value = nullptr;
   type = Equipment_NONE;
 }
 
+inline flatbuffers::TypeTable *Vec3TypeTable();
+
+inline flatbuffers::TypeTable *MonsterTypeTable();
+
+inline flatbuffers::TypeTable *WeaponTypeTable();
+
+inline flatbuffers::TypeTable *ColorTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    ColorTypeTable
+  };
+  static const char *names[] = {
+    "Red",
+    "Green",
+    "Blue"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *EquipmentTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, -1 },
+    { flatbuffers::ET_SEQUENCE, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    WeaponTypeTable
+  };
+  static const char *names[] = {
+    "NONE",
+    "Weapon"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_UNION, 2, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *Vec3TypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 4, 8, 12 };
+  static const char *names[] = {
+    "x",
+    "y",
+    "z"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 3, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *MonsterTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_STRING, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_UCHAR, 1, -1 },
+    { flatbuffers::ET_CHAR, 0, 1 },
+    { flatbuffers::ET_SEQUENCE, 1, 2 },
+    { flatbuffers::ET_UTYPE, 0, 3 },
+    { flatbuffers::ET_SEQUENCE, 0, 3 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    Vec3TypeTable,
+    ColorTypeTable,
+    WeaponTypeTable,
+    EquipmentTypeTable
+  };
+  static const char *names[] = {
+    "pos",
+    "mana",
+    "hp",
+    "name",
+    "friendly",
+    "inventory",
+    "color",
+    "weapons",
+    "equipped_type",
+    "equipped"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 10, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *WeaponTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_STRING, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 }
+  };
+  static const char *names[] = {
+    "name",
+    "damage"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 2, type_codes, nullptr, nullptr, names
+  };
+  return &tt;
+}
+
 inline const MyGame::Sample::Monster *GetMonster(const void *buf) {
   return flatbuffers::GetRoot<MyGame::Sample::Monster>(buf);
 }
@@ -576,10 +735,10 @@
   fbb.Finish(root);
 }
 
-inline std::unique_ptr<MonsterT> UnPackMonster(
+inline flatbuffers::unique_ptr<MonsterT> UnPackMonster(
     const void *buf,
     const flatbuffers::resolver_function_t *res = nullptr) {
-  return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
+  return flatbuffers::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
 }
 
 }  // namespace Sample
diff --git a/samples/monsterdata.json b/samples/monsterdata.json
old mode 100755
new mode 100644
diff --git a/src/code_generators.cpp b/src/code_generators.cpp
index 8710635..e0bee8b 100644
--- a/src/code_generators.cpp
+++ b/src/code_generators.cpp
@@ -16,8 +16,14 @@
 
 #include "flatbuffers/code_generators.h"
 #include <assert.h>
+#include "flatbuffers/base.h"
 #include "flatbuffers/util.h"
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4127) // C4127: conditional expression is constant
+#endif
+
 namespace flatbuffers {
 
 void CodeWriter::operator+=(std::string text) {
@@ -53,7 +59,7 @@
     // Update the text to everything after the }}.
     text = text.substr(end + 2);
   }
-  if (!text.empty() && text.back() == '\\') {
+  if (!text.empty() && string_back(text) == '\\') {
     text.pop_back();
     stream_ << text;
   } else {
@@ -63,7 +69,7 @@
 
 const char *BaseGenerator::FlatBuffersGeneratedWarning() {
   return "automatically generated by the FlatBuffers compiler,"
-         " do not modify\n\n";
+         " do not modify";
 }
 
 std::string BaseGenerator::NamespaceDir(const Parser &parser,
@@ -84,18 +90,6 @@
   return BaseGenerator::NamespaceDir(parser_, path_, ns);
 }
 
-bool BaseGenerator::IsEverythingGenerated() const {
-    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
-         ++it) {
-      if (!(*it)->generated) return false;
-    }
-    for (auto it = parser_.structs_.vec.begin();
-         it != parser_.structs_.vec.end(); ++it) {
-      if (!(*it)->generated) return false;
-    }
-    return true;
-  }
-
 std::string BaseGenerator::FullNamespace(const char *separator,
                                          const Namespace &ns) {
   std::string namespace_name;
@@ -130,6 +124,20 @@
   return WrapInNameSpace(def.defined_namespace, def.name);
 }
 
+std::string BaseGenerator::GetNameSpace(const Definition &def) const {
+  const Namespace *ns = def.defined_namespace;
+  if (CurrentNameSpace() == ns) return "";
+  std::string qualified_name = qualifying_start_;
+  for (auto it = ns->components.begin(); it != ns->components.end(); ++it) {
+    qualified_name += *it;
+    if ((it + 1) != ns->components.end()) {
+      qualified_name += qualifying_separator_;
+    }
+  }
+
+  return qualified_name;
+}
+
 // Generate a documentation comment, if available.
 void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
                 const CommentConfig *config, const char *prefix) {
@@ -156,3 +164,7 @@
 }
 
 }  // namespace flatbuffers
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
diff --git a/src/flatc.cpp b/src/flatc.cpp
index dc56d53..c888203 100644
--- a/src/flatc.cpp
+++ b/src/flatc.cpp
@@ -16,7 +16,9 @@
 
 #include "flatbuffers/flatc.h"
 
-#define FLATC_VERSION "1.6.0 (" __DATE__ ")"
+#include <list>
+
+#define FLATC_VERSION "1.8.0 (" __DATE__ ")"
 
 namespace flatbuffers {
 
@@ -46,7 +48,7 @@
 
 std::string FlatCompiler::GetUsageString(const char* program_name) const {
   std::stringstream ss;
-  ss << "Usageaa: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
+  ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n";
   for (size_t i = 0; i < params_.num_generators; ++i) {
     const Generator& g = params_.generators[i];
 
@@ -81,13 +83,21 @@
       "  --no-includes      Don\'t generate include statements for included\n"
       "                     schemas the generated file depends on (C++).\n"
       "  --gen-mutable      Generate accessors that can mutate buffers in-place.\n"
-      "  --gen-onefile      Generate single output file for C#.\n"
+      "  --gen-onefile      Generate single output file for C# and Go.\n"
       "  --gen-name-strings Generate type name functions for C++.\n"
-      "  --escape-proto-ids Disable appending '_' in namespaces names.\n"
       "  --gen-object-api   Generate an additional object-based API.\n"
       "  --cpp-ptr-type T   Set object API pointer type (default std::unique_ptr)\n"
+      "  --cpp-str-type T   Set object API string type (default std::string)\n"
+      "                     T::c_str() and T::length() must be supported\n"
+      "  --gen-nullable     Add Clang _Nullable for C++ pointer. or @Nullable for Java\n"
+      "  --object-prefix    Customise class prefix for C++ object-based API.\n"
+      "  --object-suffix    Customise class suffix for C++ object-based API.\n"
+      "                     Default value is \"T\"\n"
       "  --no-js-exports    Removes Node.js style export lines in JS.\n"
       "  --goog-js-export   Uses goog.exports* for closure compiler exporting in JS.\n"
+      "  --go-namespace     Generate the overrided namespace in Golang.\n"
+      "  --go-import        Generate the overrided import for flatbuffers in Golang.\n"
+      "                     (default is \"github.com/google/flatbuffers/go\")\n"
       "  --raw-binary       Allow binaries without file_indentifier to be read.\n"
       "                     This may crash flatc given a mismatched schema.\n"
       "  --proto            Input is a .proto, translate to .fbs.\n"
@@ -100,8 +110,13 @@
       "    PATH             \n"
       "  --include-prefix   Prefix this path to any generated include statements.\n"
       "    PATH\n"
-      "FILEs may be schemas, or JSON files (conforming to preceding schema)\n"
-      "FILEs after the -- must be binary flatbuffer format files.\n"
+      "  --keep-prefix      Keep original prefix of schema include statement.\n"
+      "  --no-fb-import     Don't include flatbuffers import statement for TypeScript.\n"
+      "  --no-ts-reexport   Don't re-export imported dependencies for TypeScript.\n"
+      "  --reflect-types    Add minimal type reflection to code generation.\n"
+      "  --reflect-names    Add minimal type/name reflection.\n"
+      "FILEs may be schemas (must end in .fbs), or JSON files (conforming to preceding\n"
+      "schema). FILEs after the -- must be binary flatbuffer format files.\n"
       "Output files are named using the base file name of the input,\n"
       "and written to the current directory or the path given by -o.\n"
       "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n";
@@ -122,6 +137,7 @@
   bool schema_binary = false;
   bool grpc_enabled = false;
   std::vector<std::string> filenames;
+  std::list<std::string> include_directories_storage;
   std::vector<const char *> include_directories;
   std::vector<const char *> conform_include_directories;
   std::vector<bool> generator_enabled(params_.num_generators, false);
@@ -135,21 +151,29 @@
         Error("invalid option location: " + arg, true);
       if (arg == "-o") {
         if (++argi >= argc) Error("missing path following: " + arg, true);
-        output_path = flatbuffers::ConCatPathFileName(argv[argi], "");
+        output_path = flatbuffers::ConCatPathFileName(
+                        flatbuffers::PosixPath(argv[argi]), "");
       } else if(arg == "-I") {
         if (++argi >= argc) Error("missing path following" + arg, true);
-        include_directories.push_back(argv[argi]);
+        include_directories_storage.push_back(
+                                      flatbuffers::PosixPath(argv[argi]));
+        include_directories.push_back(
+                              include_directories_storage.back().c_str());
       } else if(arg == "--conform") {
         if (++argi >= argc) Error("missing path following" + arg, true);
-        conform_to_schema = argv[argi];
+        conform_to_schema = flatbuffers::PosixPath(argv[argi]);
       } else if (arg == "--conform-includes") {
         if (++argi >= argc) Error("missing path following" + arg, true);
-        conform_include_directories.push_back(argv[argi]);
+        include_directories_storage.push_back(
+                                      flatbuffers::PosixPath(argv[argi]));
+        conform_include_directories.push_back(
+                                    include_directories_storage.back().c_str());
       } else if (arg == "--include-prefix") {
         if (++argi >= argc) Error("missing path following" + arg, true);
-        opts.include_prefix = argv[argi];
-        if (opts.include_prefix.back() != '/' &&
-            opts.include_prefix.back() != '\\') opts.include_prefix += "/";
+        opts.include_prefix = flatbuffers::ConCatPathFileName(
+                                flatbuffers::PosixPath(argv[argi]), "");
+      } else if(arg == "--keep-prefix") {
+        opts.keep_include_path = true;
       } else if(arg == "--strict-json") {
         opts.strict_json = true;
       } else if(arg == "--allow-non-utf8") {
@@ -158,6 +182,12 @@
         opts.skip_js_exports = true;
       } else if(arg == "--goog-js-export") {
         opts.use_goog_js_export_format = true;
+      } else if(arg == "--go-namespace") {
+        if (++argi >= argc) Error("missing golang namespace" + arg, true);
+        opts.go_namespace = argv[argi];
+      } else if(arg == "--go-import") {
+        if (++argi >= argc) Error("missing golang import" + arg, true);
+        opts.go_import = argv[argi];
       } else if(arg == "--defaults-json") {
         opts.output_default_scalars_in_json = true;
       } else if (arg == "--unknown-json") {
@@ -178,6 +208,17 @@
       } else if (arg == "--cpp-ptr-type") {
         if (++argi >= argc) Error("missing type following" + arg, true);
         opts.cpp_object_api_pointer_type = argv[argi];
+      } else if (arg == "--cpp-str-type") {
+        if (++argi >= argc) Error("missing type following" + arg, true);
+        opts.cpp_object_api_string_type = argv[argi];
+      } else if (arg == "--gen-nullable") {
+        opts.gen_nullable = true;
+      } else if (arg == "--object-prefix") {
+        if (++argi >= argc) Error("missing prefix following" + arg, true);
+        opts.object_prefix = argv[argi];
+      } else if (arg == "--object-suffix") {
+        if (++argi >= argc) Error("missing suffix following" + arg, true);
+        opts.object_suffix = argv[argi];
       } else if(arg == "--gen-all") {
         opts.generate_all = true;
         opts.include_dependence_headers = false;
@@ -194,8 +235,6 @@
         binary_files_from = filenames.size();
       } else if(arg == "--proto") {
         opts.proto_mode = true;
-      } else if(arg == "--escape-proto-ids") {
-        opts.escape_proto_identifiers = true;
       } else if(arg == "--schema") {
         schema_binary = true;
       } else if(arg == "-M") {
@@ -207,6 +246,14 @@
         grpc_enabled = true;
       } else if(arg == "--bfbs-comments") {
         opts.binary_schema_comments = true;
+      } else if(arg == "--no-fb-import") {
+        opts.skip_flatbuffers_import = true;
+      } else if(arg == "--no-ts-reexport") {
+        opts.reexport_ts_modules = false;
+      } else if(arg == "--reflect-types") {
+        opts.mini_reflect = IDLOptions::kTypes;
+      } else if(arg == "--reflect-names") {
+        opts.mini_reflect = IDLOptions::kTypesAndNames;
       } else {
         for (size_t i = 0; i < params_.num_generators; ++i) {
           if (arg == params_.generators[i].generator_opt_long ||
@@ -222,7 +269,7 @@
         found:;
       }
     } else {
-      filenames.push_back(argv[argi]);
+      filenames.push_back(flatbuffers::PosixPath(argv[argi]));
     }
   }
 
@@ -249,101 +296,110 @@
   for (auto file_it = filenames.begin();
             file_it != filenames.end();
           ++file_it) {
-      std::string contents;
-      if (!flatbuffers::LoadFile(file_it->c_str(), true, &contents))
-        Error("unable to load file: " + *file_it);
+    auto &filename = *file_it;
+    std::string contents;
+    if (!flatbuffers::LoadFile(filename.c_str(), true, &contents))
+      Error("unable to load file: " + filename);
 
-      bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
-                       binary_files_from;
-      if (is_binary) {
-        parser->builder_.Clear();
-        parser->builder_.PushFlatBuffer(
-          reinterpret_cast<const uint8_t *>(contents.c_str()),
-          contents.length());
-        if (!raw_binary) {
-          // Generally reading binaries that do not correspond to the schema
-          // will crash, and sadly there's no way around that when the binary
-          // does not contain a file identifier.
-          // We'd expect that typically any binary used as a file would have
-          // such an identifier, so by default we require them to match.
-          if (!parser->file_identifier_.length()) {
-            Error("current schema has no file_identifier: cannot test if \"" +
-                 *file_it +
-                 "\" matches the schema, use --raw-binary to read this file"
-                 " anyway.");
-          } else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
-                         parser->file_identifier_.c_str())) {
-            Error("binary \"" +
-                 *file_it +
-                 "\" does not have expected file_identifier \"" +
-                 parser->file_identifier_ +
-                 "\", use --raw-binary to read this file anyway.");
-          }
-        }
-      } else {
-        // Check if file contains 0 bytes.
-        if (contents.length() != strlen(contents.c_str())) {
-          Error("input file appears to be binary: " + *file_it, true);
-        }
-        auto is_schema = flatbuffers::GetExtension(*file_it) == "fbs";
-        if (is_schema) {
-          // If we're processing multiple schemas, make sure to start each
-          // one from scratch. If it depends on previous schemas it must do
-          // so explicitly using an include.
-          parser.reset(new flatbuffers::Parser(opts));
-        }
-        ParseFile(*parser.get(), *file_it, contents, include_directories);
-        if (is_schema && !conform_to_schema.empty()) {
-          auto err = parser->ConformTo(conform_parser);
-          if (!err.empty()) Error("schemas don\'t conform: " + err);
-        }
-        if (schema_binary) {
-          parser->Serialize();
-          parser->file_extension_ = reflection::SchemaExtension();
+    bool is_binary = static_cast<size_t>(file_it - filenames.begin()) >=
+                     binary_files_from;
+    auto ext = flatbuffers::GetExtension(filename);
+    auto is_schema = ext == "fbs" || ext == "proto";
+    if (is_binary) {
+      parser->builder_.Clear();
+      parser->builder_.PushFlatBuffer(
+        reinterpret_cast<const uint8_t *>(contents.c_str()),
+        contents.length());
+      if (!raw_binary) {
+        // Generally reading binaries that do not correspond to the schema
+        // will crash, and sadly there's no way around that when the binary
+        // does not contain a file identifier.
+        // We'd expect that typically any binary used as a file would have
+        // such an identifier, so by default we require them to match.
+        if (!parser->file_identifier_.length()) {
+          Error("current schema has no file_identifier: cannot test if \"" +
+               filename +
+               "\" matches the schema, use --raw-binary to read this file"
+               " anyway.");
+        } else if (!flatbuffers::BufferHasIdentifier(contents.c_str(),
+                       parser->file_identifier_.c_str())) {
+          Error("binary \"" +
+               filename +
+               "\" does not have expected file_identifier \"" +
+               parser->file_identifier_ +
+               "\", use --raw-binary to read this file anyway.");
         }
       }
+    } else {
+      // Check if file contains 0 bytes.
+      if (contents.length() != strlen(contents.c_str())) {
+        Error("input file appears to be binary: " + filename, true);
+      }
+      if (is_schema) {
+        // If we're processing multiple schemas, make sure to start each
+        // one from scratch. If it depends on previous schemas it must do
+        // so explicitly using an include.
+        parser.reset(new flatbuffers::Parser(opts));
+      }
+      ParseFile(*parser.get(), filename, contents, include_directories);
+      if (!is_schema && !parser->builder_.GetSize()) {
+        // If a file doesn't end in .fbs, it must be json/binary. Ensure we
+        // didn't just parse a schema with a different extension.
+        Error("input file is neither json nor a .fbs (schema) file: " +
+              filename, true);
+      }
+      if (is_schema && !conform_to_schema.empty()) {
+        auto err = parser->ConformTo(conform_parser);
+        if (!err.empty()) Error("schemas don\'t conform: " + err);
+      }
+      if (schema_binary) {
+        parser->Serialize();
+        parser->file_extension_ = reflection::SchemaExtension();
+      }
+    }
 
-      std::string filebase = flatbuffers::StripPath(
-                               flatbuffers::StripExtension(*file_it));
+    std::string filebase = flatbuffers::StripPath(
+                             flatbuffers::StripExtension(filename));
 
-      for (size_t i = 0; i < params_.num_generators; ++i) {
-        parser->opts.lang = params_.generators[i].lang;
-        if (generator_enabled[i]) {
-          if (!print_make_rules) {
-            flatbuffers::EnsureDirExists(output_path);
-            if (!params_.generators[i].generate(*parser.get(), output_path, filebase)) {
-              Error(std::string("Unable to generate ") +
-                    params_.generators[i].lang_name +
-                    " for " +
-                    filebase);
+    for (size_t i = 0; i < params_.num_generators; ++i) {
+      parser->opts.lang = params_.generators[i].lang;
+      if (generator_enabled[i]) {
+        if (!print_make_rules) {
+          flatbuffers::EnsureDirExists(output_path);
+          if ((!params_.generators[i].schema_only || is_schema) &&
+              !params_.generators[i].generate(*parser.get(), output_path, filebase)) {
+            Error(std::string("Unable to generate ") +
+                  params_.generators[i].lang_name +
+                  " for " +
+                  filebase);
+          }
+        } else {
+          std::string make_rule = params_.generators[i].make_rule(
+              *parser.get(), output_path, filename);
+          if (!make_rule.empty())
+            printf("%s\n", flatbuffers::WordWrap(
+                make_rule, 80, " ", " \\").c_str());
+        }
+        if (grpc_enabled) {
+          if (params_.generators[i].generateGRPC != nullptr) {
+            if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
+                                            filebase)) {
+              Error(std::string("Unable to generate GRPC interface for") +
+                    params_.generators[i].lang_name);
             }
           } else {
-            std::string make_rule = params_.generators[i].make_rule(
-                *parser.get(), output_path, *file_it);
-            if (!make_rule.empty())
-              printf("%s\n", flatbuffers::WordWrap(
-                  make_rule, 80, " ", " \\").c_str());
-          }
-          if (grpc_enabled) {
-            if (params_.generators[i].generateGRPC != nullptr) {
-              if (!params_.generators[i].generateGRPC(*parser.get(), output_path,
-                                              filebase)) {
-                Error(std::string("Unable to generate GRPC interface for") +
-                      params_.generators[i].lang_name);
-              }
-            } else {
-              Warn(std::string("GRPC interface generator not implemented for ")
-                   + params_.generators[i].lang_name);
-            }
+            Warn(std::string("GRPC interface generator not implemented for ")
+                 + params_.generators[i].lang_name);
           }
         }
       }
+    }
 
-      if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
+    if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase);
 
-      // We do not want to generate code for the definitions in this file
-      // in any files coming up next.
-      parser->MarkGenerated();
+    // We do not want to generate code for the definitions in this file
+    // in any files coming up next.
+    parser->MarkGenerated();
   }
   return 0;
 }
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index f4d9557..02d01c0 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -46,52 +46,62 @@
   g_program_name = argv[0];
 
   const flatbuffers::FlatCompiler::Generator generators[] = {
-    { flatbuffers::GenerateBinary,   "-b", "--binary", "binary",
+    { flatbuffers::GenerateBinary,   "-b", "--binary", "binary", false,
       nullptr,
       flatbuffers::IDLOptions::kBinary,
       "Generate wire format binaries for any data definitions",
       flatbuffers::BinaryMakeRule },
-    { flatbuffers::GenerateTextFile, "-t", "--json", "text",
+    { flatbuffers::GenerateTextFile, "-t", "--json", "text", false,
       nullptr,
       flatbuffers::IDLOptions::kJson,
       "Generate text output for any data definitions",
       flatbuffers::TextMakeRule },
-    { flatbuffers::GenerateCPP,      "-c", "--cpp", "C++",
+    { flatbuffers::GenerateCPP,      "-c", "--cpp", "C++", true,
       flatbuffers::GenerateCppGRPC,
       flatbuffers::IDLOptions::kCpp,
       "Generate C++ headers for tables/structs",
       flatbuffers::CPPMakeRule },
-    { flatbuffers::GenerateGo,       "-g", "--go", "Go",
+    { flatbuffers::GenerateGo,       "-g", "--go", "Go", true,
       flatbuffers::GenerateGoGRPC,
       flatbuffers::IDLOptions::kGo,
       "Generate Go files for tables/structs",
       flatbuffers::GeneralMakeRule },
-    { flatbuffers::GenerateGeneral,  "-j", "--java", "Java",
+    { flatbuffers::GenerateGeneral,  "-j", "--java", "Java", true,
       nullptr,
       flatbuffers::IDLOptions::kJava,
       "Generate Java classes for tables/structs",
       flatbuffers::GeneralMakeRule },
-    { flatbuffers::GenerateJS,       "-s", "--js", "JavaScript",
+    { flatbuffers::GenerateJS,       "-s", "--js", "JavaScript", true,
       nullptr,
       flatbuffers::IDLOptions::kJs,
       "Generate JavaScript code for tables/structs",
       flatbuffers::JSMakeRule },
-    { flatbuffers::GenerateGeneral,  "-n", "--csharp", "C#",
+    { flatbuffers::GenerateJS,       "-T", "--ts", "TypeScript", true,
+      nullptr,
+      flatbuffers::IDLOptions::kTs,
+      "Generate TypeScript code for tables/structs",
+      flatbuffers::JSMakeRule },
+    { flatbuffers::GenerateGeneral,  "-n", "--csharp", "C#", true,
       nullptr,
       flatbuffers::IDLOptions::kCSharp,
       "Generate C# classes for tables/structs",
       flatbuffers::GeneralMakeRule },
-    { flatbuffers::GeneratePython,   "-p", "--python", "Python",
+    { flatbuffers::GeneratePython,   "-p", "--python", "Python", true,
       nullptr,
       flatbuffers::IDLOptions::kPython,
       "Generate Python files for tables/structs",
       flatbuffers::GeneralMakeRule },
-    { flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
+    { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true,
       nullptr,
       flatbuffers::IDLOptions::kPhp,
       "Generate PHP files for tables/structs",
       flatbuffers::GeneralMakeRule },
-    };
+   { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema", true,
+      nullptr,
+      flatbuffers::IDLOptions::kJsonSchema,
+      "Generate Json schema",
+      flatbuffers::GeneralMakeRule },
+  };
 
   flatbuffers::FlatCompiler::InitParams params;
   params.generators = generators;
diff --git a/src/idl_gen_cpp.cpp b/src/idl_gen_cpp.cpp
index 86cadd3..8b28379 100644
--- a/src/idl_gen_cpp.cpp
+++ b/src/idl_gen_cpp.cpp
@@ -23,6 +23,11 @@
 
 namespace flatbuffers {
 
+// Pedantic warning free version of toupper().
+inline char ToUpper(char c) {
+  return static_cast<char>(::toupper(c));
+}
+
 static std::string GeneratedFileName(const std::string &path,
                                      const std::string &file_name) {
   return path + file_name + "_generated.h";
@@ -34,7 +39,26 @@
   CppGenerator(const Parser &parser, const std::string &path,
                const std::string &file_name)
       : BaseGenerator(parser, path, file_name, "", "::"),
-        cur_name_space_(nullptr) {}
+        cur_name_space_(nullptr) {
+    const char *keywords[] = {
+      "alignas", "alignof", "and", "and_eq", "asm", "atomic_cancel",
+      "atomic_commit", "atomic_noexcept", "auto", "bitand", "bitor", "bool",
+      "break", "case", "catch", "char", "char16_t", "char32_t", "class",
+      "compl", "concept", "const", "constexpr", "const_cast", "continue",
+      "co_await", "co_return", "co_yield", "decltype", "default", "delete",
+      "do", "double", "dynamic_cast", "else", "enum", "explicit", "export",
+      "extern", "false", "float", "for", "friend", "goto", "if", "import",
+      "inline", "int", "long", "module", "mutable", "namespace", "new",
+      "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
+      "private", "protected", "public", "register", "reinterpret_cast",
+      "requires", "return", "short", "signed", "sizeof", "static",
+      "static_assert", "static_cast", "struct", "switch", "synchronized",
+      "template", "this", "thread_local", "throw", "true", "try", "typedef",
+      "typeid", "typename", "union", "unsigned", "using", "virtual", "void",
+      "volatile", "wchar_t", "while", "xor", "xor_eq", nullptr
+    };
+    for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+  }
 
   std::string GenIncludeGuard() const {
     // Generate include guard.
@@ -48,13 +72,13 @@
     guard = "FLATBUFFERS_GENERATED_" + guard;
     guard += "_";
     // For further uniqueness, also add the namespace.
-    auto name_space = parser_.namespaces_.back();
+    auto name_space = parser_.current_namespace_;
     for (auto it = name_space->components.begin();
          it != name_space->components.end(); ++it) {
       guard += *it + "_";
     }
     guard += "H_";
-    std::transform(guard.begin(), guard.end(), guard.begin(), ::toupper);
+    std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper);
     return guard;
   }
 
@@ -67,31 +91,50 @@
     }
     for (auto it = parser_.included_files_.begin();
          it != parser_.included_files_.end(); ++it) {
-      const auto basename =
-          flatbuffers::StripPath(flatbuffers::StripExtension(it->first));
-      if (basename != file_name_) {
-        code_ += "#include \"" + parser_.opts.include_prefix + basename +
-                 "_generated.h\"";
-        num_includes++;
-      }
+      if (it->second.empty())
+        continue;
+      auto noext = flatbuffers::StripExtension(it->second);
+      auto basename = flatbuffers::StripPath(noext);
+
+      code_ += "#include \"" + parser_.opts.include_prefix +
+               (parser_.opts.keep_include_path ? noext : basename) +
+               "_generated.h\"";
+      num_includes++;
     }
     if (num_includes) code_ += "";
   }
 
+  std::string EscapeKeyword(const std::string &name) const {
+    return keywords_.find(name) == keywords_.end() ? name : name + "_";
+  }
+
+  std::string Name(const Definition &def) const {
+    return EscapeKeyword(def.name);
+  }
+
+  std::string Name(const EnumVal &ev) const {
+    return EscapeKeyword(ev.name);
+  }
+
   // Iterate through all definitions we haven't generate code for (enums,
   // structs, and tables) and output them to a single file.
   bool generate() {
-    if (IsEverythingGenerated()) return true;
-
     code_.Clear();
-    code_ += "// " + std::string(FlatBuffersGeneratedWarning());
+    code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
 
     const auto include_guard = GenIncludeGuard();
     code_ += "#ifndef " + include_guard;
     code_ += "#define " + include_guard;
     code_ += "";
 
+    if (parser_.opts.gen_nullable) {
+      code_ += "#pragma clang system_header\n\n";
+    }
+
     code_ += "#include \"flatbuffers/flatbuffers.h\"";
+    if (parser_.uses_flexbuffers_) {
+      code_ += "#include \"flatbuffers/flexbuffers.h\"";
+    }
     code_ += "";
 
     if (parser_.opts.include_dependence_headers) {
@@ -107,9 +150,11 @@
       const auto &struct_def = **it;
       if (!struct_def.generated) {
         SetNameSpace(struct_def.defined_namespace);
-        code_ += "struct " + struct_def.name + ";";
+        code_ += "struct " + Name(struct_def) + ";";
         if (parser_.opts.generate_object_based_api && !struct_def.fixed) {
-          code_ += "struct " + NativeName(struct_def.name) + ";";
+          code_ += "struct " +
+                   NativeName(Name(struct_def), &struct_def, parser_.opts) +
+                   ";";
         }
         code_ += "";
       }
@@ -161,21 +206,53 @@
       }
     }
 
+    // Generate code for mini reflection.
+    if (parser_.opts.mini_reflect != IDLOptions::kNone) {
+      // To break cyclic dependencies, first pre-declare all tables/structs.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (!struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenMiniReflectPre(&struct_def);
+        }
+      }
+      // Then the unions/enums that may refer to them.
+      for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+           ++it) {
+        const auto &enum_def = **it;
+        if (!enum_def.generated) {
+          SetNameSpace(enum_def.defined_namespace);
+          GenMiniReflect(nullptr, &enum_def);
+        }
+      }
+      // Then the full tables/structs.
+      for (auto it = parser_.structs_.vec.begin();
+           it != parser_.structs_.vec.end(); ++it) {
+        const auto &struct_def = **it;
+        if (!struct_def.generated) {
+          SetNameSpace(struct_def.defined_namespace);
+          GenMiniReflect(&struct_def, nullptr);
+        }
+      }
+    }
+
     // Generate convenient global helper functions:
     if (parser_.root_struct_def_) {
       auto &struct_def = *parser_.root_struct_def_;
       SetNameSpace(struct_def.defined_namespace);
-      const auto &name = struct_def.name;
-      const auto qualified_name =
-          parser_.namespaces_.back()->GetFullyQualifiedName(name);
-      const auto cpp_name = TranslateNameSpace(qualified_name);
+      auto name = Name(struct_def);
+      auto qualified_name =
+          cur_name_space_->GetFullyQualifiedName(name);
+      auto cpp_name = TranslateNameSpace(qualified_name);
 
       code_.SetValue("STRUCT_NAME", name);
       code_.SetValue("CPP_NAME", cpp_name);
+      code_.SetValue("NULLABLE_EXT", NullableExtension());
 
       // The root datatype accessor:
       code_ += "inline \\";
-      code_ += "const {{CPP_NAME}} *Get{{STRUCT_NAME}}(const void *buf) {";
+      code_ += "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void *buf) {";
       code_ += "  return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
       code_ += "}";
       code_ += "";
@@ -239,7 +316,7 @@
       if (parser_.opts.generate_object_based_api) {
         // A convenient root unpack function.
         auto native_name =
-            NativeName(WrapInNameSpace(struct_def));
+            NativeName(WrapInNameSpace(struct_def), &struct_def, parser_.opts);
         code_.SetValue("UNPACK_RETURN",
                        GenTypeNativePtr(native_name, nullptr, false));
         code_.SetValue("UNPACK_TYPE",
@@ -255,8 +332,7 @@
       }
     }
 
-    assert(cur_name_space_);
-    SetNameSpace(nullptr);
+    if (cur_name_space_) SetNameSpace(nullptr);
 
     // Close the include guard.
     code_ += "#endif  // " + include_guard;
@@ -269,6 +345,8 @@
  private:
   CodeWriter code_;
 
+  std::set<std::string> keywords_;
+
   // This tracks the current namespace so we can insert namespace declarations.
   const Namespace *cur_name_space_;
 
@@ -354,14 +432,28 @@
     }
   }
 
-  // TODO(wvo): make this configurable.
-  static std::string NativeName(const std::string &name) { return name + "T"; }
+  std::string NullableExtension() {
+    return parser_.opts.gen_nullable ? " _Nullable " : "";
+  }
+
+  static std::string NativeName(const std::string &name, const StructDef *sd, const IDLOptions & opts) {
+    return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix : name;
+  }
 
   const std::string &PtrType(const FieldDef *field) {
     auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr;
     return attr ? attr->constant : parser_.opts.cpp_object_api_pointer_type;
   }
 
+  const std::string NativeString(const FieldDef *field) {
+    auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr;
+    auto &ret = attr ? attr->constant : parser_.opts.cpp_object_api_string_type;
+    if (ret.empty()) {
+      return "std::string";
+    }
+    return ret;
+  }
+
   std::string GenTypeNativePtr(const std::string &type, const FieldDef *field,
                                bool is_constructor) {
     auto &ptr_type = PtrType(field);
@@ -383,11 +475,15 @@
                             const FieldDef &field) {
     switch (type.base_type) {
       case BASE_TYPE_STRING: {
-        return "std::string";
+        return NativeString(&field);
       }
       case BASE_TYPE_VECTOR: {
         const auto type_name = GenTypeNative(type.VectorType(), true, field);
-        return "std::vector<" + type_name + ">";
+        if (type.struct_def && type.struct_def->attributes.Lookup("native_custom_alloc")) {
+          auto native_custom_alloc = type.struct_def->attributes.Lookup("native_custom_alloc");
+          return "std::vector<" + type_name + "," + native_custom_alloc->constant + "<" + type_name + ">>";
+        } else 
+          return "std::vector<" + type_name + ">";
       }
       case BASE_TYPE_STRUCT: {
         auto type_name = WrapInNameSpace(*type.struct_def);
@@ -402,7 +498,8 @@
             return GenTypeNativePtr(type_name, &field, false);
           }
         } else {
-          return GenTypeNativePtr(NativeName(type_name), &field, false);
+          return GenTypeNativePtr(NativeName(type_name, type.struct_def, parser_.opts),
+                                  &field, false);
         }
       }
       case BASE_TYPE_UNION: {
@@ -428,97 +525,258 @@
 
   std::string GenEnumDecl(const EnumDef &enum_def) const {
     const IDLOptions &opts = parser_.opts;
-    return (opts.scoped_enums ? "enum class " : "enum ") + enum_def.name;
+    return (opts.scoped_enums ? "enum class " : "enum ") + Name(enum_def);
   }
 
   std::string GenEnumValDecl(const EnumDef &enum_def,
                              const std::string &enum_val) const {
     const IDLOptions &opts = parser_.opts;
-    return opts.prefixed_enums ? enum_def.name + "_" + enum_val : enum_val;
+    return opts.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val;
   }
 
   std::string GetEnumValUse(const EnumDef &enum_def,
                             const EnumVal &enum_val) const {
     const IDLOptions &opts = parser_.opts;
     if (opts.scoped_enums) {
-      return enum_def.name + "::" + enum_val.name;
+      return Name(enum_def) + "::" + Name(enum_val);
     } else if (opts.prefixed_enums) {
-      return enum_def.name + "_" + enum_val.name;
+      return Name(enum_def) + "_" + Name(enum_val);
     } else {
-      return enum_val.name;
+      return Name(enum_val);
     }
   }
 
-  static std::string UnionVerifySignature(const EnumDef &enum_def) {
-    return "bool Verify" + enum_def.name +
-           "(flatbuffers::Verifier &verifier, const void *obj, " +
-           enum_def.name + " type)";
+  std::string StripUnionType(const std::string &name) {
+    return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix()));
   }
 
-  static std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
-    return "bool Verify" + enum_def.name + "Vector" +
+  std::string GetUnionElement(const EnumVal &ev, bool wrap, bool actual_type,
+                              bool native_type = false) {
+    if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+      auto name = actual_type ? ev.union_type.struct_def->name : Name(ev);
+      return wrap
+          ? WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name)
+          : name;
+    } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+      return actual_type
+          ? (native_type ? "std::string" : "flatbuffers::String")
+          : Name(ev);
+    } else {
+      assert(false);
+      return Name(ev);
+    }
+  }
+
+  std::string UnionVerifySignature(const EnumDef &enum_def) {
+    return "bool Verify" + Name(enum_def) +
+           "(flatbuffers::Verifier &verifier, const void *obj, " +
+           Name(enum_def) + " type)";
+  }
+
+  std::string UnionVectorVerifySignature(const EnumDef &enum_def) {
+    return "bool Verify" + Name(enum_def) + "Vector" +
            "(flatbuffers::Verifier &verifier, " +
            "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " +
            "const flatbuffers::Vector<uint8_t> *types)";
   }
 
-  static std::string UnionUnPackSignature(const EnumDef &enum_def,
+  std::string UnionUnPackSignature(const EnumDef &enum_def,
                                           bool inclass) {
     return (inclass ? "static " : "") +
-           std::string("flatbuffers::NativeTable *") +
-           (inclass ? "" : enum_def.name + "Union::") +
-           "UnPack(const void *obj, " + enum_def.name +
+           std::string("void *") +
+           (inclass ? "" : Name(enum_def) + "Union::") +
+           "UnPack(const void *obj, " + Name(enum_def) +
            " type, const flatbuffers::resolver_function_t *resolver)";
   }
 
-  static std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
+  std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) {
     return "flatbuffers::Offset<void> " +
-           (inclass ? "" : enum_def.name + "Union::") +
+           (inclass ? "" : Name(enum_def) + "Union::") +
            "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
            "const flatbuffers::rehasher_function_t *_rehasher" +
            (inclass ? " = nullptr" : "") + ") const";
   }
 
-  static std::string TableCreateSignature(const StructDef &struct_def,
-                                          bool predecl) {
-    return "flatbuffers::Offset<" + struct_def.name + "> Create" +
-           struct_def.name  +
+  std::string TableCreateSignature(const StructDef &struct_def,
+                                          bool predecl,
+                                          const IDLOptions & opts) {
+    return "flatbuffers::Offset<" + Name(struct_def) + "> Create" +
+           Name(struct_def)  +
            "(flatbuffers::FlatBufferBuilder &_fbb, const " +
-           NativeName(struct_def.name) +
+           NativeName(Name(struct_def), &struct_def, opts) +
            " *_o, const flatbuffers::rehasher_function_t *_rehasher" +
            (predecl ? " = nullptr" : "") + ")";
   }
 
-  static std::string TablePackSignature(const StructDef &struct_def,
-                                        bool inclass) {
+  std::string TablePackSignature(const StructDef &struct_def,
+                                        bool inclass,
+                                        const IDLOptions & opts) {
     return std::string(inclass ? "static " : "") +
-           "flatbuffers::Offset<" + struct_def.name + "> " +
-           (inclass ? "" : struct_def.name + "::") +
+           "flatbuffers::Offset<" + Name(struct_def) + "> " +
+           (inclass ? "" : Name(struct_def) + "::") +
            "Pack(flatbuffers::FlatBufferBuilder &_fbb, " +
-           "const " + NativeName(struct_def.name) + "* _o, " +
+           "const " + NativeName(Name(struct_def), &struct_def, opts) + "* _o, " +
            "const flatbuffers::rehasher_function_t *_rehasher" +
            (inclass ? " = nullptr" : "") + ")";
   }
 
-  static std::string TableUnPackSignature(const StructDef &struct_def,
-                                          bool inclass) {
-    return NativeName(struct_def.name) + " *" +
-           (inclass ? "" : struct_def.name + "::") +
+  std::string TableUnPackSignature(const StructDef &struct_def,
+                                          bool inclass,
+                                          const IDLOptions & opts) {
+    return NativeName(Name(struct_def), &struct_def, opts) + " *" +
+           (inclass ? "" : Name(struct_def) + "::") +
            "UnPack(const flatbuffers::resolver_function_t *_resolver" +
            (inclass ? " = nullptr" : "") + ") const";
   }
 
-  static std::string TableUnPackToSignature(const StructDef &struct_def,
-                                            bool inclass) {
-    return "void " + (inclass ? "" : struct_def.name + "::") +
-           "UnPackTo(" + NativeName(struct_def.name) + " *" + "_o, " +
-           "const flatbuffers::resolver_function_t *_resolver" +
+  std::string TableUnPackToSignature(const StructDef &struct_def,
+                                            bool inclass,
+                                            const IDLOptions & opts) {
+    return "void " + (inclass ? "" : Name(struct_def) + "::") +
+           "UnPackTo(" + NativeName(Name(struct_def), &struct_def, opts) + " *" +
+           "_o, const flatbuffers::resolver_function_t *_resolver" +
            (inclass ? " = nullptr" : "") + ") const";
   }
 
-  // Generate an enum declaration and an enum string lookup table.
+  void GenMiniReflectPre(const StructDef *struct_def) {
+    code_.SetValue("NAME", struct_def->name);
+    code_ += "inline flatbuffers::TypeTable *{{NAME}}TypeTable();";
+    code_ += "";
+  }
+
+  void GenMiniReflect(const StructDef *struct_def,
+                      const EnumDef *enum_def) {
+    code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name);
+    code_.SetValue("SEQ_TYPE", struct_def
+                   ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE")
+                   : (enum_def->is_union ? "ST_UNION" : "ST_ENUM"));
+    auto num_fields = struct_def
+                      ? struct_def->fields.vec.size()
+                      : enum_def->vals.vec.size();
+    code_.SetValue("NUM_FIELDS", NumToString(num_fields));
+    std::vector<std::string> names;
+    std::vector<Type> types;
+    bool consecutive_enum_from_zero = true;
+    if (struct_def) {
+      for (auto it = struct_def->fields.vec.begin();
+           it != struct_def->fields.vec.end(); ++it) {
+        const auto &field = **it;
+        names.push_back(Name(field));
+        types.push_back(field.value.type);
+      }
+    } else {
+      for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end();
+           ++it) {
+        const auto &ev = **it;
+        names.push_back(Name(ev));
+        types.push_back(enum_def->is_union ? ev.union_type
+                                           : Type(enum_def->underlying_type));
+        if (static_cast<int64_t>(it - enum_def->vals.vec.begin()) != ev.value) {
+          consecutive_enum_from_zero = false;
+        }
+      }
+    }
+    std::string ts;
+    std::vector<std::string> type_refs;
+    for (auto it = types.begin(); it != types.end(); ++it) {
+      auto &type = *it;
+      if (!ts.empty()) ts += ",\n    ";
+      auto is_vector = type.base_type == BASE_TYPE_VECTOR;
+      auto bt = is_vector ? type.element : type.base_type;
+      auto et = IsScalar(bt) || bt == BASE_TYPE_STRING
+                  ? bt - BASE_TYPE_UTYPE + ET_UTYPE
+                  : ET_SEQUENCE;
+      int ref_idx = -1;
+      std::string ref_name = type.struct_def
+                              ? WrapInNameSpace(*type.struct_def)
+                              : type.enum_def
+                                ? WrapInNameSpace(*type.enum_def)
+                                : "";
+      if (!ref_name.empty()) {
+        auto rit = type_refs.begin();
+        for (; rit != type_refs.end(); ++rit) {
+          if (*rit == ref_name) {
+            ref_idx = static_cast<int>(rit - type_refs.begin());
+            break;
+          }
+        }
+        if (rit == type_refs.end()) {
+          ref_idx = static_cast<int>(type_refs.size());
+          type_refs.push_back(ref_name);
+        }
+      }
+      ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " +
+            NumToString(is_vector) + ", " + NumToString(ref_idx) + " }";
+    }
+    std::string rs;
+    for (auto it = type_refs.begin(); it != type_refs.end(); ++it) {
+      if (!rs.empty()) rs += ",\n    ";
+      rs += *it + "TypeTable";
+    }
+    std::string ns;
+    for (auto it = names.begin(); it != names.end(); ++it) {
+      if (!ns.empty()) ns += ",\n    ";
+      ns += "\"" + *it + "\"";
+    }
+    std::string vs;
+    if (enum_def && !consecutive_enum_from_zero) {
+      for (auto it = enum_def->vals.vec.begin(); it != enum_def->vals.vec.end();
+           ++it) {
+        const auto &ev = **it;
+        if (!vs.empty()) vs += ", ";
+        vs += NumToString(ev.value);
+      }
+    } else if (struct_def && struct_def->fixed) {
+      for (auto it = struct_def->fields.vec.begin();
+           it != struct_def->fields.vec.end(); ++it) {
+        const auto &field = **it;
+        vs += NumToString(field.value.offset);
+        vs += ", ";
+      }
+      vs += NumToString(struct_def->bytesize);
+    }
+    code_.SetValue("TYPES", ts);
+    code_.SetValue("REFS", rs);
+    code_.SetValue("NAMES", ns);
+    code_.SetValue("VALUES", vs);
+    code_ += "inline flatbuffers::TypeTable *{{NAME}}TypeTable() {";
+    if (num_fields) {
+      code_ += "  static flatbuffers::TypeCode type_codes[] = {";
+      code_ += "    {{TYPES}}";
+      code_ += "  };";
+    }
+    if (!type_refs.empty()) {
+      code_ += "  static flatbuffers::TypeFunction type_refs[] = {";
+      code_ += "    {{REFS}}";
+      code_ += "  };";
+    }
+    if (!vs.empty()) {
+      code_ += "  static const int32_t values[] = { {{VALUES}} };";
+    }
+    auto has_names = num_fields &&
+           parser_.opts.mini_reflect == IDLOptions::kTypesAndNames;
+    if (has_names) {
+      code_ += "  static const char *names[] = {";
+      code_ += "    {{NAMES}}";
+      code_ += "  };";
+    }
+    code_ += "  static flatbuffers::TypeTable tt = {";
+    code_ += std::string("    flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") +
+             (num_fields ? "type_codes, " : "nullptr, ") +
+             (!type_refs.empty() ? "type_refs, ": "nullptr, " ) +
+             (!vs.empty() ? "values, " : "nullptr, ") +
+             (has_names ? "names" : "nullptr");
+    code_ += "  };";
+    code_ += "  return &tt;";
+    code_ += "}";
+    code_ += "";
+  }
+
+  // Generate an enum declaration,
+  // an enum string lookup table,
+  // and an enum array of values
   void GenEnum(const EnumDef &enum_def) {
-    code_.SetValue("ENUM_NAME", enum_def.name);
+    code_.SetValue("ENUM_NAME", Name(enum_def));
     code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false));
     code_.SetValue("SEP", "");
 
@@ -535,7 +793,7 @@
       const auto &ev = **it;
 
       GenComment(ev.doc_comment, "  ");
-      code_.SetValue("KEY", GenEnumValDecl(enum_def, ev.name));
+      code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev)));
       code_.SetValue("VALUE", NumToString(ev.value));
       code_ += "{{SEP}}  {{KEY}} = {{VALUE}}\\";
       code_.SetValue("SEP", ",\n");
@@ -575,6 +833,22 @@
     }
     code_ += "";
 
+    // Generate an array of all enumeration values
+    auto num_fields = NumToString(enum_def.vals.vec.size());
+    code_ += "inline {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + num_fields + "] {";
+    code_ += "  static {{ENUM_NAME}} values[] = {";
+    for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+         ++it) {
+      const auto &ev = **it;
+      auto value = GetEnumValUse(enum_def, ev);
+      auto suffix = *it != enum_def.vals.vec.back() ? "," : "";
+      code_ +=  "    " + value + suffix;
+    }
+    code_ += "  };";
+    code_ += "  return values;";
+    code_ += "}";
+    code_ += "";
+
     // Generate a generate string table for enum values.
     // Problem is, if values are very sparse that could generate really big
     // tables. Ideally in that case we generate a map lookup instead, but for
@@ -596,7 +870,7 @@
         while (val++ != ev.value) {
           code_ += "    \"\",";
         }
-        code_ += "    \"" + ev.name + "\",";
+        code_ += "    \"" + Name(ev) + "\",";
       }
       code_ += "    nullptr";
       code_ += "  };";
@@ -620,7 +894,7 @@
     }
 
     // Generate type traits for unions to map from a type to union enum value.
-    if (enum_def.is_union) {
+    if (enum_def.is_union && !enum_def.uses_type_aliases) {
       for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
         ++it) {
         const auto &ev = **it;
@@ -629,7 +903,7 @@
           code_ += "template<typename T> struct {{ENUM_NAME}}Traits {";
         }
         else {
-          auto name = WrapInNameSpace(*ev.struct_def);
+          auto name = GetUnionElement(ev, true, true);
           code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {";
         }
 
@@ -642,32 +916,40 @@
 
     if (parser_.opts.generate_object_based_api && enum_def.is_union) {
       // Generate a union type
-      code_.SetValue("NAME", enum_def.name);
+      code_.SetValue("NAME", Name(enum_def));
       code_.SetValue("NONE",
           GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
 
       code_ += "struct {{NAME}}Union {";
       code_ += "  {{NAME}} type;";
-      code_ += "  flatbuffers::NativeTable *table;";
+      code_ += "  void *value;";
       code_ += "";
-      code_ += "  {{NAME}}Union() : type({{NONE}}), table(nullptr) {}";
-      code_ += "  {{NAME}}Union({{NAME}}Union&& u):";
-      code_ += "    type(std::move(u.type)), table(std::move(u.table)) {}";
-      code_ += "  {{NAME}}Union(const {{NAME}}Union &);";
-      code_ += "  {{NAME}}Union &operator=(const {{NAME}}Union &);";
+      code_ += "  {{NAME}}Union() : type({{NONE}}), value(nullptr) {}";
+      code_ += "  {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :";
+      code_ += "    type({{NONE}}), value(nullptr)";
+      code_ += "    { std::swap(type, u.type); std::swap(value, u.value); }";
+      code_ += "  {{NAME}}Union(const {{NAME}}Union &) FLATBUFFERS_NOEXCEPT;";
+      code_ += "  {{NAME}}Union &operator=(const {{NAME}}Union &u) FLATBUFFERS_NOEXCEPT";
+      code_ += "    { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }";
+      code_ += "  {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT";
+      code_ += "    { std::swap(type, u.type); std::swap(value, u.value); return *this; }";
       code_ += "  ~{{NAME}}Union() { Reset(); }";
       code_ += "";
       code_ += "  void Reset();";
       code_ += "";
-      code_ += "  template <typename T>";
-      code_ += "  void Set(T&& value) {";
-      code_ += "    Reset();";
-      code_ += "    type = {{NAME}}Traits<typename T::TableType>::enum_value;";
-      code_ += "    if (type != {{NONE}}) {";
-      code_ += "      table = new T(std::forward<T>(value));";
-      code_ += "    }";
-      code_ += "  }";
-      code_ += "";
+      if (!enum_def.uses_type_aliases) {
+        code_ += "#ifndef FLATBUFFERS_CPP98_STL";
+        code_ += "  template <typename T>";
+        code_ += "  void Set(T&& val) {";
+        code_ += "    Reset();";
+        code_ += "    type = {{NAME}}Traits<typename T::TableType>::enum_value;";
+        code_ += "    if (type != {{NONE}}) {";
+        code_ += "      value = new T(std::forward<T>(val));";
+        code_ += "    }";
+        code_ += "  }";
+        code_ += "#endif  // FLATBUFFERS_CPP98_STL";
+        code_ += "";
+      }
       code_ += "  " + UnionUnPackSignature(enum_def, true) + ";";
       code_ += "  " + UnionPackSignature(enum_def, true) + ";";
       code_ += "";
@@ -679,14 +961,21 @@
           continue;
         }
 
-        const auto native_type = NativeName(WrapInNameSpace(*ev.struct_def));
+        const auto native_type =
+            NativeName(GetUnionElement(ev, true, true, true),
+                       ev.union_type.struct_def, parser_.opts);
         code_.SetValue("NATIVE_TYPE", native_type);
-        code_.SetValue("NATIVE_NAME", ev.name);
+        code_.SetValue("NATIVE_NAME", Name(ev));
         code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev));
 
         code_ += "  {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {";
         code_ += "    return type == {{NATIVE_ID}} ?";
-        code_ += "      reinterpret_cast<{{NATIVE_TYPE}} *>(table) : nullptr;";
+        code_ += "      reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;";
+        code_ += "  }";
+
+        code_ += "  const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {";
+        code_ += "    return type == {{NATIVE_ID}} ?";
+        code_ += "      reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;";
         code_ += "  }";
       }
       code_ += "};";
@@ -706,7 +995,7 @@
     // verifier function to call, this should be safe even if the union type
     // has been corrupted, since the verifiers will simply fail when called
     // on the wrong type.
-    code_.SetValue("ENUM_NAME", enum_def.name);
+    code_.SetValue("ENUM_NAME", Name(enum_def));
 
     code_ += "inline " + UnionVerifySignature(enum_def) + " {";
     code_ += "  switch (type) {";
@@ -716,10 +1005,23 @@
       code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
 
       if (ev.value) {
-        code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
+        code_.SetValue("TYPE", GetUnionElement(ev, true, true));
         code_ += "    case {{LABEL}}: {";
-        code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
-        code_ += "      return verifier.VerifyTable(ptr);";
+        auto getptr =
+            "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return true;";
+          } else {
+            code_ += getptr;
+            code_ += "      return verifier.VerifyTable(ptr);";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += getptr;
+          code_ += "      return verifier.Verify(ptr);";
+        } else {
+          assert(false);
+        }
         code_ += "    }";
       } else {
         code_ += "    case {{LABEL}}: {";
@@ -735,8 +1037,8 @@
     code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {";
     code_ += "  if (values->size() != types->size()) return false;";
     code_ += "  for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {";
-    code_ += "    if (!Verify" + enum_def.name + "(";
-    code_ += "        verifier,  values->Get(i), types->GetEnum<" + enum_def.name + ">(i))) {";
+    code_ += "    if (!Verify" + Name(enum_def) + "(";
+    code_ += "        verifier,  values->Get(i), types->GetEnum<" + Name(enum_def) + ">(i))) {";
     code_ += "      return false;";
     code_ += "    }";
     code_ += "  }";
@@ -756,10 +1058,21 @@
         }
 
         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
-        code_.SetValue("TYPE", WrapInNameSpace(*ev.struct_def));
+        code_.SetValue("TYPE", GetUnionElement(ev, true, true));
         code_ += "    case {{LABEL}}: {";
         code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);";
-        code_ += "      return ptr->UnPack(resolver);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return new " +
+                     WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);";
+          } else {
+            code_ += "      return ptr->UnPack(resolver);";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += "      return new std::string(ptr->c_str(), ptr->size());";
+        } else {
+          assert(false);
+        }
         code_ += "    }";
       }
       code_ += "    default: return nullptr;";
@@ -777,11 +1090,23 @@
         }
 
         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
-        code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
-        code_.SetValue("NAME", ev.struct_def->name);
+        code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+                                          ev.union_type.struct_def, parser_.opts));
+        code_.SetValue("NAME", GetUnionElement(ev, false, true));
         code_ += "    case {{LABEL}}: {";
-        code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(table);";
-        code_ += "      return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+        code_ += "      auto ptr = reinterpret_cast<const {{TYPE}} *>(value);";
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          if (ev.union_type.struct_def->fixed) {
+            code_ += "      return _fbb.CreateStruct(*ptr).Union();";
+          } else {
+            code_ +=
+                "      return Create{{NAME}}(_fbb, ptr, _rehasher).Union();";
+          }
+        } else if (ev.union_type.base_type == BASE_TYPE_STRING) {
+          code_ += "      return _fbb.CreateString(*ptr).Union();";
+        } else {
+          assert(false);
+        }
         code_ += "    }";
       }
       code_ += "    default: return 0;";
@@ -789,6 +1114,49 @@
       code_ += "}";
       code_ += "";
 
+      // Union copy constructor
+      code_ += "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const "
+               "{{ENUM_NAME}}Union &u) FLATBUFFERS_NOEXCEPT : type(u.type), "
+               "value(nullptr) {";
+      code_ += "  switch (type) {";
+      for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+           ++it) {
+        const auto &ev = **it;
+        if (!ev.value) {
+          continue;
+        }
+        code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
+        code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+                                          ev.union_type.struct_def, parser_.opts));
+        code_ += "    case {{LABEL}}: {";
+        bool copyable = true;
+        if (ev.union_type.base_type == BASE_TYPE_STRUCT) {
+          // Don't generate code to copy if table is not copyable.
+          // TODO(wvo): make tables copyable instead.
+          for (auto fit = ev.union_type.struct_def->fields.vec.begin();
+               fit != ev.union_type.struct_def->fields.vec.end(); ++fit) {
+            const auto &field = **fit;
+            if (!field.deprecated && field.value.type.struct_def) {
+              copyable = false;
+              break;
+            }
+          }
+        }
+        if (copyable) {
+          code_ += "      value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>"
+                   "(u.value));";
+        } else {
+          code_ += "      assert(false);  // {{TYPE}} not copyable.";
+        }
+        code_ += "      break;";
+        code_ += "    }";
+      }
+      code_ += "    default:";
+      code_ += "      break;";
+      code_ += "  }";
+      code_ += "}";
+      code_ += "";
+
       // Union Reset() function.
       code_.SetValue("NONE",
           GetEnumValUse(enum_def, *enum_def.vals.Lookup("NONE")));
@@ -801,19 +1169,18 @@
         if (!ev.value) {
           continue;
         }
-
         code_.SetValue("LABEL", GetEnumValUse(enum_def, ev));
-        code_.SetValue("TYPE", NativeName(WrapInNameSpace(*ev.struct_def)));
-
+        code_.SetValue("TYPE", NativeName(GetUnionElement(ev, true, true, true),
+                                          ev.union_type.struct_def, parser_.opts));
         code_ += "    case {{LABEL}}: {";
-        code_ += "      auto ptr = reinterpret_cast<{{TYPE}} *>(table);";
+        code_ += "      auto ptr = reinterpret_cast<{{TYPE}} *>(value);";
         code_ += "      delete ptr;";
         code_ += "      break;";
         code_ += "    }";
       }
       code_ += "    default: break;";
       code_ += "  }";
-      code_ += "  table = nullptr;";
+      code_ += "  value = nullptr;";
       code_ += "  type = {{NONE}};";
       code_ += "}";
       code_ += "";
@@ -839,20 +1206,19 @@
   }
 
   std::string GenFieldOffsetName(const FieldDef &field) {
-    std::string uname = field.name;
-    std::transform(uname.begin(), uname.end(), uname.begin(), ::toupper);
+    std::string uname = Name(field);
+    std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper);
     return "VT_" + uname;
   }
 
-  void GenFullyQualifiedNameGetter(const std::string &name) {
+  void GenFullyQualifiedNameGetter(const StructDef &struct_def,
+                                   const std::string &name) {
     if (!parser_.opts.generate_name_strings) {
       return;
     }
-
-    auto fullname = parser_.namespaces_.back()->GetFullyQualifiedName(name);
+    auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name);
     code_.SetValue("NAME", fullname);
     code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR");
-
     code_ += "  static {{CONSTEXPR}} const char *GetFullyQualifiedName() {";
     code_ += "    return \"{{NAME}}\";";
     code_ += "  }";
@@ -884,7 +1250,7 @@
 
   void GenParam(const FieldDef &field, bool direct, const char *prefix) {
     code_.SetValue("PRE", prefix);
-    code_.SetValue("PARAM_NAME", field.name);
+    code_.SetValue("PARAM_NAME", Name(field));
     if (direct && field.value.type.base_type == BASE_TYPE_STRING) {
       code_.SetValue("PARAM_TYPE", "const char *");
       code_.SetValue("PARAM_VALUE", "nullptr");
@@ -902,12 +1268,14 @@
   // Generate a member, including a default value for scalars and raw pointers.
   void GenMember(const FieldDef &field) {
     if (!field.deprecated &&  // Deprecated fields won't be accessible.
-        field.value.type.base_type != BASE_TYPE_UTYPE) {
+        field.value.type.base_type != BASE_TYPE_UTYPE &&
+        (field.value.type.base_type != BASE_TYPE_VECTOR ||
+         field.value.type.element != BASE_TYPE_UTYPE)) {
       auto type = GenTypeNative(field.value.type, false, field);
       auto cpp_type = field.attributes.Lookup("cpp_type");
       auto full_type = (cpp_type ? cpp_type->constant + " *" : type + " ");
       code_.SetValue("FIELD_TYPE", full_type);
-      code_.SetValue("FIELD_NAME", field.name);
+      code_.SetValue("FIELD_NAME", Name(field));
       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}};";
     }
   }
@@ -927,7 +1295,7 @@
           if (!initializer_list.empty()) {
             initializer_list += ",\n        ";
           }
-          initializer_list += field.name;
+          initializer_list += Name(field);
           initializer_list += "(" + GetDefaultScalarValue(field) + ")";
         } else if (field.value.type.base_type == BASE_TYPE_STRUCT) {
           if (IsStruct(field.value.type)) {
@@ -937,14 +1305,14 @@
                 initializer_list += ",\n        ";
               }
               initializer_list +=
-                  field.name + "(" + native_default->constant + ")";
+                  Name(field) + "(" + native_default->constant + ")";
             }
           }
         } else if (cpp_type) {
           if (!initializer_list.empty()) {
             initializer_list += ",\n        ";
           }
-          initializer_list += field.name + "(0)";
+          initializer_list += Name(field) + "(0)";
         }
       }
     }
@@ -952,26 +1320,38 @@
       initializer_list = "\n      : " + initializer_list;
     }
 
-    code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
+    code_.SetValue("NATIVE_NAME", NativeName(Name(struct_def), &struct_def, parser_.opts));
     code_.SetValue("INIT_LIST", initializer_list);
 
     code_ += "  {{NATIVE_NAME}}(){{INIT_LIST}} {";
     code_ += "  }";
   }
 
+  void GenOperatorNewDelete(const StructDef & struct_def) {
+    if (auto native_custom_alloc = struct_def.attributes.Lookup("native_custom_alloc")) {
+      code_ += "  inline void *operator new (std::size_t count) {";
+      code_ += "    return " + native_custom_alloc->constant + "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));";
+      code_ += "  }";
+      code_ += "  inline void operator delete (void *ptr) {";
+      code_ += "    return " + native_custom_alloc->constant + "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>(ptr),1);";
+      code_ += "  }";
+    }
+  }
+
   void GenNativeTable(const StructDef &struct_def) {
-    const auto native_name = NativeName(struct_def.name);
-    code_.SetValue("STRUCT_NAME", struct_def.name);
+    const auto native_name = NativeName(Name(struct_def), &struct_def, parser_.opts);
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
     code_.SetValue("NATIVE_NAME", native_name);
 
     // Generate a C++ object that can hold an unpacked version of this table.
     code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {";
     code_ += "  typedef {{STRUCT_NAME}} TableType;";
-    GenFullyQualifiedNameGetter(native_name);
+    GenFullyQualifiedNameGetter(struct_def, native_name);
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
       GenMember(**it);
     }
+    GenOperatorNewDelete(struct_def);
     GenDefaultConstructor(struct_def);
     code_ += "};";
     code_ += "";
@@ -980,11 +1360,16 @@
   // Generate the code to call the appropriate Verify function(s) for a field.
   void GenVerifyCall(const FieldDef &field, const char* prefix) {
     code_.SetValue("PRE", prefix);
-    code_.SetValue("NAME", field.name);
+    code_.SetValue("NAME", Name(field));
     code_.SetValue("REQUIRED", field.required ? "Required" : "");
     code_.SetValue("SIZE", GenTypeSize(field.value.type));
     code_.SetValue("OFFSET", GenFieldOffsetName(field));
-    code_ += "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+    if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) {
+      code_ +=
+          "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\";
+    } else {
+      code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\";
+    }
 
     switch (field.value.type.base_type) {
       case BASE_TYPE_UNION: {
@@ -1044,14 +1429,14 @@
     // type name() const { return GetField<type>(offset, defaultval); }
     GenComment(struct_def.doc_comment);
 
-    code_.SetValue("STRUCT_NAME", struct_def.name);
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
     code_ += "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS"
             " : private flatbuffers::Table {";
     if (parser_.opts.generate_object_based_api) {
       code_ += "  typedef {{NATIVE_NAME}} NativeTableType;";
     }
 
-    GenFullyQualifiedNameGetter(struct_def.name);
+    GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
 
     // Generate field id constants.
     if (struct_def.fields.vec.size() > 0) {
@@ -1087,7 +1472,7 @@
 
       const bool is_struct = IsStruct(field.value.type);
       const bool is_scalar = IsScalar(field.value.type.base_type);
-      code_.SetValue("FIELD_NAME", field.name);
+      code_.SetValue("FIELD_NAME", Name(field));
 
       // Call a different accessor for pointers, that indirects.
       std::string accessor = "";
@@ -1109,28 +1494,66 @@
       }
       call += ")";
 
+      std::string afterptr = " *" + NullableExtension();
       GenComment(field.doc_comment, "  ");
       code_.SetValue("FIELD_TYPE",
-          GenTypeGet(field.value.type, " ", "const ", " *", true));
+          GenTypeGet(field.value.type, " ", "const ", afterptr.c_str(), true));
       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
+      code_.SetValue("NULLABLE_EXT", NullableExtension());
 
       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
       code_ += "    return {{FIELD_VALUE}};";
       code_ += "  }";
 
+      if (field.value.type.base_type == BASE_TYPE_UNION) {
+        auto u = field.value.type.enum_def;
+
+        code_ += "  template<typename T> "
+                "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;";
+
+        for (auto u_it = u->vals.vec.begin();
+             u_it != u->vals.vec.end(); ++u_it) {
+          auto &ev = **u_it;
+          if (ev.union_type.base_type == BASE_TYPE_NONE) {
+            continue;
+          }
+          auto full_struct_name = GetUnionElement(ev, true, true);
+
+          // @TODO: Mby make this decisions more universal? How?
+          code_.SetValue("U_GET_TYPE", Name(field) + UnionTypeFieldSuffix());
+          code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
+                         u->defined_namespace, GetEnumValUse(*u, ev)));
+          code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+          code_.SetValue("U_FIELD_NAME",
+                         Name(field) + "_as_" + Name(ev));
+          code_.SetValue("U_NULLABLE", NullableExtension());
+
+          // `const Type *union_name_asType() const` accessor.
+          code_ += "  {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {";
+          code_ += "    return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? "
+                  "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) "
+                  ": nullptr;";
+          code_ += "  }";
+        }
+      }
+
       if (parser_.opts.mutable_buffer) {
         if (is_scalar) {
+          const auto type = GenTypeWire(field.value.type, "", false);
+          code_.SetValue("SET_FN", "SetField<" + type + ">");
           code_.SetValue("OFFSET_NAME", offset_str);
           code_.SetValue("FIELD_TYPE", GenTypeBasic(field.value.type, true));
           code_.SetValue("FIELD_VALUE",
-                        GenUnderlyingCast(field, false, "_" + field.name));
+                        GenUnderlyingCast(field, false, "_" + Name(field)));
+          code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field));
 
           code_ += "  bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} "
                   "_{{FIELD_NAME}}) {";
-          code_ += "    return SetField({{OFFSET_NAME}}, {{FIELD_VALUE}});";
+          code_ += "    return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, {{DEFAULT_VALUE}});";
           code_ += "  }";
         } else {
-          auto type = GenTypeGet(field.value.type, " ", "", " *", true);
+          auto postptr = " *" + NullableExtension();
+          auto type = GenTypeGet(field.value.type, " ", "", postptr.c_str(), true);
           auto underlying = accessor + type + ">(" + offset_str + ")";
           code_.SetValue("FIELD_TYPE", type);
           code_.SetValue("FIELD_VALUE",
@@ -1145,19 +1568,27 @@
       auto nested = field.attributes.Lookup("nested_flatbuffer");
       if (nested) {
         std::string qualified_name =
-            parser_.namespaces_.back()->GetFullyQualifiedName(
+            parser_.current_namespace_->GetFullyQualifiedName(
                 nested->constant);
-        auto nested_root = parser_.structs_.Lookup(qualified_name);
+        auto nested_root = parser_.LookupStruct(qualified_name);
         assert(nested_root);  // Guaranteed to exist by parser.
         (void)nested_root;
         code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name));
 
         code_ += "  const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {";
-        code_ += "    const uint8_t* data = {{FIELD_NAME}}()->Data();";
+        code_ += "    auto data = {{FIELD_NAME}}()->Data();";
         code_ += "    return flatbuffers::GetRoot<{{CPP_NAME}}>(data);";
         code_ += "  }";
       }
 
+      if (field.flexbuffer) {
+        code_ += "  flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()"
+                                                                     " const {";
+        code_ += "    auto v = {{FIELD_NAME}}();";
+        code_ += "    return flexbuffers::GetRoot(v->Data(), v->size());";
+        code_ += "  }";
+      }
+
       // Generate a comparison function for this field if it is a key.
       if (field.key) {
         const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING);
@@ -1214,26 +1645,66 @@
 
     if (parser_.opts.generate_object_based_api) {
       // Generate the UnPack() pre declaration.
-      code_ += "  " + TableUnPackSignature(struct_def, true) + ";";
-      code_ += "  " + TableUnPackToSignature(struct_def, true) + ";";
-      code_ += "  " + TablePackSignature(struct_def, true) + ";";
+      code_ += "  " + TableUnPackSignature(struct_def, true, parser_.opts) + ";";
+      code_ += "  " + TableUnPackToSignature(struct_def, true, parser_.opts) + ";";
+      code_ += "  " + TablePackSignature(struct_def, true, parser_.opts) + ";";
     }
 
     code_ += "};";  // End of table.
     code_ += "";
 
+    // Explicit specializations for union accessors
+    for (auto it = struct_def.fields.vec.begin();
+         it != struct_def.fields.vec.end(); ++it) {
+      const auto &field = **it;
+      if (field.deprecated ||
+          field.value.type.base_type != BASE_TYPE_UNION) {
+        continue;
+      }
+
+      auto u = field.value.type.enum_def;
+      if (u->uses_type_aliases) continue;
+
+      code_.SetValue("FIELD_NAME", Name(field));
+
+      for (auto u_it = u->vals.vec.begin();
+           u_it != u->vals.vec.end(); ++u_it) {
+        auto &ev = **u_it;
+        if (ev.union_type.base_type == BASE_TYPE_NONE) {
+          continue;
+        }
+
+        auto full_struct_name = GetUnionElement(ev, true, true);
+
+        code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(
+                       u->defined_namespace, GetEnumValUse(*u, ev)));
+        code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *");
+        code_.SetValue("U_ELEMENT_NAME", full_struct_name);
+        code_.SetValue("U_FIELD_NAME",
+                       Name(field) + "_as_" + Name(ev));
+
+        // `template<> const T *union_name_as<T>() const` accessor.
+        code_ += "template<> "
+                "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as"
+                "<{{U_ELEMENT_NAME}}>() const {";
+        code_ += "  return {{U_FIELD_NAME}}();";
+        code_ += "}";
+        code_ += "";
+      }
+    }
+
     GenBuilders(struct_def);
 
     if (parser_.opts.generate_object_based_api) {
       // Generate a pre-declaration for a CreateX method that works with an
       // unpacked C++ object.
-      code_ += TableCreateSignature(struct_def, true) + ";";
+      code_ += TableCreateSignature(struct_def, true, parser_.opts) + ";";
       code_ += "";
     }
   }
 
   void GenBuilders(const StructDef &struct_def) {
-    code_.SetValue("STRUCT_NAME", struct_def.name);
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
 
     // Generate a builder struct:
     code_ += "struct {{STRUCT_NAME}}Builder {";
@@ -1253,16 +1724,16 @@
         }
 
         std::string offset = GenFieldOffsetName(field);
-        std::string name = GenUnderlyingCast(field, false, field.name);
+        std::string name = GenUnderlyingCast(field, false, Name(field));
         std::string value = is_scalar ? GenDefaultConstant(field) : "";
 
         // Generate accessor functions of the form:
         // void add_name(type name) {
         //   fbb_.AddElement<type>(offset, name, default);
         // }
-        code_.SetValue("FIELD_NAME", field.name);
+        code_.SetValue("FIELD_NAME", Name(field));
         code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true));
-        code_.SetValue("ADD_OFFSET", struct_def.name + "::" + offset);
+        code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset);
         code_.SetValue("ADD_NAME", name);
         code_.SetValue("ADD_VALUE", value);
         if (is_scalar) {
@@ -1286,7 +1757,7 @@
     }
 
     // Builder constructor
-    code_ += "  {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder &_fbb)";
+    code_ += "  explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder &_fbb)";
     code_ += "        : fbb_(_fbb) {";
     code_ += "    start_ = fbb_.StartTable();";
     code_ += "  }";
@@ -1296,16 +1767,15 @@
              "(const {{STRUCT_NAME}}Builder &);";
 
     // Finish() function.
-    auto num_fields = NumToString(struct_def.fields.vec.size());
     code_ += "  flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {";
-    code_ += "    const auto end = fbb_.EndTable(start_, " + num_fields + ");";
+    code_ += "    const auto end = fbb_.EndTable(start_);";
     code_ += "    auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);";
 
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
       const auto &field = **it;
       if (!field.deprecated && field.required) {
-        code_.SetValue("FIELD_NAME", field.name);
+        code_.SetValue("FIELD_NAME", Name(field));
         code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field));
         code_ += "    fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});";
       }
@@ -1337,7 +1807,7 @@
         const auto &field = **it;
         if (!field.deprecated && (!struct_def.sortbysize ||
                                   size == SizeOf(field.value.type.base_type))) {
-          code_.SetValue("FIELD_NAME", field.name);
+          code_.SetValue("FIELD_NAME", Name(field));
           code_ += "  builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});";
         }
       }
@@ -1370,7 +1840,7 @@
            it != struct_def.fields.vec.end(); ++it) {
         const auto &field = **it;
         if (!field.deprecated) {
-          code_.SetValue("FIELD_NAME", field.name);
+          code_.SetValue("FIELD_NAME", Name(field));
 
           if (field.value.type.base_type == BASE_TYPE_STRING) {
             code_ += ",\n      {{FIELD_NAME}} ? "
@@ -1390,6 +1860,14 @@
     }
   }
 
+  std::string GenUnionUnpackVal(const FieldDef &afield,
+                                const char *vec_elem_access,
+                                const char *vec_type_access) {
+    return afield.value.type.enum_def->name + "Union::UnPack(" + "_e" +
+           vec_elem_access + ", " + Name(afield) + UnionTypeFieldSuffix() +
+           "()" + vec_type_access + ", _resolver)";
+  }
+
   std::string GenUnpackVal(const Type &type, const std::string &val,
                            bool invector, const FieldDef &afield) {
     switch (type.base_type) {
@@ -1409,10 +1887,18 @@
             return ptype + "(new " + name + "(*" + val + "))";
           }
         } else {
-          const auto ptype = GenTypeNativePtr(NativeName(name), &afield, true);
+          const auto ptype = GenTypeNativePtr(NativeName(name, type.struct_def, parser_.opts),
+                                              &afield, true);
           return ptype + "(" + val + "->UnPack(_resolver))";
         }
       }
+      case BASE_TYPE_UNION: {
+        return GenUnionUnpackVal(afield,
+                                 invector ? "->Get(_i)" : "",
+                                 invector ? ("->GetEnum<" +
+                                             type.enum_def->name +
+                                             ">(_i)").c_str() : "");
+      }
       default: {
         return val;
         break;
@@ -1438,12 +1924,22 @@
         //   for (uoffset_t i = 0; i < _e->size(); ++i) {
         //     _o->field.push_back(_e->Get(_i));
         //   }
+        auto name = Name(field);
+        if (field.value.type.element == BASE_TYPE_UTYPE) {
+          name = StripUnionType(Name(field));
+        }
+        auto access = field.value.type.element == BASE_TYPE_UTYPE
+                        ? ".type"
+                        : (field.value.type.element == BASE_TYPE_UNION
+                          ? ".value"
+                          : "");
+        code += "{ _o->" + name + ".resize(_e->size()); ";
         code += "for (flatbuffers::uoffset_t _i = 0;";
         code += " _i < _e->size(); _i++) { ";
-        code += "_o->" + field.name + ".push_back(";
+        code += "_o->" + name + "[_i]" + access + " = ";
         code += GenUnpackVal(field.value.type.VectorType(),
                                   indexing, true, field);
-        code += "); }";
+        code += "; } }";
         break;
       }
       case BASE_TYPE_UTYPE: {
@@ -1454,12 +1950,11 @@
         break;
       }
       case BASE_TYPE_UNION: {
-        // Generate code that sets the union table, of the form:
-        //   _o->field.table = Union::Unpack(_e, field_type(), resolver);
-        code += "_o->" + field.name + ".table = ";
-        code += field.value.type.enum_def->name + "Union::UnPack(";
-        code += "_e, " + field.name + UnionTypeFieldSuffix() + "(),";
-        code += "_resolver);";
+        // Generate code that sets the union value, of the form:
+        //   _o->field.value = Union::Unpack(_e, field_type(), resolver);
+        code += "_o->" + Name(field) + ".value = ";
+        code += GenUnionUnpackVal(field, "", "");
+        code += ";";
         break;
       }
       default: {
@@ -1472,14 +1967,14 @@
           //    _o->field = nullptr;
           code += "if (_resolver) ";
           code += "(*_resolver)";
-          code += "(reinterpret_cast<void **>(&_o->" + field.name + "), ";
+          code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), ";
           code += "static_cast<flatbuffers::hash_value_t>(_e));";
           code += " else ";
-          code += "_o->" + field.name + " = nullptr;";
+          code += "_o->" + Name(field) + " = nullptr;";
         } else {
           // Generate code for assigning the value, of the form:
           //  _o->field = value;
-          code += "_o->" + field.name + " = ";
+          code += "_o->" + Name(field) + " = ";
           code += GenUnpackVal(field.value.type, "_e", false, field) + ";";
         }
         break;
@@ -1491,11 +1986,10 @@
   std::string GenCreateParam(const FieldDef &field) {
     std::string value = "_o->";
     if (field.value.type.base_type == BASE_TYPE_UTYPE) {
-      value += field.name.substr(0, field.name.size() -
-                                 strlen(UnionTypeFieldSuffix()));
+      value += StripUnionType(Name(field));
       value += ".type";
     } else {
-      value += field.name;
+      value += Name(field);
     }
     if (field.attributes.Lookup("cpp_type")) {
       auto type = GenTypeBasic(field.value.type, false);
@@ -1513,7 +2007,7 @@
         // For optional fields, check to see if there actually is any data
         // in _o->field before attempting to access it.
         if (!field.required) {
-          code = value + ".size() ? " + code + " : 0";
+          code = value + ".empty() ? 0 : " + code;
         }
         break;
       }
@@ -1534,14 +2028,24 @@
           }
           case BASE_TYPE_STRUCT: {
             if (IsStruct(vector_type)) {
-              code += "_fbb.CreateVectorOfStructs(" + value + ")";
+              auto native_type =
+                field.value.type.struct_def->attributes.Lookup("native_type");
+              if (native_type) {
+                code += "_fbb.CreateVectorOfNativeStructs<";
+                code += WrapInNameSpace(*vector_type.struct_def) + ">";
+              } else {
+                code += "_fbb.CreateVectorOfStructs";
+              }
+              code += "(" + value + ")";
             } else {
               code += "_fbb.CreateVector<flatbuffers::Offset<";
-              code += WrapInNameSpace(*vector_type.struct_def) + ">>";
-              code += "(" + value + ".size(), [&](size_t i) {";
-              code += " return Create" + vector_type.struct_def->name;
-              code += "(_fbb, " + value + "[i]" + GenPtrGet(field) + ", ";
-              code += "_rehasher); })";
+              code += WrapInNameSpace(*vector_type.struct_def) + ">> ";
+              code += "(" + value + ".size(), ";
+              code += "[](size_t i, _VectorArgs *__va) { ";
+              code += "return Create" + vector_type.struct_def->name;
+              code += "(*__va->__fbb, __va->_" + value + "[i]" +
+                      GenPtrGet(field) + ", ";
+              code += "__va->__rehasher); }, &_va )";
             }
             break;
           }
@@ -1549,6 +2053,22 @@
             code += "_fbb.CreateVector(" + value + ")";
             break;
           }
+          case BASE_TYPE_UNION: {
+            code += "_fbb.CreateVector<flatbuffers::"
+                    "Offset<void>>(" + value +
+                    ".size(), [](size_t i, _VectorArgs *__va) { "
+                    "return __va->_" + value +
+                    "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)";
+            break;
+          }
+          case BASE_TYPE_UTYPE: {
+            value = StripUnionType(value);
+            code += "_fbb.CreateVector<uint8_t>(" + value +
+                    ".size(), [](size_t i, _VectorArgs *__va) { "
+                    "return static_cast<uint8_t>(__va->_" + value +
+                    "[i].type); }, &_va)";
+            break;
+          }
           default: {
             if (field.value.type.enum_def) {
               // For enumerations, we need to get access to the array data for
@@ -1606,19 +2126,19 @@
 
   // Generate code for tables that needs to come after the regular definition.
   void GenTablePost(const StructDef &struct_def) {
-    code_.SetValue("STRUCT_NAME", struct_def.name);
-    code_.SetValue("NATIVE_NAME", NativeName(struct_def.name));
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
+    code_.SetValue("NATIVE_NAME", NativeName(Name(struct_def), &struct_def, parser_.opts));
 
     if (parser_.opts.generate_object_based_api) {
       // Generate the X::UnPack() method.
-      code_ += "inline " + TableUnPackSignature(struct_def, false) + " {";
+      code_ += "inline " + TableUnPackSignature(struct_def, false, parser_.opts) + " {";
       code_ += "  auto _o = new {{NATIVE_NAME}}();";
       code_ += "  UnPackTo(_o, _resolver);";
       code_ += "  return _o;";
       code_ += "}";
       code_ += "";
 
-      code_ += "inline " + TableUnPackToSignature(struct_def, false) + " {";
+      code_ += "inline " + TableUnPackToSignature(struct_def, false, parser_.opts) + " {";
       code_ += "  (void)_o;";
       code_ += "  (void)_resolver;";
 
@@ -1636,7 +2156,7 @@
         const auto statement =
             GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr);
 
-        code_.SetValue("FIELD_NAME", field.name);
+        code_.SetValue("FIELD_NAME", Name(field));
         auto prefix = "  { auto _e = {{FIELD_NAME}}(); ";
         auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) ";
         auto postfix = " };";
@@ -1647,23 +2167,32 @@
 
       // Generate the X::Pack member function that simply calls the global
       // CreateX function.
-      code_ += "inline " + TablePackSignature(struct_def, false) + " {";
+      code_ += "inline " + TablePackSignature(struct_def, false, parser_.opts) + " {";
       code_ += "  return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);";
       code_ += "}";
       code_ += "";
 
       // Generate a CreateX method that works with an unpacked C++ object.
-      code_ += "inline " + TableCreateSignature(struct_def, false) + " {";
+      code_ += "inline " + TableCreateSignature(struct_def, false, parser_.opts) + " {";
       code_ += "  (void)_rehasher;";
       code_ += "  (void)_o;";
 
+      code_ +=
+          "  struct _VectorArgs "
+          "{ flatbuffers::FlatBufferBuilder *__fbb; "
+          "const " +
+          NativeName(Name(struct_def), &struct_def, parser_.opts) +
+          "* __o; "
+          "const flatbuffers::rehasher_function_t *__rehasher; } _va = { "
+          "&_fbb, _o, _rehasher}; (void)_va;";
+
       for (auto it = struct_def.fields.vec.begin();
            it != struct_def.fields.vec.end(); ++it) {
         auto &field = **it;
         if (field.deprecated) {
           continue;
         }
-        code_ += "  auto _" + field.name + " = " + GenCreateParam(field) + ";";
+        code_ += "  auto _" + Name(field) + " = " + GenCreateParam(field) + ";";
       }
       // Need to call "Create" with the struct namespace.
       const auto qualified_create_name = struct_def.defined_namespace->GetFullyQualifiedName("Create");
@@ -1691,9 +2220,9 @@
 
         // Call the CreateX function using values from |_o|.
         if (pass_by_address) {
-          code_ += ",\n      &_" + field.name + "\\";
+          code_ += ",\n      &_" + Name(field) + "\\";
         } else {
-          code_ += ",\n      _" + field.name + "\\";
+          code_ += ",\n      _" + Name(field) + "\\";
         }
       }
       code_ += ");";
@@ -1739,7 +2268,7 @@
     // platforms.
     GenComment(struct_def.doc_comment);
     code_.SetValue("ALIGN", NumToString(struct_def.minalign));
-    code_.SetValue("STRUCT_NAME", struct_def.name);
+    code_.SetValue("STRUCT_NAME", Name(struct_def));
 
     code_ += "MANUALLY_ALIGNED_STRUCT({{ALIGN}}) "
             "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {";
@@ -1751,7 +2280,7 @@
       const auto &field = **it;
       code_.SetValue("FIELD_TYPE",
           GenTypeGet(field.value.type, " ", "", " ", false));
-      code_.SetValue("FIELD_NAME", field.name);
+      code_.SetValue("FIELD_NAME", Name(field));
       code_ += "  {{FIELD_TYPE}}{{FIELD_NAME}}_;";
 
       if (field.padding) {
@@ -1764,18 +2293,13 @@
     // Generate GetFullyQualifiedName
     code_ += "";
     code_ += " public:";
-    GenFullyQualifiedNameGetter(struct_def.name);
+    GenFullyQualifiedNameGetter(struct_def, Name(struct_def));
 
     // Generate a default constructor.
     code_ += "  {{STRUCT_NAME}}() {";
     code_ += "    memset(this, 0, sizeof({{STRUCT_NAME}}));";
     code_ += "  }";
 
-    // Generate a copy constructor.
-    code_ += "  {{STRUCT_NAME}}(const {{STRUCT_NAME}} &_o) {";
-    code_ += "    memcpy(this, &_o, sizeof({{STRUCT_NAME}}));";
-    code_ += "  }";
-
     // Generate a constructor that takes all fields as arguments.
     std::string arg_list;
     std::string init_list;
@@ -1783,8 +2307,8 @@
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
       const auto &field = **it;
-      const auto member_name = field.name + "_";
-      const auto arg_name = "_" + field.name;
+      const auto member_name = Name(field) + "_";
+      const auto arg_name = "_" + Name(field);
       const auto arg_type =
           GenTypeGet(field.value.type, " ", "const ", " &", true);
 
@@ -1830,11 +2354,11 @@
 
       auto field_type = GenTypeGet(field.value.type, " ", "const ", " &", true);
       auto is_scalar = IsScalar(field.value.type.base_type);
-      auto member = field.name + "_";
+      auto member = Name(field) + "_";
       auto value = is_scalar ? "flatbuffers::EndianScalar(" + member + ")"
                              : member;
 
-      code_.SetValue("FIELD_NAME", field.name);
+      code_.SetValue("FIELD_NAME", Name(field));
       code_.SetValue("FIELD_TYPE", field_type);
       code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value));
 
@@ -1844,10 +2368,12 @@
       code_ += "  }";
 
       if (parser_.opts.mutable_buffer) {
+        auto mut_field_type = GenTypeGet(field.value.type, " ", "", " &", true);
+        code_.SetValue("FIELD_TYPE", mut_field_type);
         if (is_scalar) {
           code_.SetValue("ARG", GenTypeBasic(field.value.type, true));
           code_.SetValue("FIELD_VALUE",
-                        GenUnderlyingCast(field, false, "_" + field.name));
+                        GenUnderlyingCast(field, false, "_" + Name(field)));
 
           code_ += "  void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {";
           code_ += "    flatbuffers::WriteScalar(&{{FIELD_NAME}}_, "
@@ -1859,7 +2385,27 @@
           code_ += "  }";
         }
       }
+
+      // Generate a comparison function for this field if it is a key.
+      if (field.key) {
+        code_ += "  bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {";
+        code_ += "    return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();";
+        code_ += "  }";
+        auto type = GenTypeBasic(field.value.type, false);
+        if (parser_.opts.scoped_enums && field.value.type.enum_def &&
+            IsScalar(field.value.type.base_type)) {
+          type = GenTypeGet(field.value.type, " ", "const ", " *", true);
+        }
+
+        code_.SetValue("KEY_TYPE", type);
+        code_ += "  int KeyCompareWithValue({{KEY_TYPE}} val) const {";
+        code_ += "    const auto key = {{FIELD_NAME}}();";
+        code_ += "    return static_cast<int>(key > val) - static_cast<int>(key < val);";
+        code_ += "  }";
+      }
     }
+    code_.SetValue("NATIVE_NAME", Name(struct_def));
+    GenOperatorNewDelete(struct_def);
     code_ += "};";
 
     code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize));
diff --git a/src/idl_gen_fbs.cpp b/src/idl_gen_fbs.cpp
index 7752369..2ef70da 100644
--- a/src/idl_gen_fbs.cpp
+++ b/src/idl_gen_fbs.cpp
@@ -23,18 +23,20 @@
 
 namespace flatbuffers {
 
-static std::string GenType(const Type &type) {
+static std::string GenType(const Type &type, bool underlying = false) {
   switch (type.base_type) {
     case BASE_TYPE_STRUCT:
       return type.struct_def->defined_namespace->GetFullyQualifiedName(
                type.struct_def->name);
-    case BASE_TYPE_UNION:
-      return type.enum_def->defined_namespace->GetFullyQualifiedName(
-               type.enum_def->name);
     case BASE_TYPE_VECTOR:
         return "[" + GenType(type.VectorType()) + "]";
     default:
-        return kTypeNames[type.base_type];
+        if (type.enum_def && !underlying) {
+          return type.enum_def->defined_namespace->GetFullyQualifiedName(
+                   type.enum_def->name);
+        } else {
+          return kTypeNames[type.base_type];
+        }
   }
 }
 
@@ -54,14 +56,13 @@
 
 // Generate a flatbuffer schema from the Parser's internal representation.
 std::string GenerateFBS(const Parser &parser, const std::string &file_name) {
- // Proto namespaces may clash with table names, so we have to prefix all:
-  if (!parser.opts.escape_proto_identifiers) {
-    for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
-         ++it) {
-      for (auto comp = (*it)->components.begin(); comp != (*it)->components.end();
-           ++comp) {
-        (*comp) = "_" + (*comp);
-      }
+  // Proto namespaces may clash with table names, escape the ones that were
+  // generated from a table:
+  for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end();
+       ++it) {
+    auto &ns = **it;
+    for (size_t i = 0; i < ns.from_table; i++) {
+      ns.components[ns.components.size() - 1 - i] += "_";
     }
   }
 
@@ -72,12 +73,12 @@
     int num_includes = 0;
     for (auto it = parser.included_files_.begin();
          it != parser.included_files_.end(); ++it) {
+      if (it->second.empty())
+        continue;
       auto basename = flatbuffers::StripPath(
-                        flatbuffers::StripExtension(it->first));
-      if (basename != file_name) {
-        schema += "include \"" + basename + ".fbs\";\n";
-        num_includes++;
-      }
+                        flatbuffers::StripExtension(it->second));
+      schema += "include \"" + basename + ".fbs\";\n";
+      num_includes++;
     }
     if (num_includes) schema += "\n";
     #endif
@@ -90,7 +91,7 @@
     GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace);
     GenComment(enum_def.doc_comment, &schema, nullptr);
     schema += "enum " + enum_def.name + " : ";
-    schema += GenType(enum_def.underlying_type) + " {\n";
+    schema += GenType(enum_def.underlying_type, true) + " {\n";
     for (auto it = enum_def.vals.vec.begin();
          it != enum_def.vals.vec.end(); ++it) {
       auto &ev = **it;
@@ -109,11 +110,13 @@
     for (auto field_it = struct_def.fields.vec.begin();
              field_it != struct_def.fields.vec.end(); ++field_it) {
       auto &field = **field_it;
-      GenComment(field.doc_comment, &schema, nullptr, "  ");
-      schema += "  " + field.name + ":" + GenType(field.value.type);
-      if (field.value.constant != "0") schema += " = " + field.value.constant;
-      if (field.required) schema += " (required)";
-      schema += ";\n";
+      if (field.value.type.base_type != BASE_TYPE_UTYPE) {
+        GenComment(field.doc_comment, &schema, nullptr, "  ");
+        schema += "  " + field.name + ":" + GenType(field.value.type);
+        if (field.value.constant != "0") schema += " = " + field.value.constant;
+        if (field.required) schema += " (required)";
+        schema += ";\n";
+      }
     }
     schema += "}\n\n";
   }
diff --git a/src/idl_gen_general.cpp b/src/idl_gen_general.cpp
index 857bf46..0329300 100644
--- a/src/idl_gen_general.cpp
+++ b/src/idl_gen_general.cpp
@@ -20,7 +20,10 @@
 #include "flatbuffers/idl.h"
 #include "flatbuffers/util.h"
 #include "flatbuffers/code_generators.h"
-#include <algorithm>
+
+#if defined(FLATBUFFERS_CPP98_STL)
+  #include <cctype>
+#endif  // defined(FLATBUFFERS_CPP98_STL)
 
 namespace flatbuffers {
 
@@ -67,6 +70,7 @@
   std::string accessor_prefix_static;
   std::string optional_suffix;
   std::string includes;
+  std::string class_annotation;
   CommentConfig comment_config;
 };
 
@@ -96,8 +100,8 @@
       "",
       "",
       "",
-      "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\n"
-        "import com.google.flatbuffers.*;\n\n@SuppressWarnings(\"unused\")\n",
+      "import java.nio.*;\nimport java.lang.*;\nimport java.util.*;\nimport com.google.flatbuffers.*;\n",
+      "\n@SuppressWarnings(\"unused\")\n",
       {
         "/**",
         " *",
@@ -128,7 +132,8 @@
       "__p.",
       "Table.",
       "?",
-      "using System;\nusing FlatBuffers;\n\n",
+      "using global::System;\nusing global::FlatBuffers;\n\n",
+      "",
       {
         nullptr,
         "///",
@@ -158,7 +163,7 @@
   GeneralGenerator &operator=(const GeneralGenerator &);
   bool generate() {
     std::string one_file_code;
-    cur_name_space_ = parser_.namespaces_.back();
+    cur_name_space_ = parser_.current_namespace_;
 
     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
          ++it) {
@@ -191,7 +196,7 @@
     }
 
     if (parser_.opts.one_file) {
-      return SaveType(file_name_, *parser_.namespaces_.back(),
+      return SaveType(file_name_, *parser_.current_namespace_,
                       one_file_code, true);
     }
     return true;
@@ -204,13 +209,26 @@
     if (!classcode.length()) return true;
 
     std::string code;
-    code = code + "// " + FlatBuffersGeneratedWarning();
+    if (lang_.language == IDLOptions::kCSharp) {
+      code = "// <auto-generated>\n"
+             "//  " + std::string(FlatBuffersGeneratedWarning()) + "\n"
+             "// </auto-generated>\n\n";
+    } else {
+      code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+    }
+
     std::string namespace_name = FullNamespace(".", ns);
     if (!namespace_name.empty()) {
       code += lang_.namespace_ident + namespace_name + lang_.namespace_begin;
       code += "\n\n";
     }
-    if (needs_includes) code += lang_.includes;
+    if (needs_includes) {
+      code += lang_.includes;
+      if (parser_.opts.gen_nullable) {
+        code += "\nimport javax.annotation.Nullable;\n";
+      }
+      code += lang_.class_annotation;
+    }
     code += classcode;
     if (!namespace_name.empty()) code += lang_.namespace_end;
     auto filename = NamespaceDir(ns) + defname + lang_.file_extension;
@@ -225,20 +243,28 @@
                                 : upper);
 }
 
+std::string GenNullableAnnotation(const Type& t) {
+  return lang_.language == IDLOptions::kJava 
+    && parser_.opts.gen_nullable 
+    && !IsScalar(DestinationType(t, true).base_type) ? " @Nullable ": "";
+}
+
 static bool IsEnum(const Type& type) {
   return type.enum_def != nullptr && IsInteger(type.base_type);
 }
 
 std::string GenTypeBasic(const Type &type, bool enableLangOverrides) {
   static const char *java_typename[] = {
-    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
         #JTYPE,
       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
     #undef FLATBUFFERS_TD
   };
 
   static const char *csharp_typename[] = {
-    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
         #NTYPE,
       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
     #undef FLATBUFFERS_TD
@@ -301,7 +327,7 @@
     case BASE_TYPE_VECTOR:
       if (vectorelem)
         return DestinationType(type.VectorType(), vectorelem);
-      // else fall thru:
+      // else fall thru
     default: return type;
   }
 }
@@ -348,7 +374,7 @@
     case BASE_TYPE_VECTOR:
       if (vectorelem)
         return DestinationMask(type.VectorType(), vectorelem);
-      // else fall thru:
+      // else fall thru
     default: return "";
   }
 }
@@ -587,6 +613,22 @@
   }
 }
 
+// Returns the function name that is able to read a value of the given type.
+std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field,
+                                    const std::string &data_buffer,
+                                    const char *num = nullptr) {
+  auto type = key_field->value.type;
+  auto dest_mask = DestinationMask(type, true);
+  auto dest_cast = DestinationCast(type);
+  auto getter = data_buffer + "." + FunctionStart('G') + "et";
+  if (GenTypeBasic(type, false) != "byte") {
+    getter += MakeCamel(GenTypeBasic(type, false));
+  }
+  getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")"
+    + dest_mask;
+  return getter;
+}
+
 // Direct mutation is only allowed for scalar fields.
 // Hence a setter method will only be generated for such fields.
 std::string GenSetter(const Type &type) {
@@ -668,7 +710,7 @@
 std::string GenByteBufferLength(const char *bb_name) {
   std::string bb_len = bb_name;
   if (lang_.language == IDLOptions::kCSharp) bb_len += ".Length";
-  else bb_len += ".array().length";
+  else bb_len += ".capacity()";
   return bb_len;
 }
 
@@ -699,12 +741,11 @@
     key_getter += GenOffsetGetter(key_field);
     key_getter += ", byteKey, bb);\n";
   } else {
-    auto get_val = GenGetter(key_field->value.type) +
-      "(" + GenOffsetGetter(key_field) + ")";
+    auto get_val = GenGetterForLookupByKey(key_field, "bb");
     if (lang_.language == IDLOptions::kCSharp) {
       key_getter += "int comp = " + get_val + ".CompareTo(key);\n";
     } else {
-      key_getter += GenTypeGet(key_field->value.type) + " val = ";
+      key_getter += GenTypeNameDest(key_field->value.type) + " val = ";
       key_getter += get_val + ";\n";
       key_getter += "      int comp = val > key ? 1 : val < key ? -1 : 0;\n";
     }
@@ -728,20 +769,17 @@
       key_getter += ";";
   }
   else {
-    auto field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
-      "(" + GenOffsetGetter(key_field, "o1") + ")";
+    auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1");
     if (lang_.language == IDLOptions::kCSharp) {
       key_getter += field_getter;
-      field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
-        "(" + GenOffsetGetter(key_field, "o2") + ")";
+      field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
       key_getter += ".CompareTo(" + field_getter + ")";
     }
     else {
-      key_getter += "\n    " + GenTypeGet(key_field->value.type) + " val_1 = ";
-      key_getter += field_getter + ";\n    " + GenTypeGet(key_field->value.type);
+      key_getter += "\n    " + GenTypeNameDest(key_field->value.type) + " val_1 = ";
+      key_getter += field_getter + ";\n    " + GenTypeNameDest(key_field->value.type);
       key_getter += " val_2 = ";
-      field_getter = data_buffer + GenGetter(key_field->value.type).substr(2) +
-        "(" + GenOffsetGetter(key_field, "o2") + ")";
+      field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2");
       key_getter += field_getter + ";\n";
       key_getter += "    return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n ";
     }
@@ -845,7 +883,8 @@
     std::string dest_mask = DestinationMask(field.value.type, true);
     std::string dest_cast = DestinationCast(field.value.type);
     std::string src_cast = SourceCast(field.value.type);
-    std::string method_start = "  public " + type_name_dest + optional + " " +
+    std::string method_start = "  public " + GenNullableAnnotation(field.value.type) +
+                               type_name_dest + optional + " " +
                                MakeCamel(field.name, lang_.first_camel_upper);
     std::string obj = lang_.language == IDLOptions::kCSharp
       ? "(new " + type_name + "())"
@@ -993,6 +1032,26 @@
       code += lang_.accessor_prefix + "__vector_len(o) : 0; ";
       code += lang_.getter_suffix;
       code += "}\n";
+      // See if we should generate a by-key accessor.
+      if (field.value.type.element == BASE_TYPE_STRUCT &&
+          !field.value.type.struct_def->fixed) {
+        auto &sd = *field.value.type.struct_def;
+        auto &fields = sd.fields.vec;
+        for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+          auto &key_field = **kit;
+          if (key_field.key) {
+            code += "  public " + sd.name + lang_.optional_suffix + " ";
+            code += MakeCamel(field.name, lang_.first_camel_upper) + "ByKey(";
+            code += GenTypeNameDest(key_field.value.type) + " key)";
+            code += offset_prefix;
+            code += sd.name + ".__lookup_by_key(";
+            code += lang_.accessor_prefix + "__vector(o), key, ";
+            code += lang_.accessor_prefix + "bb) : null; ";
+            code += "}\n";
+            break;
+          }
+        }
+      }
     }
     // Generate a ByteBuffer accessor for strings & vectors of scalars.
     if ((field.value.type.base_type == BASE_TYPE_VECTOR &&
@@ -1023,28 +1082,24 @@
       }
     }
   // generate object accessors if is nested_flatbuffer
-  auto nested = field.attributes.Lookup("nested_flatbuffer");
-  if (nested) {
-    auto nested_qualified_name =
-      parser_.namespaces_.back()->GetFullyQualifiedName(nested->constant);
-    auto nested_type = parser_.structs_.Lookup(nested_qualified_name);
-    auto nested_type_name = WrapInNameSpace(*nested_type);
-    auto nestedMethodName = MakeCamel(field.name, lang_.first_camel_upper)
+  if (field.nested_flatbuffer) {
+    auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+    auto nested_method_name = MakeCamel(field.name, lang_.first_camel_upper)
       + "As" + nested_type_name;
-    auto getNestedMethodName = nestedMethodName;
+    auto get_nested_method_name = nested_method_name;
     if (lang_.language == IDLOptions::kCSharp) {
-      getNestedMethodName = "Get" + nestedMethodName;
+      get_nested_method_name = "Get" + nested_method_name;
       conditional_cast = "(" + nested_type_name + lang_.optional_suffix + ")";
     }
     if (lang_.language != IDLOptions::kCSharp) {
       code += "  public " + nested_type_name + lang_.optional_suffix + " ";
-      code += nestedMethodName + "() { return ";
-      code += getNestedMethodName + "(new " + nested_type_name + "()); }\n";
+      code += nested_method_name + "() { return ";
+      code += get_nested_method_name + "(new " + nested_type_name + "()); }\n";
     } else {
       obj = "(new " + nested_type_name + "())";
     }
     code += "  public " + nested_type_name + lang_.optional_suffix + " ";
-    code += getNestedMethodName + "(";
+    code += get_nested_method_name + "(";
     if (lang_.language != IDLOptions::kCSharp)
       code += nested_type_name + " obj";
     code += ") { int o = " + lang_.accessor_prefix + "__offset(";
@@ -1127,7 +1182,9 @@
         num_fields++;
       }
     }
-    if (has_no_struct_fields && num_fields) {
+    // JVM specifications restrict default constructor params to be < 255.
+    // Longs and doubles take up 2 units, so we set the limit to be < 127.
+    if (has_no_struct_fields && num_fields && num_fields < 127) {
       // Generate a table constructor of the form:
       // public static int createName(FlatBufferBuilder builder, args...)
       code += "  public static " + GenOffsetType(struct_def) + " ";
@@ -1279,7 +1336,9 @@
       code += "); }\n";
     }
   }
-  if (struct_def.has_key) {
+  // Only generate key compare function for table,
+  // because `key_field` is not set for struct
+  if (struct_def.has_key && !struct_def.fixed) {
     if (lang_.language == IDLOptions::kJava) {
       code += "\n  @Override\n  protected int keysCompare(";
       code += "Integer o1, Integer o2, ByteBuffer _bb) {";
@@ -1288,7 +1347,8 @@
     }
     else {
       code += "\n  public static VectorOffset ";
-      code += "CreateMySortedVectorOfTables(FlatBufferBuilder builder, ";
+      code += "CreateSortedVectorOf" + struct_def.name;
+      code += "(FlatBufferBuilder builder, ";
       code += "Offset<" + struct_def.name + ">";
       code += "[] offsets) {\n";
       code += "    Array.Sort(offsets, (Offset<" + struct_def.name +
@@ -1298,8 +1358,8 @@
     }
 
     code += "\n  public static " + struct_def.name + lang_.optional_suffix;
-    code += " " + FunctionStart('L') + "ookupByKey(" + GenVectorOffsetType();
-    code += " vectorOffset, " + GenTypeGet(key_field->value.type);
+    code += " __lookup_by_key(int vectorLocation, ";
+    code += GenTypeNameDest(key_field->value.type);
     code += " key, ByteBuffer bb) {\n";
     if (key_field->value.type.base_type == BASE_TYPE_STRING) {
       code += "    byte[] byteKey = ";
@@ -1308,13 +1368,9 @@
       else
         code += "System.Text.Encoding.UTF8.GetBytes(key);\n";
     }
-    code += "    int vectorLocation = " + GenByteBufferLength("bb");
-    code += " - vectorOffset";
-    if (lang_.language == IDLOptions::kCSharp) code += ".Value";
-    code += ";\n    int span = ";
-    code += "bb." + FunctionStart('G') + "etInt(vectorLocation);\n";
+    code += "    int span = ";
+    code += "bb." + FunctionStart('G') + "etInt(vectorLocation - 4);\n";
     code += "    int start = 0;\n";
-    code += "    vectorLocation += 4;\n";
     code += "    while (span != 0) {\n";
     code += "      int middle = span / 2;\n";
     code += GenLookupKeyGetter(key_field);
diff --git a/src/idl_gen_go.cpp b/src/idl_gen_go.cpp
index dadb350..1f8e09e 100644
--- a/src/idl_gen_go.cpp
+++ b/src/idl_gen_go.cpp
@@ -17,6 +17,7 @@
 // independent from idl_parser, since this code is not needed for most clients
 
 #include <string>
+#include <sstream>
 
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
@@ -33,8 +34,21 @@
 #endif
 
 namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + "_generated.go";
+}
+
 namespace go {
 
+// see https://golang.org/ref/spec#Keywords
+static const char *g_golang_keywords[] = {
+  "break", "default", "func", "interface", "select", "case", "defer", "go",
+  "map", "struct", "chan", "else", "goto", "package", "switch", "const",
+  "fallthrough", "if", "range", "type", "continue", "for", "import", "return", "var",
+};
+
 static std::string GenGetter(const Type &type);
 static std::string GenMethod(const FieldDef &field);
 static void GenStructBuilder(const StructDef &struct_def,
@@ -43,6 +57,15 @@
 static std::string GenTypeBasic(const Type &type);
 static std::string GenTypeGet(const Type &type);
 static std::string TypeName(const FieldDef &field);
+static std::string GoIdentity(const std::string& name) {
+  for (size_t i=0; i<sizeof(g_golang_keywords)/sizeof(g_golang_keywords[0]); i++) {
+    if (name == g_golang_keywords[i]) {
+      return MakeCamel(name + "_", false);
+    }
+  }
+
+  return MakeCamel(name, false);
+}
 
 
 // Most field accessors need to retrieve and test the field offset first,
@@ -368,7 +391,7 @@
     } else {
       std::string &code = *code_ptr;
       code += (std::string)", " + nameprefix;
-      code += MakeCamel(field.name, false);
+      code += GoIdentity(field.name);
       code += " " + GenTypeBasic(field.value.type);
     }
   }
@@ -400,7 +423,7 @@
                         code_ptr);
     } else {
       code += "\tbuilder.Prepend" + GenMethod(field) + "(";
-      code += nameprefix + MakeCamel(field.name, false) + ")\n";
+      code += nameprefix + GoIdentity(field.name) + ")\n";
     }
   }
 }
@@ -430,7 +453,7 @@
   std::string &code = *code_ptr;
   code += "func " + struct_def.name + "Add" + MakeCamel(field.name);
   code += "(builder *flatbuffers.Builder, ";
-  code += MakeCamel(field.name, false) + " ";
+  code += GoIdentity(field.name) + " ";
   if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
     code += "flatbuffers.UOffsetT";
   } else {
@@ -443,9 +466,9 @@
   if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
     code += "flatbuffers.UOffsetT";
     code += "(";
-    code += MakeCamel(field.name, false) + ")";
+    code += GoIdentity(field.name) + ")";
   } else {
-    code += MakeCamel(field.name, false);
+    code += GoIdentity(field.name);
   }
   code += ", " + field.value.constant;
   code += ")\n}\n";
@@ -677,7 +700,8 @@
 
 static std::string GenTypeBasic(const Type &type) {
   static const char *ctypename[] = {
-    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
       #GTYPE,
       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
     #undef FLATBUFFERS_TD
@@ -724,22 +748,45 @@
 class GoGenerator : public BaseGenerator {
  public:
   GoGenerator(const Parser &parser, const std::string &path,
-              const std::string &file_name)
-      : BaseGenerator(parser, path, file_name, "" /* not used*/,
-                      "" /* not used */){};
+              const std::string &file_name, const std::string &go_namespace)
+      : BaseGenerator(parser, path, file_name, "" /* not used*/, "" /* not used */) {
+    std::istringstream iss(go_namespace);
+    std::string component;
+    while (std::getline(iss, component, '.')) {
+      go_namespace_.components.push_back(component);
+    }
+  }
+
   bool generate() {
+    std::string one_file_code;
     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
          ++it) {
       std::string enumcode;
       go::GenEnum(**it, &enumcode);
-      if (!SaveType(**it, enumcode, false)) return false;
+      if (parser_.opts.one_file) {
+        one_file_code += enumcode;
+      } else {
+        if (!SaveType(**it, enumcode, false)) return false;
+      }
     }
 
     for (auto it = parser_.structs_.vec.begin();
          it != parser_.structs_.vec.end(); ++it) {
       std::string declcode;
       go::GenStruct(**it, &declcode);
-      if (!SaveType(**it, declcode, true)) return false;
+      if (parser_.opts.one_file) {
+        one_file_code += declcode;
+      } else {
+        if (!SaveType(**it, declcode, true)) return false;
+      }
+    }
+
+    if (parser_.opts.one_file) {
+      std::string code = "";
+      BeginFile(LastNamespacePart(go_namespace_), true, &code);
+      code += one_file_code;
+      const std::string filename = GeneratedFileName(path_, file_name_);
+      return SaveFile(filename.c_str(), code, false);
     }
 
     return true;
@@ -750,11 +797,15 @@
   void BeginFile(const std::string name_space_name, const bool needs_imports,
                  std::string *code_ptr) {
     std::string &code = *code_ptr;
-    code = code + "// " + FlatBuffersGeneratedWarning();
+    code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
     code += "package " + name_space_name + "\n\n";
     if (needs_imports) {
       code += "import (\n";
-      code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
+      if (!parser_.opts.go_import.empty()) {
+        code += "\tflatbuffers \"" + parser_.opts.go_import +"\"\n";
+      } else{
+        code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n";
+      }
       code += ")\n\n";
     }
   }
@@ -764,19 +815,22 @@
                 bool needs_imports) {
     if (!classcode.length()) return true;
 
+    Namespace& ns = go_namespace_.components.empty() ? *def.defined_namespace : go_namespace_;
     std::string code = "";
-    BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+    BeginFile(LastNamespacePart(ns), needs_imports, &code);
     code += classcode;
     std::string filename =
-        NamespaceDir(*def.defined_namespace) + def.name + ".go";
+        NamespaceDir(ns) + def.name + ".go";
     return SaveFile(filename.c_str(), code, false);
   }
+
+  Namespace go_namespace_;
 };
 }  // namespace go
 
 bool GenerateGo(const Parser &parser, const std::string &path,
                 const std::string &file_name) {
-  go::GoGenerator generator(parser, path, file_name);
+  go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace);
   return generator.generate();
 }
 
diff --git a/src/idl_gen_grpc.cpp b/src/idl_gen_grpc.cpp
index a540b8b..5fca268 100644
--- a/src/idl_gen_grpc.cpp
+++ b/src/idl_gen_grpc.cpp
@@ -24,6 +24,11 @@
 #include "src/compiler/cpp_generator.h"
 #include "src/compiler/go_generator.h"
 
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable: 4512) // C4512: 'class' : assignment operator could not be generated
+#endif
+
 namespace flatbuffers {
 
 class FlatBufMethod : public grpc_generator::Method {
@@ -41,30 +46,52 @@
     }
   }
 
+  grpc::string GetLeadingComments(const grpc::string) const {
+    return "";
+  }
+  grpc::string GetTrailingComments(const grpc::string) const {
+    return "";
+  }
+  std::vector<grpc::string> GetAllComments() const {
+    return std::vector<grpc::string>();
+  }
+
   std::string name() const { return method_->name; }
 
   std::string GRPCType(const StructDef &sd) const {
-    return "flatbuffers::BufferRef<" + sd.name + ">";
+    return "flatbuffers::grpc::Message<" + sd.name + ">";
+  }
+
+  std::string get_input_type_name() const {
+    return (*method_->request).name;
+  }
+  std::string get_output_type_name() const {
+    return (*method_->response).name;
+  }
+
+  bool get_module_and_message_path_input(
+      grpc::string * /*str*/, grpc::string /*generator_file_name*/,
+      bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
+    return true;
+  }
+
+  bool get_module_and_message_path_output(
+      grpc::string * /*str*/, grpc::string /*generator_file_name*/,
+      bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const {
+    return true;
   }
 
   std::string input_type_name() const {
     return GRPCType(*method_->request);
   }
+
   std::string output_type_name() const {
     return GRPCType(*method_->response);
   }
 
-  std::string input_name() const {
-    return (*method_->request).name;
-  }
-
-  std::string output_name() const {
-    return (*method_->response).name;
-  }
-
   bool NoStreaming() const { return streaming_ == kNone; }
-  bool ClientOnlyStreaming() const { return streaming_ == kClient; }
-  bool ServerOnlyStreaming() const { return streaming_ == kServer; }
+  bool ClientStreaming() const { return streaming_ == kClient; }
+  bool ServerStreaming() const { return streaming_ == kServer; }
   bool BidiStreaming() const { return streaming_ == kBiDi; }
 
  private:
@@ -76,6 +103,16 @@
  public:
   FlatBufService(const ServiceDef *service) : service_(service) {}
 
+  grpc::string GetLeadingComments(const grpc::string) const {
+    return "";
+  }
+  grpc::string GetTrailingComments(const grpc::string) const {
+    return "";
+  }
+  std::vector<grpc::string> GetAllComments() const {
+    return std::vector<grpc::string>();
+  }
+
   std::string name() const { return service_->name; }
 
   int method_count() const {
@@ -117,6 +154,9 @@
   }
 
   void Print(const char *s) {
+    if (s == nullptr || std::strlen(s) == 0) {
+      return;
+    }
     // Add this string, but for each part separated by \n, add indentation.
     for (;;) {
       // Current indentation.
@@ -145,10 +185,26 @@
 
 class FlatBufFile : public grpc_generator::File {
  public:
-  FlatBufFile(const Parser &parser, const std::string &file_name)
-    : parser_(parser), file_name_(file_name) {}
+  enum Language {
+    kLanguageGo,
+    kLanguageCpp
+  };
+
+  FlatBufFile(
+      const Parser &parser, const std::string &file_name, Language language)
+    : parser_(parser), file_name_(file_name), language_(language) {}
   FlatBufFile &operator=(const FlatBufFile &);
 
+  grpc::string GetLeadingComments(const grpc::string) const {
+    return "";
+  }
+  grpc::string GetTrailingComments(const grpc::string) const {
+    return "";
+  }
+  std::vector<grpc::string> GetAllComments() const {
+    return std::vector<grpc::string>();
+  }
+
   std::string filename() const { return file_name_; }
   std::string filename_without_ext() const {
     return StripExtension(file_name_);
@@ -158,19 +214,23 @@
   std::string service_header_ext() const { return ".grpc.fb.h"; }
 
   std::string package() const {
-    return parser_.namespaces_.back()->GetFullyQualifiedName("");
+    return parser_.current_namespace_->GetFullyQualifiedName("");
   }
 
   std::vector<std::string> package_parts() const {
-    return parser_.namespaces_.back()->components;
+    return parser_.current_namespace_->components;
   }
 
   std::string additional_headers() const {
-    return "#include \"flatbuffers/grpc.h\"\n";
-  }
-
-  std::string additional_imports() const {
-    return "import \"github.com/google/flatbuffers/go\"";
+    switch (language_) {
+      case kLanguageCpp: {
+        return "#include \"flatbuffers/grpc.h\"\n";
+      }
+      case kLanguageGo: {
+        return "import \"github.com/google/flatbuffers/go\"";
+      }
+    }
+    return "";
   }
 
   int service_count() const {
@@ -190,6 +250,7 @@
  private:
   const Parser &parser_;
   const std::string &file_name_;
+  const Language language_;
 };
 
 class GoGRPCGenerator : public flatbuffers::BaseGenerator {
@@ -200,7 +261,7 @@
       parser_(parser), path_(path), file_name_(file_name) {}
 
   bool generate() {
-    FlatBufFile file(parser_, file_name_);
+    FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo);
     grpc_go_generator::Parameters p;
     p.custom_method_io_type = "flatbuffers.Builder";
     for (int i = 0; i < file.service_count(); i++) {
@@ -233,7 +294,7 @@
 }
 
 bool GenerateCppGRPC(const Parser &parser,
-                  const std::string &/*path*/,
+                  const std::string &path,
                   const std::string &file_name) {
 
   int nservices = 0;
@@ -247,7 +308,7 @@
   // TODO(wvo): make the other parameters in this struct configurable.
   generator_parameters.use_system_headers = true;
 
-  FlatBufFile fbfile(parser, file_name);
+  FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp);
 
   std::string header_code =
       grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) +
@@ -261,11 +322,15 @@
       grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) +
       grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters);
 
-  return flatbuffers::SaveFile((file_name + ".grpc.fb.h").c_str(),
+  return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(),
                                header_code, false) &&
-         flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
+         flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(),
                                source_code, false);
 }
 
 }  // namespace flatbuffers
 
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
diff --git a/src/idl_gen_js.cpp b/src/idl_gen_js.cpp
index e1daf0a..c435986 100644
--- a/src/idl_gen_js.cpp
+++ b/src/idl_gen_js.cpp
@@ -15,6 +15,9 @@
  */
 
 // independent from idl_parser, since this code is not needed for most clients
+#include <unordered_set>
+#include <unordered_map>
+#include <cassert>
 
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
@@ -23,9 +26,43 @@
 
 namespace flatbuffers {
 
+const std::string kGeneratedFileNamePostfix = "_generated";
+
+struct JsLanguageParameters {
+  IDLOptions::Language language;
+  std::string file_extension;
+};
+
+struct ReexportDescription {
+  std::string symbol;
+  std::string source_namespace;
+  std::string target_namespace;
+};
+
+const JsLanguageParameters& GetJsLangParams(IDLOptions::Language lang) {
+  static JsLanguageParameters js_language_parameters[] = {
+    {
+      IDLOptions::kJs,
+      ".js",
+    },
+    {
+      IDLOptions::kTs,
+      ".ts",
+    },
+  };
+
+  if (lang == IDLOptions::kJs) {
+    return js_language_parameters[0];
+  } else {
+    assert(lang == IDLOptions::kTs);
+    return js_language_parameters[1];
+  }
+}
+
 static std::string GeneratedFileName(const std::string &path,
-                                     const std::string &file_name) {
-  return path + file_name + "_generated.js";
+                                     const std::string &file_name,
+                                     const JsLanguageParameters &lang) {
+  return path + file_name + kGeneratedFileNamePostfix + lang.file_extension;
 }
 
 namespace js {
@@ -33,56 +70,127 @@
 // and tables) and output them to a single file.
 class JsGenerator : public BaseGenerator {
  public:
+  typedef std::unordered_set<std::string> imported_fileset;
+  typedef std::unordered_multimap<std::string, ReexportDescription>
+          reexport_map;
+
   JsGenerator(const Parser &parser, const std::string &path,
               const std::string &file_name)
-      : BaseGenerator(parser, path, file_name, "", "."){};
+      : BaseGenerator(parser, path, file_name, "", "."),
+        lang_(GetJsLangParams(parser_.opts.lang))
+  {
+  };
   // Iterate through all definitions we haven't generate code for (enums,
   // structs, and tables) and output them to a single file.
   bool generate() {
-    if (IsEverythingGenerated()) return true;
+    imported_fileset imported_files;
+    reexport_map reexports;
 
-    std::string enum_code, struct_code, exports_code, code;
-    generateEnums(&enum_code, &exports_code);
-    generateStructs(&struct_code, &exports_code);
+    std::string enum_code, struct_code, import_code, exports_code, code;
+    generateEnums(&enum_code, &exports_code, reexports);
+    generateStructs(&struct_code, &exports_code, imported_files);
+    generateImportDependencies(&import_code, imported_files);
+    generateReexports(&import_code, reexports, imported_files);
 
-    code = code + "// " + FlatBuffersGeneratedWarning();
+    code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
 
     // Generate code for all the namespace declarations.
     GenNamespaces(&code, &exports_code);
 
     // Output the main declaration code from above.
+    code += import_code;
+
     code += enum_code;
     code += struct_code;
 
-    if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
+    if (lang_.language == IDLOptions::kJs && !exports_code.empty() &&
+        !parser_.opts.skip_js_exports) {
       code += "// Exports for Node.js and RequireJS\n";
       code += exports_code;
     }
 
-    return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
+    return SaveFile(GeneratedFileName(path_, file_name_, lang_).c_str(), code,
+                    false);
   }
 
  private:
+  JsLanguageParameters lang_;
+
+  // Generate code for imports
+  void generateImportDependencies(std::string *code_ptr,
+                                  const imported_fileset &imported_files) {
+    std::string &code = *code_ptr;
+    for (auto it = imported_files.begin(); it != imported_files.end(); ++it) {
+      const auto &file = *it;
+      const auto basename =
+          flatbuffers::StripPath(flatbuffers::StripExtension(file));
+      if (basename != file_name_) {
+        const auto file_name = basename + kGeneratedFileNamePostfix;
+        code += GenPrefixedImport(file, file_name);
+      }
+    }
+  }
+
+  // Generate reexports, which might not have been explicitly imported using the
+  // "export import" trick
+  void generateReexports(std::string *code_ptr,
+                         const reexport_map &reexports,
+                         imported_fileset imported_files) {
+      if (!parser_.opts.reexport_ts_modules ||
+          lang_.language != IDLOptions::kTs) {
+          return;
+      }
+
+      std::string &code = *code_ptr;
+      for (auto it = reexports.begin(); it != reexports.end(); ++it) {
+        const auto &file = *it;
+        const auto basename =
+            flatbuffers::StripPath(flatbuffers::StripExtension(file.first));
+        if (basename != file_name_) {
+          const auto file_name = basename + kGeneratedFileNamePostfix;
+
+          if (imported_files.find(file.first) == imported_files.end()) {
+            code += GenPrefixedImport(file.first, file_name);
+            imported_files.emplace(file.first);
+          }
+
+          code += "export namespace " + file.second.target_namespace + " { \n";
+          code += "export import " + file.second.symbol + " = ";
+          code += GenFileNamespacePrefix(file.first) + "." +
+                  file.second.source_namespace + "." + file.second.symbol +
+                  "; }\n";
+        }
+      }
+  }
+
   // Generate code for all enums.
   void generateEnums(std::string *enum_code_ptr,
-                     std::string *exports_code_ptr) {
+                     std::string *exports_code_ptr,
+                     reexport_map &reexports) {
     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
          ++it) {
       auto &enum_def = **it;
-      GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
+      GenEnum(enum_def, enum_code_ptr, exports_code_ptr, reexports);
     }
   }
 
   // Generate code for all structs.
   void generateStructs(std::string *decl_code_ptr,
-                       std::string *exports_code_ptr) {
+                       std::string *exports_code_ptr,
+                       imported_fileset &imported_files) {
     for (auto it = parser_.structs_.vec.begin();
          it != parser_.structs_.vec.end(); ++it) {
       auto &struct_def = **it;
-      GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr);
+      GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr,
+                imported_files);
     }
   }
   void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
+  if (lang_.language == IDLOptions::kTs &&
+      parser_.opts.skip_flatbuffers_import) {
+    return;
+  }
+
   std::set<std::string> namespaces;
 
   for (auto it = parser_.namespaces_.begin();
@@ -110,16 +218,23 @@
   std::string &exports = *exports_ptr;
   for (auto it = sorted_namespaces.begin();
        it != sorted_namespaces.end(); it++) {
-    code += "/**\n * @const\n * @namespace\n */\n";
-    if (it->find('.') == std::string::npos) {
-      code += "var ";
-      if(parser_.opts.use_goog_js_export_format) {
-        exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
-      } else {
-        exports += "this." + *it + " = " + *it + ";\n";
+    if (lang_.language == IDLOptions::kTs) {
+      if (it->find('.') == std::string::npos) {
+        code += "import { flatbuffers } from \"./flatbuffers\"\n";
+        break;
       }
+    } else {
+      code += "/**\n * @const\n * @namespace\n */\n";
+      if (it->find('.') == std::string::npos) {
+        code += "var ";
+        if(parser_.opts.use_goog_js_export_format) {
+          exports += "goog.exportSymbol('" + *it + "', " + *it + ");\n";
+        } else {
+          exports += "this." + *it + " = " + *it + ";\n";
+        }
+      }
+      code += *it + " = " + *it + " || {};\n\n";
     }
-    code += *it + " = " + *it + " || {};\n\n";
   }
 }
 
@@ -169,21 +284,29 @@
 
 // Generate an enum declaration and an enum string lookup table.
 void GenEnum(EnumDef &enum_def, std::string *code_ptr,
-                    std::string *exports_ptr) {
+             std::string *exports_ptr, reexport_map &reexports) {
   if (enum_def.generated) return;
   std::string &code = *code_ptr;
   std::string &exports = *exports_ptr;
   GenDocComment(enum_def.doc_comment, code_ptr, "@enum");
-  if (enum_def.defined_namespace->components.empty()) {
-    code += "var ";
-    if(parser_.opts.use_goog_js_export_format) {
-      exports += "goog.exportSymbol('" + enum_def.name + "', " + enum_def.name +
-        ");\n";
-    } else {
-      exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
+  std::string ns = GetNameSpace(enum_def);
+  if (lang_.language == IDLOptions::kTs) {
+    if (!ns.empty()) {
+      code += "export namespace " + ns + "{\n";
     }
+    code += "export enum " + enum_def.name + "{\n";
+  } else {
+    if (enum_def.defined_namespace->components.empty()) {
+      code += "var ";
+      if(parser_.opts.use_goog_js_export_format) {
+        exports += "goog.exportSymbol('" + enum_def.name + "', " +
+                   enum_def.name + ");\n";
+      } else {
+        exports += "this." + enum_def.name + " = " + enum_def.name + ";\n";
+      }
+    }
+    code += WrapInNameSpace(enum_def) + " = {\n";
   }
-  code += WrapInNameSpace(enum_def) + " = {\n";
   for (auto it = enum_def.vals.vec.begin();
        it != enum_def.vals.vec.end(); ++it) {
     auto &ev = **it;
@@ -193,8 +316,24 @@
       }
       GenDocComment(ev.doc_comment, code_ptr, "", "  ");
     }
-    code += "  " + ev.name + ": " + NumToString(ev.value);
+    code += "  " + ev.name;
+    code += lang_.language == IDLOptions::kTs ? "= " : ": ";
+    code += NumToString(ev.value);
     code += (it + 1) != enum_def.vals.vec.end() ? ",\n" : "\n";
+
+    if (ev.union_type.struct_def) {
+        ReexportDescription desc = {
+          ev.name,
+          GetNameSpace(*ev.union_type.struct_def),
+          GetNameSpace(enum_def)
+        };
+        reexports.insert(std::make_pair(ev.union_type.struct_def->file,
+                                        std::move(desc)));
+    }
+  }
+
+  if (lang_.language == IDLOptions::kTs && !ns.empty()) {
+    code += "}";
   }
   code += "};\n\n";
 }
@@ -244,7 +383,12 @@
   if (value.type.enum_def) {
     if (auto val = value.type.enum_def->ReverseLookup(
         atoi(value.constant.c_str()), false)) {
-      return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+      if (lang_.language == IDLOptions::kTs) {
+        return GenPrefixedTypeName(WrapInNameSpace(*value.type.enum_def),
+                                   value.type.enum_def->file) + "." + val->name;
+      } else {
+        return WrapInNameSpace(*value.type.enum_def) + "." + val->name;
+      }
     } else {
       return "/** @type {" + WrapInNameSpace(*value.type.enum_def) + "} */ ("
         + value.constant + ")";
@@ -270,13 +414,16 @@
   }
 }
 
-std::string GenTypeName(const Type &type, bool input) {
+std::string GenTypeName(const Type &type, bool input, bool allowNull = false) {
   if (!input) {
-    if (type.base_type == BASE_TYPE_STRING) {
-      return "string|Uint8Array";
-    }
-    if (type.base_type == BASE_TYPE_STRUCT) {
-      return WrapInNameSpace(*type.struct_def);
+    if (type.base_type == BASE_TYPE_STRING || type.base_type == BASE_TYPE_STRUCT) {
+      std::string name;
+      if (type.base_type == BASE_TYPE_STRING) {
+        name = "string|Uint8Array";
+      } else {
+        name = WrapInNameSpace(*type.struct_def);
+      }
+      return (allowNull) ? (name + "|null") : (name);
     }
   }
 
@@ -322,6 +469,28 @@
   return value != 1 ? " * " + NumToString(value) : "";
 }
 
+static std::string GenFileNamespacePrefix(const std::string &file) {
+  return "NS" + std::to_string(
+        static_cast<unsigned long long>(std::hash<std::string>()(file)));
+}
+
+static std::string GenPrefixedImport(const std::string &full_file_name,
+                                     const std::string &base_file_name) {
+  return "import * as "+ GenFileNamespacePrefix(full_file_name) +
+         " from \"./" + base_file_name + "\";\n";
+}
+
+// Adds a source-dependent prefix, for of import * statements.
+std::string GenPrefixedTypeName(const std::string &typeName,
+                                const std::string &file) {
+  const auto basename =
+      flatbuffers::StripPath(flatbuffers::StripExtension(file));
+  if (basename == file_name_) {
+    return typeName;
+  }
+  return GenFileNamespacePrefix(file) + "." + typeName;
+}
+
 void GenStructArgs(const StructDef &struct_def,
                           std::string *annotations,
                           std::string *arguments,
@@ -338,7 +507,13 @@
     } else {
       *annotations += "@param {" + GenTypeName(field.value.type, true);
       *annotations += "} " + nameprefix + field.name + "\n";
-      *arguments += ", " + nameprefix + field.name;
+
+      if (lang_.language == IDLOptions::kTs) {
+          *arguments += ", " + nameprefix + field.name + ": " +
+                        GenTypeName(field.value.type, true);
+      } else {
+          *arguments += ", " + nameprefix + field.name;
+      }
     }
   }
 }
@@ -373,37 +548,61 @@
 }
 
 // Generate an accessor struct with constructor for a flatbuffers struct.
-void GenStruct(const Parser &parser, StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
+void GenStruct(const Parser &parser, StructDef &struct_def,
+               std::string *code_ptr, std::string *exports_ptr,
+               imported_fileset &imported_files) {
   if (struct_def.generated) return;
   std::string &code = *code_ptr;
   std::string &exports = *exports_ptr;
 
+  std::string object_name;
+  std::string object_namespace = GetNameSpace(struct_def);
+
   // Emit constructor
-  bool isStatement = struct_def.defined_namespace->components.empty();
-  std::string object_name = WrapInNameSpace(struct_def);
-  GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
-  if (isStatement) {
-    if(parser_.opts.use_goog_js_export_format) {
-      exports += "goog.exportSymbol('" + struct_def.name + "', " +
-        struct_def.name + ");\n";
-    } else {
-      exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
+  if (lang_.language == IDLOptions::kTs) {
+    object_name = struct_def.name;
+    GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+    if (!object_namespace.empty()) {
+      code += "export namespace " + object_namespace + "{\n";
     }
-    code += "function " + object_name;
+    code += "export class " + struct_def.name;
+    code += " {\n";
+    code += "  /**\n";
+    code += "   * @type {flatbuffers.ByteBuffer}\n";
+    code += "   */\n";
+    code += "  bb: flatbuffers.ByteBuffer;\n";
+    code += "\n";
+    code += "  /**\n";
+    code += "   * @type {number}\n";
+    code += "   */\n";
+    code += "  bb_pos:number = 0;\n";
   } else {
-    code += object_name + " = function";
+    bool isStatement = struct_def.defined_namespace->components.empty();
+    object_name = WrapInNameSpace(struct_def);
+    GenDocComment(struct_def.doc_comment, code_ptr, "@constructor");
+    if (isStatement) {
+      if(parser_.opts.use_goog_js_export_format) {
+        exports += "goog.exportSymbol('" + struct_def.name + "', " +
+          struct_def.name + ");\n";
+      } else {
+        exports += "this." + struct_def.name + " = " + struct_def.name + ";\n";
+      }
+      code += "function " + object_name;
+    } else {
+      code += object_name + " = function";
+    }
+    code += "() {\n";
+    code += "  /**\n";
+    code += "   * @type {flatbuffers.ByteBuffer}\n";
+    code += "   */\n";
+    code += "  this.bb = null;\n";
+    code += "\n";
+    code += "  /**\n";
+    code += "   * @type {number}\n";
+    code += "   */\n";
+    code += "  this.bb_pos = 0;\n";
+    code += isStatement ? "}\n\n" : "};\n\n";
   }
-  code += "() {\n";
-  code += "  /**\n";
-  code += "   * @type {flatbuffers.ByteBuffer}\n";
-  code += "   */\n";
-  code += "  this.bb = null;\n";
-  code += "\n";
-  code += "  /**\n";
-  code += "   * @type {number}\n";
-  code += "   */\n";
-  code += "  this.bb_pos = 0;\n";
-  code += isStatement ? "}\n\n" : "};\n\n";
 
   // Generate the __init method that sets the field in a pre-existing
   // accessor object. This is to allow object reuse.
@@ -412,7 +611,14 @@
   code += " * @param {flatbuffers.ByteBuffer} bb\n";
   code += " * @returns {" + object_name + "}\n";
   code += " */\n";
-  code += object_name + ".prototype.__init = function(i, bb) {\n";
+
+  if (lang_.language == IDLOptions::kTs) {
+    code += "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name +
+            " {\n";
+  } else {
+    code += object_name + ".prototype.__init = function(i, bb) {\n";
+  }
+
   code += "  this.bb_pos = i;\n";
   code += "  this.bb = bb;\n";
   code += "  return this;\n";
@@ -425,8 +631,14 @@
       "@param {flatbuffers.ByteBuffer} bb\n"
       "@param {" + object_name + "=} obj\n"
       "@returns {" + object_name + "}");
-    code += object_name + ".getRootAs" + struct_def.name;
-    code += " = function(bb, obj) {\n";
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static getRootAs" + struct_def.name;
+      code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + "):" +
+              object_name + " {\n";
+    } else {
+      code += object_name + ".getRootAs" + struct_def.name;
+      code += " = function(bb, obj) {\n";
+    }
     code += "  return (obj || new " + object_name;
     code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n";
     code += "};\n\n";
@@ -437,7 +649,13 @@
       GenDocComment(code_ptr,
         "@param {flatbuffers.ByteBuffer} bb\n"
         "@returns {boolean}");
-      code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+      if (lang_.language == IDLOptions::kTs) {
+        code +=
+            "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {\n";
+      } else {
+        code += object_name + ".bufferHasIdentifier = function(bb) {\n";
+      }
+
       code += "  return bb.__has_identifier('" + parser_.file_identifier_;
       code += "');\n};\n\n";
     }
@@ -457,13 +675,33 @@
       GenDocComment(field.doc_comment, code_ptr,
         std::string(field.value.type.base_type == BASE_TYPE_STRING ?
           "@param {flatbuffers.Encoding=} optionalEncoding\n" : "") +
-        "@returns {" + GenTypeName(field.value.type, false) + "}");
-      code += object_name + ".prototype." + MakeCamel(field.name, false);
-      code += " = function(";
-      if (field.value.type.base_type == BASE_TYPE_STRING) {
-        code += "optionalEncoding";
+        "@returns {" + GenTypeName(field.value.type, false, true) + "}");
+      if (lang_.language == IDLOptions::kTs) {
+        std::string prefix = MakeCamel(field.name, false) + "(";
+        if (field.value.type.base_type == BASE_TYPE_STRING) {
+          code += prefix + "):string|null\n";
+          code += prefix + "optionalEncoding:flatbuffers.Encoding"+"):" +
+                  GenTypeName(field.value.type, false, true)+"\n";
+          code += prefix + "optionalEncoding?:any";
+        } else {
+          code += prefix;
+        }
+        if (field.value.type.enum_def) {
+          code += "):" +
+                  GenPrefixedTypeName(GenTypeName(field.value.type, false, true),
+                                      field.value.type.enum_def->file) + " {\n";
+        } else {
+          code += "):" + GenTypeName(field.value.type, false, true) + " {\n";
+        }
+      } else {
+        code += object_name + ".prototype." + MakeCamel(field.name, false);
+        code += " = function(";
+        if (field.value.type.base_type == BASE_TYPE_STRING) {
+          code += "optionalEncoding";
+        }
+        code += ") {\n";
       }
-      code += ") {\n";
+
       if (struct_def.fixed) {
         code += "  return " + GenGetter(field.value.type, "(this.bb_pos" +
           MaybeAdd(field.value.offset) + ")") + ";\n";
@@ -484,9 +722,16 @@
         case BASE_TYPE_STRUCT: {
           auto type = WrapInNameSpace(*field.value.type.struct_def);
           GenDocComment(field.doc_comment, code_ptr,
-            "@param {" + type + "=} obj\n@returns {" + type + "}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(obj) {\n";
+            "@param {" + type + "=} obj\n@returns {" + type + "|null}");
+          if (lang_.language == IDLOptions::kTs) {
+            type = GenPrefixedTypeName(type, field.value.type.struct_def->file);
+            code += MakeCamel(field.name, false);
+            code += "(obj?:" + type + "):" + type + "|null {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(obj) {\n";
+          }
+
           if (struct_def.fixed) {
             code += "  return (obj || new " + type;
             code += ").__init(this.bb_pos";
@@ -498,6 +743,11 @@
               : "this.bb.__indirect(this.bb_pos + offset)";
             code += ", this.bb) : null;\n";
           }
+
+          if (lang_.language == IDLOptions::kTs) {
+            imported_files.insert(field.value.type.struct_def->file);
+          }
+
           break;
         }
 
@@ -508,21 +758,61 @@
           auto index = "this.bb.__vector(this.bb_pos + offset) + index" +
                        MaybeScale(inline_size);
           std::string args = "@param {number} index\n";
-          if (vectortype.base_type == BASE_TYPE_STRUCT) {
-            args += "@param {" + vectortypename + "=} obj\n";
-          } else if (vectortype.base_type == BASE_TYPE_STRING) {
-            args += "@param {flatbuffers.Encoding=} optionalEncoding\n";
+          std::string ret_type;
+          bool is_union = false;
+          switch (vectortype.base_type) {
+            case BASE_TYPE_STRUCT:
+              args += "@param {" + vectortypename + "=} obj\n";
+              ret_type = vectortypename;
+              break;
+            case BASE_TYPE_STRING:
+              args += "@param {flatbuffers.Encoding=} optionalEncoding\n";
+              ret_type = vectortypename;
+              break;
+            case BASE_TYPE_UNION:
+              args += "@param {flatbuffers.Table=} obj\n";
+              ret_type = "?flatbuffers.Table";
+              is_union = true;
+              break;
+            default:
+              ret_type = vectortypename;
           }
           GenDocComment(field.doc_comment, code_ptr, args +
-            "@returns {" + vectortypename + "}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(index";
-          if (vectortype.base_type == BASE_TYPE_STRUCT) {
-            code += ", obj";
-          } else if (vectortype.base_type == BASE_TYPE_STRING) {
-            code += ", optionalEncoding";
+            "@returns {" + ret_type + "}");
+          if (lang_.language == IDLOptions::kTs) {
+            std::string prefix = MakeCamel(field.name, false);
+            if (is_union) {
+              prefix += "<T extends flatbuffers.Table>";
+            }
+            prefix += "(index: number";
+            if (is_union) {
+              vectortypename = "T";
+              code += prefix + ", obj:T";
+            } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
+              vectortypename = GenPrefixedTypeName(vectortypename,
+                                                   vectortype.struct_def->file);
+              code += prefix + ", obj?:" + vectortypename;
+              imported_files.insert(vectortype.struct_def->file);
+            } else if (vectortype.base_type == BASE_TYPE_STRING) {
+              code += prefix + "):string\n";
+              code += prefix + ",optionalEncoding:flatbuffers.Encoding" + "):" +
+                      vectortypename + "\n";
+              code += prefix + ",optionalEncoding?:any";
+            } else {
+              code += prefix;
+            }
+            code += "):" + vectortypename + "|null {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(index";
+            if (vectortype.base_type == BASE_TYPE_STRUCT || is_union) {
+              code += ", obj";
+            } else if (vectortype.base_type == BASE_TYPE_STRING) {
+              code += ", optionalEncoding";
+            }
+            code += ") {\n";
           }
-          code += ") {\n";
+
           if (vectortype.base_type == BASE_TYPE_STRUCT) {
             code += offset_prefix + "(obj || new " + vectortypename;
             code += ").__init(";
@@ -531,7 +821,9 @@
               : "this.bb.__indirect(" + index + ")";
             code += ", this.bb)";
           } else {
-            if (vectortype.base_type == BASE_TYPE_STRING) {
+            if (is_union) {
+              index = "obj, " + index;
+            } else if (vectortype.base_type == BASE_TYPE_STRING) {
               index += ", optionalEncoding";
             }
             code += offset_prefix + GenGetter(vectortype, "(" + index + ")");
@@ -561,8 +853,14 @@
           GenDocComment(field.doc_comment, code_ptr,
             "@param {flatbuffers.Table} obj\n"
             "@returns {?flatbuffers.Table}");
-          code += object_name + ".prototype." + MakeCamel(field.name, false);
-          code += " = function(obj) {\n";
+          if (lang_.language == IDLOptions::kTs) {
+            code += MakeCamel(field.name, false);
+            code += "<T extends flatbuffers.Table>(obj:T):T|null {\n";
+          } else {
+            code += object_name + ".prototype." + MakeCamel(field.name, false);
+            code += " = function(obj) {\n";
+          }
+
           code += offset_prefix + GenGetter(field.value.type,
             "(obj, this.bb_pos + offset)") + " : null;\n";
           break;
@@ -581,16 +879,41 @@
 
     // Adds the mutable scalar value to the output
     if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer) {
-      std::string annotations = "@param {" + GenTypeName(field.value.type, true) + "} value\n";
+      std::string annotations =
+          "@param {" + GenTypeName(field.value.type, true) + "} value\n";
       GenDocComment(code_ptr, annotations +
         "@returns {boolean}");
 
-      code += object_name + ".prototype.mutate_" + field.name + " = function(value) {\n";
-      code += "  var offset = this.bb.__offset(this.bb_pos, " + NumToString(field.value.offset) + ");\n\n";
+      if (lang_.language == IDLOptions::kTs) {
+        std::string type;
+        if (field.value.type.enum_def) {
+          type = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+                                     field.value.type.enum_def->file);
+        } else {
+          type = GenTypeName(field.value.type, true);
+        }
+
+        code += "mutate_" + field.name + "(value:" + type + "):boolean {\n";
+      } else {
+        code += object_name + ".prototype.mutate_" + field.name +
+                " = function(value) {\n";
+      }
+
+      code += "  var offset = this.bb.__offset(this.bb_pos, " +
+              NumToString(field.value.offset) + ");\n\n";
       code += "  if (offset === 0) {\n";
       code += "    return false;\n";
       code += "  }\n\n";
-      code += "  this.bb.write" + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + offset, value);\n";
+
+      // special case for bools, which are treated as uint8
+      code += "  this.bb.write" + MakeCamel(GenType(field.value.type)) +
+              "(this.bb_pos + offset, ";
+      if (field.value.type.base_type == BASE_TYPE_BOOL &&
+          lang_.language == IDLOptions::kTs) {
+          code += "+";
+      }
+
+      code += "value);\n";
       code += "  return true;\n";
       code += "};\n\n";
 
@@ -605,8 +928,14 @@
     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
       // Emit a length helper
       GenDocComment(code_ptr, "@returns {number}");
-      code += object_name + ".prototype." + MakeCamel(field.name, false);
-      code += "Length = function() {\n" + offset_prefix;
+      if (lang_.language == IDLOptions::kTs) {
+        code += MakeCamel(field.name, false);
+        code += "Length():number {\n" + offset_prefix;
+      } else {
+        code += object_name + ".prototype." + MakeCamel(field.name, false);
+        code += "Length = function() {\n" + offset_prefix;
+      }
+
       code += "this.bb.__vector_len(this.bb_pos + offset) : 0;\n};\n\n";
 
       if(parser_.opts.use_goog_js_export_format) {
@@ -619,8 +948,16 @@
       auto vectorType = field.value.type.VectorType();
       if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) {
         GenDocComment(code_ptr, "@returns {" + GenType(vectorType) + "Array}");
-        code += object_name + ".prototype." + MakeCamel(field.name, false);
-        code += "Array = function() {\n" + offset_prefix;
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += MakeCamel(field.name, false);
+          code += "Array():" + GenType(vectorType) + "Array|null {\n" +
+                  offset_prefix;
+        } else {
+          code += object_name + ".prototype." + MakeCamel(field.name, false);
+          code += "Array = function() {\n" + offset_prefix;
+        }
+
         code += "new " + GenType(vectorType) + "Array(this.bb.bytes().buffer, "
           "this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), "
           "this.bb.__vector_len(this.bb_pos + offset)) : null;\n};\n\n";
@@ -641,16 +978,30 @@
     GenStructArgs(struct_def, &annotations, &arguments, "");
     GenDocComment(code_ptr, annotations +
       "@returns {flatbuffers.Offset}");
-    code += object_name + ".create" + struct_def.name + " = function(builder";
-    code += arguments + ") {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static create" + struct_def.name + "(builder:flatbuffers.Builder";
+      code += arguments + "):flatbuffers.Offset {\n";
+    } else {
+      code += object_name + ".create" + struct_def.name + " = function(builder";
+      code += arguments + ") {\n";
+    }
+
     GenStructBody(struct_def, &code, "");
     code += "  return builder.offset();\n};\n\n";
   } else {
     // Generate a method to start building a new object
     GenDocComment(code_ptr,
       "@param {flatbuffers.Builder} builder");
-    code += object_name + ".start" + struct_def.name;
-    code += " = function(builder) {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static start" + struct_def.name;
+      code += "(builder:flatbuffers.Builder) {\n";
+    } else {
+      code += object_name + ".start" + struct_def.name;
+      code += " = function(builder) {\n";
+    }
+
     code += "  builder.startObject(" + NumToString(
       struct_def.fields.vec.size()) + ");\n";
     code += "};\n\n";
@@ -670,8 +1021,24 @@
         "@param {flatbuffers.Builder} builder\n"
         "@param {" + GenTypeName(field.value.type, true) + "} " +
         argname);
-      code += object_name + ".add" + MakeCamel(field.name);
-      code += " = function(builder, " + argname + ") {\n";
+
+      if (lang_.language == IDLOptions::kTs) {
+        std::string argType;
+        if (field.value.type.enum_def) {
+          argType = GenPrefixedTypeName(GenTypeName(field.value.type, true),
+                                        field.value.type.enum_def->file);
+        } else {
+          argType = GenTypeName(field.value.type, true);
+        }
+
+        code += "static add" + MakeCamel(field.name);
+        code += "(builder:flatbuffers.Builder, " + argname + ":" + argType +
+                ") {\n";
+      } else {
+        code += object_name + ".add" + MakeCamel(field.name);
+        code += " = function(builder, " + argname + ") {\n";
+      }
+
       code += "  builder.addField" + GenWriteMethod(field.value.type) + "(";
       code += NumToString(it - struct_def.fields.vec.begin()) + ", ";
       if (field.value.type.base_type == BASE_TYPE_BOOL) {
@@ -700,8 +1067,20 @@
             "@param {Array.<" + GenTypeName(vector_type, true) +
             ">} data\n"
             "@returns {flatbuffers.Offset}");
-          code += object_name + ".create" + MakeCamel(field.name);
-          code += "Vector = function(builder, data) {\n";
+
+          if (lang_.language == IDLOptions::kTs) {
+            code += "static create" + MakeCamel(field.name);
+            std::string type = GenTypeName(vector_type, true) + "[]";
+            if (type == "number[]") {
+              type += " | Uint8Array";
+            }
+            code += "Vector(builder:flatbuffers.Builder, data:" + type +
+                    "):flatbuffers.Offset {\n";
+          } else {
+            code += object_name + ".create" + MakeCamel(field.name);
+            code += "Vector = function(builder, data) {\n";
+          }
+
           code += "  builder.startVector(" + NumToString(elem_size);
           code += ", data.length, " + NumToString(alignment) + ");\n";
           code += "  for (var i = data.length - 1; i >= 0; i--) {\n";
@@ -719,8 +1098,15 @@
         GenDocComment(code_ptr,
           "@param {flatbuffers.Builder} builder\n"
           "@param {number} numElems");
-        code += object_name + ".start" + MakeCamel(field.name);
-        code += "Vector = function(builder, numElems) {\n";
+
+        if (lang_.language == IDLOptions::kTs) {
+          code += "static start" + MakeCamel(field.name);
+          code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n";
+        } else {
+          code += object_name + ".start" + MakeCamel(field.name);
+          code += "Vector = function(builder, numElems) {\n";
+        }
+
         code += "  builder.startVector(" + NumToString(elem_size);
         code += ", numElems, " + NumToString(alignment) + ");\n";
         code += "};\n\n";
@@ -731,8 +1117,15 @@
     GenDocComment(code_ptr,
       "@param {flatbuffers.Builder} builder\n"
       "@returns {flatbuffers.Offset}");
-    code += object_name + ".end" + struct_def.name;
-    code += " = function(builder) {\n";
+
+    if (lang_.language == IDLOptions::kTs) {
+      code += "static end" + struct_def.name;
+      code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n";
+    } else {
+      code += object_name + ".end" + struct_def.name;
+      code += " = function(builder) {\n";
+    }
+
     code += "  var offset = builder.endObject();\n";
     for (auto it = struct_def.fields.vec.begin();
          it != struct_def.fields.vec.end(); ++it) {
@@ -751,8 +1144,15 @@
       GenDocComment(code_ptr,
         "@param {flatbuffers.Builder} builder\n"
         "@param {flatbuffers.Offset} offset");
-      code += object_name + ".finish" + struct_def.name + "Buffer";
-      code += " = function(builder, offset) {\n";
+
+      if (lang_.language == IDLOptions::kTs) {
+        code += "static finish" + struct_def.name + "Buffer";
+        code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n";
+      } else {
+        code += object_name + ".finish" + struct_def.name + "Buffer";
+        code += " = function(builder, offset) {\n";
+      }
+
       code += "  builder.finish(offset";
       if (!parser_.file_identifier_.empty()) {
         code += ", '" + parser_.file_identifier_ + "'";
@@ -761,6 +1161,13 @@
       code += "};\n\n";
     }
   }
+
+  if (lang_.language == IDLOptions::kTs) {
+    if (!object_namespace.empty()) {
+      code += "}\n";
+    }
+    code += "}\n";
+  }
 }
 };
 }  // namespace js
@@ -774,15 +1181,19 @@
 std::string JSMakeRule(const Parser &parser,
                        const std::string &path,
                        const std::string &file_name) {
+  assert(parser.opts.lang <= IDLOptions::kMAX);
+  const auto &lang = GetJsLangParams(parser.opts.lang);
+
   std::string filebase = flatbuffers::StripPath(
       flatbuffers::StripExtension(file_name));
-  std::string make_rule = GeneratedFileName(path, filebase) + ": ";
+  std::string make_rule = GeneratedFileName(path, filebase, lang) + ": ";
+
   auto included_files = parser.GetIncludedFilesRecursive(file_name);
   for (auto it = included_files.begin();
        it != included_files.end(); ++it) {
     make_rule += " " + *it;
   }
-  return make_rule;
+return make_rule;
 }
 
 }  // namespace flatbuffers
diff --git a/src/idl_gen_json_schema.cpp b/src/idl_gen_json_schema.cpp
new file mode 100644
index 0000000..2b67398
--- /dev/null
+++ b/src/idl_gen_json_schema.cpp
@@ -0,0 +1,223 @@
+/*
+* Copyright 2014 Google Inc. All rights reserved.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*     http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+#include <iostream>
+
+namespace flatbuffers {
+
+static std::string GeneratedFileName(const std::string &path,
+                                     const std::string &file_name) {
+  return path + file_name + ".schema.json";
+}
+
+namespace jsons {
+
+std::string GenNativeType(BaseType type) {
+  switch (type) {
+    case BASE_TYPE_BOOL:
+      return "boolean";
+    case BASE_TYPE_CHAR:
+    case BASE_TYPE_UCHAR:
+    case BASE_TYPE_SHORT:
+    case BASE_TYPE_USHORT:
+    case BASE_TYPE_INT:
+    case BASE_TYPE_UINT:
+    case BASE_TYPE_LONG:
+    case BASE_TYPE_ULONG:
+    case BASE_TYPE_FLOAT:
+    case BASE_TYPE_DOUBLE:
+      return "number";
+    case BASE_TYPE_STRING:
+      return "string";
+    default:
+      return "";
+  }
+}
+
+template <class T> std::string GenFullName(const T *enum_def) {
+  std::string full_name;
+  const auto &name_spaces = enum_def->defined_namespace->components;
+  for (auto ns = name_spaces.cbegin(); ns != name_spaces.cend(); ++ns) {
+    full_name.append(*ns + "_");
+  }
+  full_name.append(enum_def->name);
+  return full_name;
+}
+
+template <class T> std::string GenTypeRef(const T *enum_def) {
+  return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\"";
+}
+
+std::string GenType(const std::string &name) {
+  return "\"type\" : \"" + name + "\"";
+}
+
+std::string GenType(const Type &type) {
+  if (type.enum_def != nullptr && !type.enum_def->is_union) {
+    // it is a reference to an enum type
+    return GenTypeRef(type.enum_def);
+  }
+  switch (type.base_type) {
+    case BASE_TYPE_VECTOR: {
+      std::string typeline;
+      typeline.append("\"type\" : \"array\", \"items\" : { ");
+      if (type.element == BASE_TYPE_STRUCT) {
+        typeline.append(GenTypeRef(type.struct_def));
+      } else {
+        typeline.append(GenType(GenNativeType(type.element)));
+      }
+      typeline.append(" }");
+      return typeline;
+    }
+    case BASE_TYPE_STRUCT: {
+      return GenTypeRef(type.struct_def);
+    }
+    case BASE_TYPE_UNION: {
+      std::string union_type_string("\"anyOf\": [");
+      const auto &union_types = type.enum_def->vals.vec;
+      for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) {
+        auto &union_type = *ut;
+        if (union_type->union_type.base_type == BASE_TYPE_NONE) {
+          continue;
+        }
+        if (union_type->union_type.base_type == BASE_TYPE_STRUCT) {
+          union_type_string.append("{ " + GenTypeRef(union_type->union_type.struct_def) + " }");
+        }
+        if (union_type != *type.enum_def->vals.vec.rbegin()) {
+          union_type_string.append(",");
+        }
+      }
+      union_type_string.append("]");
+      return union_type_string;
+    }
+    case BASE_TYPE_UTYPE:
+      return GenTypeRef(type.enum_def);
+    default:
+      return GenType(GenNativeType(type.base_type));
+  }
+}
+
+class JsonSchemaGenerator : public BaseGenerator {
+ private:
+  CodeWriter code_;
+
+ public:
+  JsonSchemaGenerator(const Parser &parser, const std::string &path,
+                      const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "") {}
+
+  explicit JsonSchemaGenerator(const BaseGenerator &base_generator)
+      : BaseGenerator(base_generator) {}
+
+  bool generate() {
+    code_.Clear();
+    code_ += "{";
+    code_ += "  \"$schema\": \"http://json-schema.org/draft-04/schema#\",";
+    code_ += "  \"definitions\": {";
+    for (auto e = parser_.enums_.vec.cbegin();
+         e != parser_.enums_.vec.cend();
+         ++e) {
+      code_ += "    \"" + GenFullName(*e) + "\" : {";
+      code_ += "      " + GenType("string") + ",";
+      std::string enumdef("      \"enum\": [");
+      for (auto enum_value = (*e)->vals.vec.begin(); 
+           enum_value != (*e)->vals.vec.end();
+           ++enum_value) {
+        enumdef.append("\"" + (*enum_value)->name + "\"");
+        if (*enum_value != (*e)->vals.vec.back()) {
+          enumdef.append(", ");
+        }
+      }
+      enumdef.append("]");
+      code_ += enumdef;
+      code_ += "    },";  // close type
+    }
+    for (auto s = parser_.structs_.vec.cbegin(); 
+         s != parser_.structs_.vec.cend();
+         ++s) {
+      const auto &structure = *s;
+      code_ += "    \"" + GenFullName(structure) + "\" : {";
+      code_ += "      " + GenType("object") + ",";
+      std::string comment;
+      const auto &comment_lines = structure->doc_comment;
+      for (auto comment_line = comment_lines.cbegin();
+           comment_line != comment_lines.cend();
+           ++comment_line) {
+        comment.append(*comment_line);
+      }
+      if (comment.size() > 0) {
+        code_ += "      \"description\" : \"" + comment + "\",";
+      }
+      code_ += "      \"properties\" : {";
+
+      const auto &properties = structure->fields.vec;
+      for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) {
+        const auto &property = *prop;
+        std::string typeLine("        \"" + property->name + "\" : { " + GenType(property->value.type) + " }");
+        if (property != properties.back()) {
+          typeLine.append(",");
+        }          
+        code_ += typeLine;
+      }
+      code_ += "      },";  // close properties
+
+      std::vector<FieldDef *> requiredProperties;
+      std::copy_if(properties.begin(), properties.end(),
+                   back_inserter(requiredProperties),
+                   [](FieldDef const *prop) { return prop->required; });
+      if (requiredProperties.size() > 0) {
+        std::string required_string("      \"required\" : [");
+        for (auto req_prop = requiredProperties.cbegin();
+             req_prop != requiredProperties.cend();
+             ++req_prop) {
+          required_string.append("\"" + (*req_prop)->name + "\"");
+          if (*req_prop != requiredProperties.back()) {
+            required_string.append(", ");
+          }
+        }
+        required_string.append("],");
+        code_ += required_string;
+      }
+      code_ += "      \"additionalProperties\" : false";
+      std::string closeType("    }");
+      if (*s != parser_.structs_.vec.back()) {
+        closeType.append(",");
+      }
+      code_ += closeType;  // close type
+    }
+    code_ += "  },";  // close definitions
+
+    // mark root type
+    code_ += "  \"$ref\" : \"#/definitions/" +
+             GenFullName(parser_.root_struct_def_) + "\"";
+
+    code_ += "}";  // close schema root
+    const std::string file_path = GeneratedFileName(path_, file_name_);
+    const std::string final_code = code_.ToString();
+    return SaveFile(file_path.c_str(), final_code, false);
+  }
+};
+}  // namespace jsons
+
+bool GenerateJsonSchema(const Parser &parser, const std::string &path,
+                        const std::string &file_name) {
+  jsons::JsonSchemaGenerator generator(parser, path, file_name);
+  return generator.generate();
+}
+}  // namespace flatbuffers
diff --git a/src/idl_gen_php.cpp b/src/idl_gen_php.cpp
index a893f98..b261089 100644
--- a/src/idl_gen_php.cpp
+++ b/src/idl_gen_php.cpp
@@ -66,8 +66,11 @@
                      const bool needs_imports, std::string *code_ptr) {
         std::string &code = *code_ptr;
         code += "<?php\n";
-        code = code + "// " + FlatBuffersGeneratedWarning();
-        code += "namespace " + name_space_name + ";\n\n";
+        code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n";
+
+        if (!name_space_name.empty()) {
+          code += "namespace " + name_space_name + ";\n\n";
+        }
 
         if (needs_imports) {
           code += "use \\Google\\FlatBuffers\\Struct;\n";
@@ -428,6 +431,31 @@
       code += Indent + "}\n\n";
     }
 
+    // Get the value of a vector's union member. Uses a named return
+    // argument to conveniently set the zero value for the result.
+    void GetMemberOfVectorOfUnion(const FieldDef &field,
+      std::string *code_ptr) {
+      std::string &code = *code_ptr;
+      auto vectortype = field.value.type.VectorType();
+
+      code += Indent + "/**\n";
+      code += Indent + " * @param int offset\n";
+      code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n";
+      code += Indent + " */\n";
+      code += Indent + "public function get";
+      code += MakeCamel(field.name);
+      code += "($j, $obj)\n";
+      code += Indent + "{\n";
+      code += Indent + Indent +
+        "$o = $this->__offset(" +
+        NumToString(field.value.offset) +
+        ");\n";
+      code += Indent + Indent + "return $o != 0 ? ";
+      code += "$this->__union($obj, $this->__vector($o) + $j * ";
+      code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n";
+      code += Indent + "}\n\n";
+    }
+
     // Recursively generate arguments for a constructor, to deal with nested
     // structs.
     static void StructBuilderArgs(const StructDef &struct_def,
@@ -703,7 +731,9 @@
           break;
         case BASE_TYPE_VECTOR: {
           auto vectortype = field.value.type.VectorType();
-          if (vectortype.base_type == BASE_TYPE_STRUCT) {
+          if (vectortype.base_type == BASE_TYPE_UNION) {
+            GetMemberOfVectorOfUnion(field, code_ptr);
+          } else if (vectortype.base_type == BASE_TYPE_STRUCT) {
             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
           } else {
             GetMemberOfVectorOfNonStruct(field, code_ptr);
@@ -879,7 +909,8 @@
 
     static std::string GenTypeBasic(const Type &type) {
       static const char *ctypename[] = {
-#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+#define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+    CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
     #NTYPE,
         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
 #undef FLATBUFFERS_TD
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index 76fea3e..a1a96b5 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -198,7 +198,7 @@
   code += OffsetPrefix(field);
   code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
   code += "o + self._tab.Pos)\n";
-  code += Indent + Indent + "return \"\"\n\n";
+  code += Indent + Indent + "return bytes()\n\n";
 }
 
 // Get the value of a union from an object.
@@ -274,6 +274,38 @@
   code += "\n";
 }
 
+// Returns a non-struct vector as a numpy array. Much faster
+// than iterating over the vector element by element.
+static void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
+                                        const FieldDef &field,
+                                        std::string *code_ptr) {
+  std::string &code = *code_ptr;
+  auto vectortype = field.value.type.VectorType();
+
+  // Currently, we only support accessing as numpy array if
+  // the vector type is a scalar.
+  if (!(IsScalar(vectortype.base_type))) {
+    return;
+  }
+
+  GenReceiver(struct_def, code_ptr);
+  code += MakeCamel(field.name) + "AsNumpy(self):";
+  code += OffsetPrefix(field);
+
+  code += Indent + Indent + Indent;
+  code += "return ";
+  code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
+  code += MakeCamel(GenTypeGet(field.value.type));
+  code += "Flags, o)\n";
+
+  if (vectortype.base_type == BASE_TYPE_STRING) {
+    code += Indent + Indent + "return \"\"\n";
+  } else {
+    code += Indent + Indent + "return 0\n";
+  }
+  code += "\n";
+}
+
 // Begin the creator function signature.
 static void BeginBuilderArgs(const StructDef &struct_def,
                              std::string *code_ptr) {
@@ -440,6 +472,7 @@
           GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
         } else {
           GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+          GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
         }
         break;
       }
@@ -547,7 +580,8 @@
 
 static std::string GenTypeBasic(const Type &type) {
   static const char *ctypename[] = {
-    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
       #PTYPE,
       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
     #undef FLATBUFFERS_TD
@@ -630,7 +664,7 @@
   void BeginFile(const std::string name_space_name, const bool needs_imports,
                  std::string *code_ptr) {
     std::string &code = *code_ptr;
-    code = code + "# " + FlatBuffersGeneratedWarning();
+    code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
     code += "# namespace: " + name_space_name + "\n\n";
     if (needs_imports) {
       code += "import flatbuffers\n\n";
@@ -643,7 +677,7 @@
     if (!classcode.length()) return true;
 
     std::string namespace_dir = path_;
-    auto &namespaces = parser_.namespaces_.back()->components;
+    auto &namespaces = def.defined_namespace->components;
     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
       namespace_dir += *it;
diff --git a/src/idl_gen_text.cpp b/src/idl_gen_text.cpp
index 17cd987..50d54c5 100644
--- a/src/idl_gen_text.cpp
+++ b/src/idl_gen_text.cpp
@@ -19,6 +19,7 @@
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
 #include "flatbuffers/util.h"
+#include "flatbuffers/flexbuffers.h"
 
 namespace flatbuffers {
 
@@ -49,7 +50,7 @@
 // for a single FlatBuffer value into JSON format.
 // The general case for scalars:
 template<typename T> bool Print(T val, Type type, int /*indent*/,
-                                StructDef * /*union_sd*/,
+                                Type * /*union_type*/,
                                 const IDLOptions &opts,
                                 std::string *_text) {
   std::string &text = *_text;
@@ -79,7 +80,7 @@
   text += NewLine(opts);
   for (uoffset_t i = 0; i < v.size(); i++) {
     if (i) {
-      text += ",";
+      if (!opts.protobuf_ascii_alike) text += ",";
       text += NewLine(opts);
     }
     text.append(indent + Indent(opts), ' ');
@@ -101,90 +102,19 @@
   return true;
 }
 
-static bool EscapeString(const String &s, std::string *_text, const IDLOptions& opts) {
-  std::string &text = *_text;
-  text += "\"";
-  for (uoffset_t i = 0; i < s.size(); i++) {
-    char c = s[i];
-    switch (c) {
-      case '\n': text += "\\n"; break;
-      case '\t': text += "\\t"; break;
-      case '\r': text += "\\r"; break;
-      case '\b': text += "\\b"; break;
-      case '\f': text += "\\f"; break;
-      case '\"': text += "\\\""; break;
-      case '\\': text += "\\\\"; break;
-      default:
-        if (c >= ' ' && c <= '~') {
-          text += c;
-        } else {
-          // Not printable ASCII data. Let's see if it's valid UTF-8 first:
-          const char *utf8 = s.c_str() + i;
-          int ucc = FromUTF8(&utf8);
-          if (ucc < 0) {
-            if (opts.allow_non_utf8) {
-              text += "\\x";
-              text += IntToStringHex(static_cast<uint8_t>(c), 2);
-            } else {
-              // There are two cases here:
-              //
-              // 1) We reached here by parsing an IDL file. In that case,
-              // we previously checked for non-UTF-8, so we shouldn't reach
-              // here.
-              //
-              // 2) We reached here by someone calling GenerateText()
-              // on a previously-serialized flatbuffer. The data might have
-              // non-UTF-8 Strings, or might be corrupt.
-              //
-              // In both cases, we have to give up and inform the caller
-              // they have no JSON.
-              return false;
-            }
-          } else {
-            if (ucc <= 0xFFFF) {
-              // Parses as Unicode within JSON's \uXXXX range, so use that.
-              text += "\\u";
-              text += IntToStringHex(ucc, 4);
-            } else if (ucc <= 0x10FFFF) {
-              // Encode Unicode SMP values to a surrogate pair using two \u escapes.
-              uint32_t base = ucc - 0x10000;
-              auto high_surrogate = (base >> 10) + 0xD800;
-              auto low_surrogate = (base & 0x03FF) + 0xDC00;
-              text += "\\u";
-              text += IntToStringHex(high_surrogate, 4);
-              text += "\\u";
-              text += IntToStringHex(low_surrogate, 4);
-            }
-            // Skip past characters recognized.
-            i = static_cast<uoffset_t>(utf8 - s.c_str() - 1);
-          }
-        }
-        break;
-    }
-  }
-  text += "\"";
-  return true;
-}
-
 // Specialization of Print above for pointer types.
 template<> bool Print<const void *>(const void *val,
                                     Type type, int indent,
-                                    StructDef *union_sd,
+                                    Type *union_type,
                                     const IDLOptions &opts,
                                     std::string *_text) {
   switch (type.base_type) {
     case BASE_TYPE_UNION:
       // If this assert hits, you have an corrupt buffer, a union type field
       // was not present or was out of range.
-      assert(union_sd);
-      if (!GenStruct(*union_sd,
-                     reinterpret_cast<const Table *>(val),
-                     indent,
-                     opts,
-                     _text)) {
-        return false;
-      }
-      break;
+      assert(union_type);
+      return Print<const void *>(val, *union_type, indent, nullptr, opts,
+                                 _text);
     case BASE_TYPE_STRUCT:
       if (!GenStruct(*type.struct_def,
                      reinterpret_cast<const Table *>(val),
@@ -195,7 +125,8 @@
       }
       break;
     case BASE_TYPE_STRING: {
-      if (!EscapeString(*reinterpret_cast<const String *>(val), _text, opts)) {
+      auto s = reinterpret_cast<const String *>(val);
+      if (!EscapeString(s->c_str(), s->Length(), _text, opts.allow_non_utf8)) {
         return false;
       }
       break;
@@ -204,8 +135,8 @@
       type = type.VectorType();
       // Call PrintVector above specifically for each element type:
       switch (type.base_type) {
-        #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-          PTYPE) \
+        #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+          CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
           case BASE_TYPE_ ## ENUM: \
             if (!PrintVector<CTYPE>( \
                   *reinterpret_cast<const Vector<CTYPE> *>(val), \
@@ -234,9 +165,13 @@
                                             opts, _text);
 }
 
+static bool GenStruct(const StructDef &struct_def, const Table *table,
+						  int indent, const IDLOptions &opts,
+						  std::string *_text);
+
 // Generate text for non-scalar field.
 static bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed,
-                           int indent, StructDef *union_sd,
+                           int indent, Type *union_type,
                            const IDLOptions &opts, std::string *_text) {
   const void *val = nullptr;
   if (fixed) {
@@ -244,12 +179,21 @@
     assert(IsStruct(fd.value.type));
     val = reinterpret_cast<const Struct *>(table)->
             GetStruct<const void *>(fd.value.offset);
+  } else if (fd.flexbuffer) {
+    auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+    auto root = flexbuffers::GetRoot(vec->data(), vec->size());
+    root.ToString(true, opts.strict_json, *_text);
+    return true;
+  } else if (fd.nested_flatbuffer) {
+    auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset);
+    auto root = GetRoot<Table>(vec->data());
+    return GenStruct(*fd.nested_flatbuffer, root, indent, opts, _text);
   } else {
     val = IsStruct(fd.value.type)
       ? table->GetStruct<const void *>(fd.value.offset)
       : table->GetPointer<const void *>(fd.value.offset);
   }
-  return Print(val, fd.value.type, indent, union_sd, opts, _text);
+  return Print(val, fd.value.type, indent, union_type, opts, _text);
 }
 
 // Generate text for a struct or table, values separated by commas, indented,
@@ -260,7 +204,7 @@
   std::string &text = *_text;
   text += "{";
   int fieldout = 0;
-  StructDef *union_sd = nullptr;
+  Type *union_type = nullptr;
   for (auto it = struct_def.fields.vec.begin();
        it != struct_def.fields.vec.end();
        ++it) {
@@ -271,16 +215,19 @@
                          !fd.deprecated;
     if (is_present || output_anyway) {
       if (fieldout++) {
-        text += ",";
+        if (!opts.protobuf_ascii_alike) text += ",";
       }
       text += NewLine(opts);
       text.append(indent + Indent(opts), ' ');
       OutputIdentifier(fd.name, opts, _text);
-      text += ": ";
+      if (!opts.protobuf_ascii_alike ||
+          (fd.value.type.base_type != BASE_TYPE_STRUCT &&
+           fd.value.type.base_type != BASE_TYPE_VECTOR)) text += ":";
+      text += " ";
       if (is_present) {
         switch (fd.value.type.base_type) {
-           #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-             PTYPE) \
+           #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+             CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
              case BASE_TYPE_ ## ENUM: \
                 if (!GenField<CTYPE>(fd, table, struct_def.fixed, \
                                      opts, indent + Indent(opts), _text)) { \
@@ -290,13 +237,13 @@
             FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD)
           #undef FLATBUFFERS_TD
           // Generate drop-thru case statements for all pointer types:
-          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-            PTYPE) \
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
             case BASE_TYPE_ ## ENUM:
             FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD)
           #undef FLATBUFFERS_TD
               if (!GenFieldOffset(fd, table, struct_def.fixed, indent + Indent(opts),
-                                  union_sd, opts, _text)) {
+                                  union_type, opts, _text)) {
                 return false;
               }
               break;
@@ -305,7 +252,7 @@
           auto enum_val = fd.value.type.enum_def->ReverseLookup(
                                   table->GetField<uint8_t>(fd.value.offset, 0));
           assert(enum_val);
-          union_sd = enum_val->struct_def;
+          union_type = &enum_val->union_type;
         }
       }
       else
diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp
index 7adfcca..57e7226 100644
--- a/src/idl_parser.cpp
+++ b/src/idl_parser.cpp
@@ -16,12 +16,7 @@
 
 #include <algorithm>
 #include <list>
-
-#ifdef _WIN32
-#if !defined(_USE_MATH_DEFINES)
-#define _USE_MATH_DEFINES  // For M_PI.
-#endif                     // !defined(_USE_MATH_DEFINES)
-#endif                     // _WIN32
+#include <iostream>
 
 #include <math.h>
 
@@ -30,8 +25,11 @@
 
 namespace flatbuffers {
 
+const double kPi = 3.14159265358979323846;
+
 const char *const kTypeNames[] = {
-  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+  #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+    CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
     IDLTYPE,
     FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
   #undef FLATBUFFERS_TD
@@ -39,7 +37,8 @@
 };
 
 const char kTypeSizes[] = {
-  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+  #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
       sizeof(CTYPE),
     FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
   #undef FLATBUFFERS_TD
@@ -72,7 +71,7 @@
   return true;
 }
 
-CheckedError Parser::Error(const std::string &msg) {
+void Parser::Message(const std::string &msg) {
   error_ = file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : "";
   #ifdef _WIN32
     error_ += "(" + NumToString(line_) + ")";  // MSVC alike
@@ -80,32 +79,43 @@
     if (file_being_parsed_.length()) error_ += ":";
     error_ += NumToString(line_) + ":0";  // gcc alike
   #endif
-  error_ += ": error: " + msg;
+  error_ += ": " + msg;
+}
+
+void Parser::Warning(const std::string &msg) {
+  Message("warning: " + msg);
+}
+
+CheckedError Parser::Error(const std::string &msg) {
+  Message("error: " + msg);
   return CheckedError(true);
 }
 
 inline CheckedError NoError() { return CheckedError(false); }
 
+inline std::string OutOfRangeErrorMsg(int64_t val, const std::string &op,
+                                      int64_t limit) {
+  const std::string cause = NumToString(val) + op + NumToString(limit);
+  return "constant does not fit (" + cause + ")";
+}
+
 // Ensure that integer values we parse fit inside the declared integer type.
-CheckedError Parser::CheckBitsFit(int64_t val, size_t bits) {
-  // Left-shifting a 64-bit value by 64 bits or more is undefined
-  // behavior (C99 6.5.7), so check *before* we shift.
-  if (bits < 64) {
-    // Bits we allow to be used.
-    auto mask = static_cast<int64_t>((1ull << bits) - 1);
-    if ((val & ~mask) != 0 &&  // Positive or unsigned.
-        (val |  mask) != -1)   // Negative.
-      return Error("constant does not fit in a " + NumToString(bits) +
-                   "-bit field");
-  }
-  return NoError();
+CheckedError Parser::CheckInRange(int64_t val, int64_t min, int64_t max) {
+  if (val < min)
+    return Error(OutOfRangeErrorMsg(val, " < ", min));
+  else if (val > max)
+    return Error(OutOfRangeErrorMsg(val, " > ", max));
+  else
+    return NoError();
 }
 
 // atot: templated version of atoi/atof: convert a string to an instance of T.
 template<typename T> inline CheckedError atot(const char *s, Parser &parser,
                                               T *val) {
   int64_t i = StringToInt(s);
-  ECHECK(parser.CheckBitsFit(i, sizeof(T) * 8));
+  const int64_t min = flatbuffers::numeric_limits<T>::min();
+  const int64_t max = flatbuffers::numeric_limits<T>::max();
+  ECHECK(parser.CheckInRange(i, min, max));
   *val = (T)i;
   return NoError();
 }
@@ -159,8 +169,6 @@
   return stream.str();
 }
 
-
-
 // Declare tokens we'll use. Single character tokens are represented by their
 // ascii character code (e.g. '{'), others above 256.
 #define FLATBUFFERS_GEN_TOKENS(TD) \
@@ -168,20 +176,7 @@
   TD(StringConstant, 257, "string constant") \
   TD(IntegerConstant, 258, "integer constant") \
   TD(FloatConstant, 259, "float constant") \
-  TD(Identifier, 260, "identifier") \
-  TD(Table, 261, "table") \
-  TD(Struct, 262, "struct") \
-  TD(Enum, 263, "enum") \
-  TD(Union, 264, "union") \
-  TD(NameSpace, 265, "namespace") \
-  TD(RootType, 266, "root_type") \
-  TD(FileIdentifier, 267, "file_identifier") \
-  TD(FileExtension, 268, "file_extension") \
-  TD(Include, 269, "include") \
-  TD(Attribute, 270, "attribute") \
-  TD(Null, 271, "null") \
-  TD(Service, 272, "rpc_service") \
-  TD(NativeInclude, 273, "native_include")
+  TD(Identifier, 260, "identifier")
 #ifdef __GNUC__
 __extension__  // Stop GCC complaining about trailing comma with -Wpendantic.
 #endif
@@ -189,10 +184,6 @@
   #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE,
     FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
   #undef FLATBUFFERS_TOKEN
-  #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
-      kToken ## ENUM,
-    FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
-  #undef FLATBUFFERS_TD
 };
 
 static std::string TokenToString(int t) {
@@ -200,7 +191,8 @@
     #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING,
       FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN)
     #undef FLATBUFFERS_TOKEN
-    #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+      CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
       IDLTYPE,
       FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
     #undef FLATBUFFERS_TD
@@ -215,7 +207,7 @@
 }
 
 std::string Parser::TokenToStringId(int t) {
-  return TokenToString(t) + (t == kTokenIdentifier ? ": " + attribute_ : "");
+  return t == kTokenIdentifier ? attribute_ : TokenToString(t);
 }
 
 // Parses exactly nibbles worth of hex digits into a number, or error.
@@ -231,11 +223,14 @@
 }
 
 CheckedError Parser::SkipByteOrderMark() {
-  if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError();
+  if (static_cast<unsigned char>(*cursor_) != 0xef)
+    return NoError();
   cursor_++;
-  if (static_cast<unsigned char>(*cursor_) != 0xbb) return Error("invalid utf-8 byte order mark");
+  if (static_cast<unsigned char>(*cursor_) != 0xbb)
+    return Error("invalid utf-8 byte order mark");
   cursor_++;
-  if (static_cast<unsigned char>(*cursor_) != 0xbf) return Error("invalid utf-8 byte order mark");
+  if (static_cast<unsigned char>(*cursor_) != 0xbf)
+    return Error("invalid utf-8 byte order mark");
   cursor_++;
   return NoError();
 }
@@ -374,76 +369,6 @@
                  *cursor_ == '_')
             cursor_++;
           attribute_.append(start, cursor_);
-          // First, see if it is a type keyword from the table of types:
-          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-            PTYPE) \
-            if (attribute_ == IDLTYPE) { \
-              token_ = kToken ## ENUM; \
-              return NoError(); \
-            }
-            FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
-          #undef FLATBUFFERS_TD
-          // If it's a boolean constant keyword, turn those into integers,
-          // which simplifies our logic downstream.
-          if (attribute_ == "true" || attribute_ == "false") {
-            attribute_ = NumToString(attribute_ == "true");
-            token_ = kTokenIntegerConstant;
-            return NoError();
-          }
-          // Check for declaration keywords:
-          if (attribute_ == "table") {
-            token_ = kTokenTable;
-            return NoError();
-          }
-          if (attribute_ == "struct") {
-            token_ = kTokenStruct;
-            return NoError();
-          }
-          if (attribute_ == "enum") {
-            token_ = kTokenEnum;
-            return NoError();
-          }
-          if (attribute_ == "union") {
-            token_ = kTokenUnion;
-            return NoError();
-          }
-          if (attribute_ == "namespace") {
-            token_ = kTokenNameSpace;
-            return NoError();
-          }
-          if (attribute_ == "root_type") {
-            token_ = kTokenRootType;
-            return NoError();
-          }
-          if (attribute_ == "include") {
-            token_ = kTokenInclude;
-            return NoError();
-          }
-          if (attribute_ == "attribute") {
-            token_ = kTokenAttribute;
-            return NoError();
-          }
-          if (attribute_ == "file_identifier") {
-            token_ = kTokenFileIdentifier;
-            return NoError();
-          }
-          if (attribute_ == "file_extension") {
-            token_ = kTokenFileExtension;
-            return NoError();
-          }
-          if (attribute_ == "null") {
-            token_ = kTokenNull;
-            return NoError();
-          }
-          if (attribute_ == "rpc_service") {
-            token_ = kTokenService;
-            return NoError();
-          }
-          if (attribute_ == "native_include") {
-            token_ = kTokenNativeInclude;
-            return NoError();
-          }
-          // If not, it is a user-defined identifier:
           token_ = kTokenIdentifier;
           return NoError();
         } else if (isdigit(static_cast<unsigned char>(c)) || c == '-') {
@@ -497,6 +422,10 @@
   return t == token_;
 }
 
+bool Parser::IsIdent(const char *id) {
+  return token_ == kTokenIdentifier && attribute_ == id;
+}
+
 // Expect a given token to be next, consume it, or error if not present.
 CheckedError Parser::Expect(int t) {
   if (t != token_) {
@@ -520,15 +449,21 @@
 
 EnumDef *Parser::LookupEnum(const std::string &id) {
   // Search thru parent namespaces.
-  for (int components = static_cast<int>(namespaces_.back()->components.size());
+  for (int components = static_cast<int>(current_namespace_->components.size());
        components >= 0; components--) {
     auto ed = enums_.Lookup(
-                namespaces_.back()->GetFullyQualifiedName(id, components));
+                current_namespace_->GetFullyQualifiedName(id, components));
     if (ed) return ed;
   }
   return nullptr;
 }
 
+StructDef *Parser::LookupStruct(const std::string &id) const {
+  auto sd = structs_.Lookup(id);
+  if (sd) sd->refcount++;
+  return sd;
+}
+
 CheckedError Parser::ParseTypeIdent(Type &type) {
   std::string id = attribute_;
   EXPECT(kTokenIdentifier);
@@ -546,28 +481,61 @@
 
 // Parse any IDL type.
 CheckedError Parser::ParseType(Type &type) {
-  if (token_ >= kTokenBOOL && token_ <= kTokenSTRING) {
-    type.base_type = static_cast<BaseType>(token_ - kTokenNONE);
-    NEXT();
-  } else {
-    if (token_ == kTokenIdentifier) {
-      ECHECK(ParseTypeIdent(type));
-    } else if (token_ == '[') {
+  if (token_ == kTokenIdentifier) {
+    if (IsIdent("bool")) {
+      type.base_type = BASE_TYPE_BOOL;
       NEXT();
-      Type subtype;
-      ECHECK(ParseType(subtype));
-      if (subtype.base_type == BASE_TYPE_VECTOR) {
-        // We could support this, but it will complicate things, and it's
-        // easier to work around with a struct around the inner vector.
-        return Error(
-              "nested vector types not supported (wrap in table first).");
-      }
-      type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
-      type.element = subtype.base_type;
-      EXPECT(']');
+    } else if (IsIdent("byte") || IsIdent("int8")) {
+      type.base_type = BASE_TYPE_CHAR;
+      NEXT();
+    } else if (IsIdent("ubyte") || IsIdent("uint8")) {
+      type.base_type = BASE_TYPE_UCHAR;
+      NEXT();
+    } else if (IsIdent("short") || IsIdent("int16")) {
+      type.base_type = BASE_TYPE_SHORT;
+      NEXT();
+    } else if (IsIdent("ushort") || IsIdent("uint16")) {
+      type.base_type = BASE_TYPE_USHORT;
+      NEXT();
+    } else if (IsIdent("int") || IsIdent("int32")) {
+      type.base_type = BASE_TYPE_INT;
+      NEXT();
+    } else if (IsIdent("uint") || IsIdent("uint32")) {
+      type.base_type = BASE_TYPE_UINT;
+      NEXT();
+    } else if (IsIdent("long") || IsIdent("int64")) {
+      type.base_type = BASE_TYPE_LONG;
+      NEXT();
+    } else if (IsIdent("ulong") || IsIdent("uint64")) {
+      type.base_type = BASE_TYPE_ULONG;
+      NEXT();
+    } else if (IsIdent("float") || IsIdent("float32")) {
+      type.base_type = BASE_TYPE_FLOAT;
+      NEXT();
+    } else if (IsIdent("double") || IsIdent("float64")) {
+      type.base_type = BASE_TYPE_DOUBLE;
+      NEXT();
+    } else if (IsIdent("string")) {
+      type.base_type = BASE_TYPE_STRING;
+      NEXT();
     } else {
-      return Error("illegal type syntax");
+      ECHECK(ParseTypeIdent(type));
     }
+  } else if (token_ == '[') {
+    NEXT();
+    Type subtype;
+    ECHECK(ParseType(subtype));
+    if (subtype.base_type == BASE_TYPE_VECTOR) {
+      // We could support this, but it will complicate things, and it's
+      // easier to work around with a struct around the inner vector.
+      return Error(
+            "nested vector types not supported (wrap in table first).");
+    }
+    type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def);
+    type.element = subtype.base_type;
+    EXPECT(']');
+  } else {
+    return Error("illegal type syntax");
   }
   return NoError();
 }
@@ -598,6 +566,10 @@
 
 CheckedError Parser::ParseField(StructDef &struct_def) {
   std::string name = attribute_;
+
+  if (LookupStruct(name))
+    return Error("field name can not be the same as table/struct name");
+
   std::vector<std::string> dc = doc_comment_;
   EXPECT(kTokenIdentifier);
   EXPECT(':');
@@ -615,8 +587,8 @@
                     type.enum_def->underlying_type, &typefield));
   } else if (type.base_type == BASE_TYPE_VECTOR &&
              type.element == BASE_TYPE_UNION) {
-    // Only cpp supports the union vector feature so far.
-    if (opts.lang_to_generate != IDLOptions::kCpp) {
+    // Only cpp, js and ts supports the union vector feature so far.
+    if (!SupportsVectorOfUnions()) {
       return Error("Vectors of unions are not yet supported in all "
                    "the specified programming languages.");
     }
@@ -648,7 +620,7 @@
       !type.enum_def->attributes.Lookup("bit_flags") &&
       !type.enum_def->ReverseLookup(static_cast<int>(
                          StringToInt(field->value.constant.c_str()))))
-    return Error("enum " + type.enum_def->name +
+    Warning("enum " + type.enum_def->name +
           " does not have a declaration for this field\'s default of " +
           field->value.constant);
 
@@ -700,6 +672,10 @@
     }
   }
 
+  auto field_native_custom_alloc = field->attributes.Lookup("native_custom_alloc");
+  if (field_native_custom_alloc)
+    return Error("native_custom_alloc can only be used with a table or struct definition");
+
   field->native_inline = field->attributes.Lookup("native_inline") != nullptr;
   if (field->native_inline && !IsStruct(field->value.type))
     return Error("native_inline can only be defined on structs'");
@@ -716,9 +692,27 @@
     // This will cause an error if the root type of the nested flatbuffer
     // wasn't defined elsewhere.
     LookupCreateStruct(nested->constant);
+
+    // Keep a pointer to StructDef in FieldDef to simplify re-use later
+    auto nested_qualified_name =
+        current_namespace_->GetFullyQualifiedName(nested->constant);
+    field->nested_flatbuffer = LookupStruct(nested_qualified_name);
+  }
+
+  if (field->attributes.Lookup("flexbuffer")) {
+    field->flexbuffer = true;
+    uses_flexbuffers_ = true;
+    if (field->value.type.base_type != BASE_TYPE_VECTOR ||
+        field->value.type.element != BASE_TYPE_UCHAR)
+      return Error(
+            "flexbuffer attribute may only apply to a vector of ubyte");
   }
 
   if (typefield) {
+    if (!IsScalar(typefield->value.type.base_type)) {
+      // this is a union vector field
+      typefield->required = field->required;
+    }
     // If this field is a union, and it has a manually assigned id,
     // the automatically added type field should have an id as well (of N - 1).
     auto attr = field->attributes.Lookup("id");
@@ -735,6 +729,18 @@
   return NoError();
 }
 
+CheckedError Parser::ParseString(Value &val) {
+  auto s = attribute_;
+  EXPECT(kTokenStringConstant);
+  val.constant = NumToString(builder_.CreateString(s).o);
+  return NoError();
+}
+
+CheckedError Parser::ParseComma() {
+  if (!opts.protobuf_ascii_alike) EXPECT(',');
+  return NoError();
+}
+
 CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
                                    size_t parent_fieldn,
                                    const StructDef *parent_struct_def) {
@@ -763,7 +769,7 @@
         // Remember where we are in the source file, so we can come back here.
         auto backup = *static_cast<ParserState *>(this);
         ECHECK(SkipAnyJsonValue());  // The table.
-        EXPECT(',');
+        ECHECK(ParseComma());
         auto next_name = attribute_;
         if (Is(kTokenStringConstant)) {
           NEXT();
@@ -784,20 +790,30 @@
       ECHECK(atot(constant.c_str(), *this, &enum_idx));
       auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
       if (!enum_val) return Error("illegal type id for: " + field->name);
-      ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
+      if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) {
+        ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant,
+                          nullptr));
+        if (enum_val->union_type.struct_def->fixed) {
+          // All BASE_TYPE_UNION values are offsets, so turn this into one.
+          SerializeStruct(*enum_val->union_type.struct_def, val);
+          builder_.ClearOffsets();
+          val.constant = NumToString(builder_.GetSize());
+        }
+      } else if (enum_val->union_type.base_type == BASE_TYPE_STRING) {
+        ECHECK(ParseString(val));
+      } else {
+        assert(false);
+      }
       break;
     }
     case BASE_TYPE_STRUCT:
       ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr));
       break;
     case BASE_TYPE_STRING: {
-      auto s = attribute_;
-      EXPECT(kTokenStringConstant);
-      val.constant = NumToString(builder_.CreateString(s).o);
+      ECHECK(ParseString(val));
       break;
     }
     case BASE_TYPE_VECTOR: {
-      EXPECT('[');
       uoffset_t off;
       ECHECK(ParseVector(val.type.VectorType(), &off));
       val.constant = NumToString(off);
@@ -830,53 +846,128 @@
   builder_.AddStructOffset(val.offset, builder_.GetSize());
 }
 
+CheckedError Parser::ParseTableDelimiters(size_t &fieldn,
+                                          const StructDef *struct_def,
+                                          ParseTableDelimitersBody body,
+                                          void *state) {
+  // We allow tables both as JSON object{ .. } with field names
+  // or vector[..] with all fields in order
+  char terminator = '}';
+  bool is_nested_vector = struct_def && Is('[');
+  if (is_nested_vector) {
+    NEXT();
+    terminator = ']';
+  } else {
+    EXPECT('{');
+  }
+  for (;;) {
+    if ((!opts.strict_json || !fieldn) && Is(terminator)) break;
+    std::string name;
+    if (is_nested_vector) {
+      if (fieldn > struct_def->fields.vec.size()) {
+        return Error("too many unnamed fields in nested array");
+      }
+      name = struct_def->fields.vec[fieldn]->name;
+    } else {
+      name = attribute_;
+      if (Is(kTokenStringConstant)) {
+        NEXT();
+      } else {
+        EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
+      }
+      if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':');
+    }
+    ECHECK(body(name, fieldn, struct_def, state));
+    if (Is(terminator)) break;
+    ECHECK(ParseComma());
+  }
+  NEXT();
+  if (is_nested_vector && fieldn != struct_def->fields.vec.size()) {
+    return Error("wrong number of unnamed fields in table vector");
+  }
+  return NoError();
+}
+
 CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
                                 uoffset_t *ovalue) {
-  EXPECT('{');
-  size_t fieldn = 0;
-  for (;;) {
-    if ((!opts.strict_json || !fieldn) && Is('}')) { NEXT(); break; }
-    std::string name = attribute_;
-    if (Is(kTokenStringConstant)) {
-      NEXT();
-    } else {
-      EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
+  size_t fieldn_outer = 0;
+  auto err = ParseTableDelimiters(fieldn_outer, &struct_def,
+                                  [](const std::string &name, size_t &fieldn,
+                                             const StructDef *struct_def_inner,
+                                             void *state) -> CheckedError {
+    Parser *parser = static_cast<Parser *>(state);
+    if (name == "$schema") {
+      ECHECK(parser->Expect(kTokenStringConstant));
+      return NoError();
     }
-    auto field = struct_def.fields.Lookup(name);
+    auto field = struct_def_inner->fields.Lookup(name);
     if (!field) {
-      if (!opts.skip_unexpected_fields_in_json) {
-        return Error("unknown field: " + name);
+      if (!parser->opts.skip_unexpected_fields_in_json) {
+        return parser->Error("unknown field: " + name);
       } else {
-        EXPECT(':');
-        ECHECK(SkipAnyJsonValue());
+        ECHECK(parser->SkipAnyJsonValue());
       }
     } else {
-      EXPECT(':');
-      if (Is(kTokenNull)) {
-        NEXT(); // Ignore this field.
+      if (parser->IsIdent("null")) {
+        ECHECK(parser->Next());  // Ignore this field.
       } else {
         Value val = field->value;
-        ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
+        if (field->flexbuffer) {
+          flexbuffers::Builder builder(1024,
+                                       flexbuffers::BUILDER_FLAG_SHARE_ALL);
+          ECHECK(parser->ParseFlexBufferValue(&builder));
+          builder.Finish();
+          auto off = parser->builder_.CreateVector(builder.GetBuffer());
+          val.constant = NumToString(off.o);
+        } else if (field->nested_flatbuffer) {
+          ECHECK(parser->ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner));
+        } else {
+          ECHECK(parser->ParseAnyValue(val, field, fieldn, struct_def_inner));
+        }
         // Hardcoded insertion-sort with error-check.
         // If fields are specified in order, then this loop exits immediately.
-        auto elem = field_stack_.rbegin();
-        for (; elem != field_stack_.rbegin() + fieldn; ++elem) {
+        auto elem = parser->field_stack_.rbegin();
+        for (; elem != parser->field_stack_.rbegin() + fieldn; ++elem) {
           auto existing_field = elem->second;
           if (existing_field == field)
-            return Error("field set more than once: " + field->name);
+            return parser->Error("field set more than once: " + field->name);
           if (existing_field->value.offset < field->value.offset) break;
         }
         // Note: elem points to before the insertion point, thus .base() points
         // to the correct spot.
-        field_stack_.insert(elem.base(), std::make_pair(val, field));
+        parser->field_stack_.insert(elem.base(),
+                                    std::make_pair(val, field));
         fieldn++;
       }
     }
-    if (Is('}')) { NEXT(); break; }
-    EXPECT(',');
+    return NoError();
+  }, this);
+  ECHECK(err);
+
+  // Check if all required fields are parsed.
+  for (auto field_it = struct_def.fields.vec.begin();
+            field_it != struct_def.fields.vec.end();
+            ++field_it) {
+    auto required_field = *field_it;
+    if (!required_field->required) {
+      continue;
+    }
+    bool found = false;
+    for (auto pf_it = field_stack_.end() - fieldn_outer;
+         pf_it != field_stack_.end();
+         ++pf_it) {
+      auto parsed_field = pf_it->second;
+      if (parsed_field == required_field) {
+        found = true;
+        break;
+      }
+    }
+    if (!found) {
+      return Error("required field is missing: " + required_field->name + " in " + struct_def.name);
+    }
   }
 
-  if (struct_def.fixed && fieldn != struct_def.fields.vec.size())
+  if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size())
     return Error("struct: wrong number of initializers: " + struct_def.name);
 
   auto start = struct_def.fixed
@@ -887,15 +978,16 @@
        size;
        size /= 2) {
     // Go through elements in reverse, since we're building the data backwards.
-    for (auto it = field_stack_.rbegin();
-             it != field_stack_.rbegin() + fieldn; ++it) {
+    for (auto it = field_stack_.rbegin(); it != field_stack_.rbegin() +
+             fieldn_outer;
+         ++it) {
       auto &field_value = it->first;
       auto field = it->second;
       if (!struct_def.sortbysize ||
           size == SizeOf(field_value.type.base_type)) {
         switch (field_value.type.base_type) {
-          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-            PTYPE) \
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
             case BASE_TYPE_ ## ENUM: \
               builder_.Pad(field->padding); \
               if (struct_def.fixed) { \
@@ -911,8 +1003,8 @@
               break;
             FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD);
           #undef FLATBUFFERS_TD
-          #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, \
-            PTYPE) \
+          #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+            CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
             case BASE_TYPE_ ## ENUM: \
               builder_.Pad(field->padding); \
               if (IsStruct(field->value.type)) { \
@@ -929,7 +1021,7 @@
       }
     }
   }
-  for (size_t i = 0; i < fieldn; i++) field_stack_.pop_back();
+  for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back();
 
   if (struct_def.fixed) {
     builder_.ClearOffsets();
@@ -943,34 +1035,52 @@
     builder_.PopBytes(struct_def.bytesize);
     assert(!ovalue);
   } else {
-    auto val = builder_.EndTable(start,
-                          static_cast<voffset_t>(struct_def.fields.vec.size()));
+    auto val = builder_.EndTable(start);
     if (ovalue) *ovalue = val;
     if (value) *value = NumToString(val);
   }
   return NoError();
 }
 
-CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
-  int count = 0;
+CheckedError Parser::ParseVectorDelimiters(size_t &count,
+                                           ParseVectorDelimitersBody body,
+                                           void *state) {
+  EXPECT('[');
   for (;;) {
-    if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
-    Value val;
-    val.type = type;
-    ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
-    field_stack_.push_back(std::make_pair(val, nullptr));
+    if ((!opts.strict_json || !count) && Is(']')) break;
+    ECHECK(body(count, state));
     count++;
-    if (Is(']')) { NEXT(); break; }
-    EXPECT(',');
+    if (Is(']')) break;
+    ECHECK(ParseComma());
   }
+  NEXT();
+  return NoError();
+}
+
+CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
+  size_t count = 0;
+  std::pair<Parser *, const Type &> parser_and_type_state(this, type);
+  auto err = ParseVectorDelimiters(count,
+                                   [](size_t &, void *state) -> CheckedError {
+    auto *parser_and_type =
+        static_cast<std::pair<Parser *, const Type &> *>(state);
+    auto *parser = parser_and_type->first;
+    Value val;
+    val.type = parser_and_type->second;
+    ECHECK(parser->ParseAnyValue(val, nullptr, 0, nullptr));
+    parser->field_stack_.push_back(std::make_pair(val, nullptr));
+    return NoError();
+  }, &parser_and_type_state);
+  ECHECK(err);
 
   builder_.StartVector(count * InlineSize(type) / InlineAlignment(type),
                        InlineAlignment(type));
-  for (int i = 0; i < count; i++) {
+  for (size_t i = 0; i < count; i++) {
     // start at the back, since we're building the data backwards.
     auto &val = field_stack_.back().first;
     switch (val.type.base_type) {
-      #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+      #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
         case BASE_TYPE_ ## ENUM: \
           if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \
           else { \
@@ -990,6 +1100,38 @@
   return NoError();
 }
 
+CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field,
+                                          size_t fieldn,
+                                          const StructDef *parent_struct_def) {
+  if (token_ == '[') {// backwards compat for 'legacy' ubyte buffers
+    ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def));
+  } else {
+    auto cursor_at_value_begin = cursor_;
+    ECHECK(SkipAnyJsonValue());
+    std::string substring(cursor_at_value_begin -1 , cursor_ -1);
+
+    // Create and initialize new parser
+    Parser nested_parser;
+    assert(field->nested_flatbuffer);
+    nested_parser.root_struct_def_ = field->nested_flatbuffer;
+    nested_parser.enums_ = enums_;
+    nested_parser.opts = opts;
+    nested_parser.uses_flexbuffers_ = uses_flexbuffers_;
+
+    // Parse JSON substring into new flatbuffer builder using nested_parser
+    if (!nested_parser.Parse(substring.c_str(), nullptr, nullptr)) {
+      ECHECK(Error(nested_parser.error_));
+    }
+    auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), nested_parser.builder_.GetSize());
+    val.constant = NumToString(off.o);
+
+    // Clean nested_parser before destruction to avoid deleting the elements in the SymbolTables
+    nested_parser.enums_.dict.clear();
+    nested_parser.enums_.vec.clear();
+  }
+  return NoError();
+}
+
 CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) {
   if (Is('(')) {
     NEXT();
@@ -1077,14 +1219,24 @@
   assert(field);
   Value *hash_name = field->attributes.Lookup("hash");
   switch (e.type.base_type) {
-    case BASE_TYPE_INT:
+    case BASE_TYPE_INT: {
+      auto hash = FindHashFunction32(hash_name->constant.c_str());
+      int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str()));
+      e.constant = NumToString(hashed_value);
+      break;
+    }
     case BASE_TYPE_UINT: {
       auto hash = FindHashFunction32(hash_name->constant.c_str());
       uint32_t hashed_value = hash(attribute_.c_str());
       e.constant = NumToString(hashed_value);
       break;
     }
-    case BASE_TYPE_LONG:
+    case BASE_TYPE_LONG: {
+      auto hash = FindHashFunction64(hash_name->constant.c_str());
+      int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str()));
+      e.constant = NumToString(hashed_value);
+      break;
+    }
     case BASE_TYPE_ULONG: {
       auto hash = FindHashFunction64(hash_name->constant.c_str());
       uint64_t hashed_value = hash(attribute_.c_str());
@@ -1098,6 +1250,11 @@
   return NoError();
 }
 
+CheckedError Parser::TokenError() {
+  return Error("cannot parse value starting with: " +
+               TokenToStringId(token_));
+}
+
 CheckedError Parser::ParseSingleValue(Value &e) {
   // First see if this could be a conversion function:
   if (token_ == kTokenIdentifier && *cursor_ == '(') {
@@ -1111,8 +1268,8 @@
         auto x = strtod(e.constant.c_str(), nullptr); \
         e.constant = NumToString(op); \
       }
-    FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
-    FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 180);
+    FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180);
+    FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180);
     FLATBUFFERS_FN_DOUBLE("sin", sin(x));
     FLATBUFFERS_FN_DOUBLE("cos", cos(x));
     FLATBUFFERS_FN_DOUBLE("tan", tan(x));
@@ -1123,6 +1280,7 @@
     #undef FLATBUFFERS_FN_DOUBLE
   // Then check if this could be a string/identifier enum value:
   } else if (e.type.base_type != BASE_TYPE_STRING &&
+      e.type.base_type != BASE_TYPE_BOOL &&
       e.type.base_type != BASE_TYPE_NONE &&
       (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
     if (IsIdentifierStart(attribute_[0])) {  // Enum value.
@@ -1164,42 +1322,49 @@
                          e,
                          BASE_TYPE_STRING,
                          &match));
-    if (!match)
-      return Error("cannot parse value starting with: " +
-                   TokenToStringId(token_));
+    auto istrue = IsIdent("true");
+    if (istrue || IsIdent("false")) {
+      attribute_ = NumToString(istrue);
+      ECHECK(TryTypedValue(kTokenIdentifier,
+                           IsBool(e.type.base_type),
+                           e,
+                           BASE_TYPE_BOOL,
+                           &match));
+    }
+    if (!match) return TokenError();
   }
   return NoError();
 }
 
 StructDef *Parser::LookupCreateStruct(const std::string &name,
                                       bool create_if_new, bool definition) {
-  std::string qualified_name = namespaces_.back()->GetFullyQualifiedName(name);
+  std::string qualified_name = current_namespace_->GetFullyQualifiedName(name);
   // See if it exists pre-declared by an unqualified use.
-  auto struct_def = structs_.Lookup(name);
+  auto struct_def = LookupStruct(name);
   if (struct_def && struct_def->predecl) {
     if (definition) {
       // Make sure it has the current namespace, and is registered under its
       // qualified name.
-      struct_def->defined_namespace = namespaces_.back();
+      struct_def->defined_namespace = current_namespace_;
       structs_.Move(name, qualified_name);
     }
     return struct_def;
   }
   // See if it exists pre-declared by an qualified use.
-  struct_def = structs_.Lookup(qualified_name);
+  struct_def = LookupStruct(qualified_name);
   if (struct_def && struct_def->predecl) {
     if (definition) {
       // Make sure it has the current namespace.
-      struct_def->defined_namespace = namespaces_.back();
+      struct_def->defined_namespace = current_namespace_;
     }
     return struct_def;
   }
   if (!definition) {
     // Search thru parent namespaces.
-    for (size_t components = namespaces_.back()->components.size();
+    for (size_t components = current_namespace_->components.size();
          components && !struct_def; components--) {
-      struct_def = structs_.Lookup(
-          namespaces_.back()->GetFullyQualifiedName(name, components - 1));
+      struct_def = LookupStruct(
+          current_namespace_->GetFullyQualifiedName(name, components - 1));
     }
   }
   if (!struct_def && create_if_new) {
@@ -1207,18 +1372,18 @@
     if (definition) {
       structs_.Add(qualified_name, struct_def);
       struct_def->name = name;
-      struct_def->defined_namespace = namespaces_.back();
+      struct_def->defined_namespace = current_namespace_;
     } else {
       // Not a definition.
       // Rather than failing, we create a "pre declared" StructDef, due to
       // circular references, and check for errors at the end of parsing.
-      // It is defined in the root namespace, since we don't know what the
+      // It is defined in the current namespace, as the best guess what the
       // final namespace will be.
-      // TODO: maybe safer to use special namespace?
       structs_.Add(name, struct_def);
       struct_def->name = name;
-      struct_def->defined_namespace = new Namespace();
-      namespaces_.insert(namespaces_.begin(), struct_def->defined_namespace);
+      struct_def->defined_namespace = current_namespace_;
+      struct_def->original_location.reset(new std::string(file_being_parsed_ +
+                                                     ":" + NumToString(line_)));
     }
   }
   return struct_def;
@@ -1234,8 +1399,8 @@
   enum_def.file = file_being_parsed_;
   enum_def.doc_comment = enum_comment;
   enum_def.is_union = is_union;
-  enum_def.defined_namespace = namespaces_.back();
-  if (enums_.Add(namespaces_.back()->GetFullyQualifiedName(enum_name),
+  enum_def.defined_namespace = current_namespace_;
+  if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name),
                  &enum_def))
     return Error("enum already exists: " + enum_name);
   if (is_union) {
@@ -1290,7 +1455,16 @@
         return Error("enum value already exists: " + value_name);
       ev.doc_comment = value_comment;
       if (is_union) {
-        ev.struct_def = LookupCreateStruct(full_name);
+        if (Is(':')) {
+          NEXT();
+          ECHECK(ParseType(ev.union_type));
+          if (ev.union_type.base_type != BASE_TYPE_STRUCT &&
+              ev.union_type.base_type != BASE_TYPE_STRING)
+            return Error("union value type may only be table/struct/string");
+          enum_def.uses_type_aliases = true;
+        } else {
+          ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name));
+        }
       }
       if (Is('=')) {
         NEXT();
@@ -1300,6 +1474,10 @@
             enum_def.vals.vec[prevsize - 1]->value >= ev.value)
           return Error("enum values must be specified in ascending order");
       }
+      if (is_union) {
+        if (ev.value < 0 || ev.value >= 256)
+          return Error("union enum value must fit in a ubyte");
+      }
       if (opts.proto_mode && Is('[')) {
         NEXT();
         // ignore attributes on enums.
@@ -1322,7 +1500,7 @@
     }
   }
   if (dest) *dest = &enum_def;
-  types_.Add(namespaces_.back()->GetFullyQualifiedName(enum_def.name),
+  types_.Add(current_namespace_->GetFullyQualifiedName(enum_def.name),
              new Type(BASE_TYPE_UNION, nullptr, &enum_def));
   return NoError();
 }
@@ -1335,7 +1513,7 @@
   struct_def.file = file_being_parsed_;
   // Move this struct to the back of the vector just in case it was predeclared,
   // to preserve declaration order.
-  *remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
+  *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = &struct_def;
   *dest = &struct_def;
   return NoError();
 }
@@ -1361,6 +1539,22 @@
   return NoError();
 }
 
+bool Parser::SupportsVectorOfUnions() const {
+  return opts.lang_to_generate != 0 && (opts.lang_to_generate &
+    ~(IDLOptions::kCpp | IDLOptions::kJs | IDLOptions::kTs | IDLOptions::kPhp)) == 0;
+}
+
+Namespace *Parser::UniqueNamespace(Namespace *ns) {
+  for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) {
+    if (ns->components == (*it)->components) {
+      delete ns;
+      return *it;
+    }
+  }
+  namespaces_.push_back(ns);
+  return ns;
+}
+
 static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
   auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
   auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
@@ -1369,8 +1563,9 @@
 
 CheckedError Parser::ParseDecl() {
   std::vector<std::string> dc = doc_comment_;
-  bool fixed = Is(kTokenStruct);
-  if (fixed) NEXT() else EXPECT(kTokenTable);
+  bool fixed = IsIdent("struct");
+  if (!fixed && !IsIdent("table")) return Error("declaration expected");
+  NEXT();
   std::string name = attribute_;
   EXPECT(kTokenIdentifier);
   StructDef *struct_def;
@@ -1429,7 +1624,7 @@
   ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
   ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
   EXPECT('}');
-  types_.Add(namespaces_.back()->GetFullyQualifiedName(struct_def->name),
+  types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name),
              new Type(BASE_TYPE_STRUCT, struct_def, nullptr));
   return NoError();
 }
@@ -1443,8 +1638,8 @@
   service_def.name = service_name;
   service_def.file = file_being_parsed_;
   service_def.doc_comment = service_comment;
-  service_def.defined_namespace = namespaces_.back();
-  if (services_.Add(namespaces_.back()->GetFullyQualifiedName(service_name),
+  service_def.defined_namespace = current_namespace_;
+  if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name),
                     &service_def))
     return Error("service already exists: " + service_name);
   ECHECK(ParseMetaData(&service_def.attributes));
@@ -1475,10 +1670,10 @@
 }
 
 bool Parser::SetRootType(const char *name) {
-  root_struct_def_ = structs_.Lookup(name);
+  root_struct_def_ = LookupStruct(name);
   if (!root_struct_def_)
-    root_struct_def_ = structs_.Lookup(
-                         namespaces_.back()->GetFullyQualifiedName(name));
+    root_struct_def_ = LookupStruct(
+                         current_namespace_->GetFullyQualifiedName(name));
   return root_struct_def_ != nullptr;
 }
 
@@ -1492,7 +1687,9 @@
   }
   for (auto it = structs_.vec.begin();
            it != structs_.vec.end(); ++it) {
-    (*it)->generated = true;
+    if (!(*it)->predecl) {
+      (*it)->generated = true;
+    }
   }
   for (auto it = services_.vec.begin();
            it != services_.vec.end(); ++it) {
@@ -1503,7 +1700,7 @@
 CheckedError Parser::ParseNamespace() {
   NEXT();
   auto ns = new Namespace();
-  namespaces_.push_back(ns);
+  namespaces_.push_back(ns);  // Store it here to not leak upon error.
   if (token_ != ';') {
     for (;;) {
       ns->components.push_back(attribute_);
@@ -1511,6 +1708,8 @@
       if (Is('.')) NEXT() else break;
     }
   }
+  namespaces_.pop_back();
+  current_namespace_ = UniqueNamespace(ns);
   EXPECT(';');
   return NoError();
 }
@@ -1524,14 +1723,15 @@
 // We parse everything as identifiers instead of keywords, since we don't
 // want protobuf keywords to become invalid identifiers in FlatBuffers.
 CheckedError Parser::ParseProtoDecl() {
-  bool isextend = attribute_ == "extend";
-  if (attribute_ == "package") {
+  bool isextend = IsIdent("extend");
+  if (IsIdent("package")) {
     // These are identical in syntax to FlatBuffer's namespace decl.
     ECHECK(ParseNamespace());
-  } else if (attribute_ == "message" || isextend) {
+  } else if (IsIdent("message") || isextend) {
     std::vector<std::string> struct_comment = doc_comment_;
     NEXT();
     StructDef *struct_def = nullptr;
+    Namespace *parent_namespace = nullptr;
     if (isextend) {
       if (Is('.')) NEXT();  // qualified names may start with a . ?
       auto id = attribute_;
@@ -1547,22 +1747,20 @@
       // Since message definitions can be nested, we create a new namespace.
       auto ns = new Namespace();
       // Copy of current namespace.
-      *ns = *namespaces_.back();
+      *ns = *current_namespace_;
       // But with current message name.
       ns->components.push_back(name);
-      namespaces_.push_back(ns);
+      ns->from_table++;
+      parent_namespace = current_namespace_;
+      current_namespace_ = UniqueNamespace(ns);
     }
     struct_def->doc_comment = struct_comment;
     ECHECK(ParseProtoFields(struct_def, isextend, false));
     if (!isextend) {
-      // We have to remove the nested namespace, but we can't just throw it
-      // away, so put it at the beginning of the vector.
-      auto ns = namespaces_.back();
-      namespaces_.pop_back();
-      namespaces_.insert(namespaces_.begin(), ns);
+      current_namespace_ = parent_namespace;
     }
     if (Is(';')) NEXT();
-  } else if (attribute_ == "enum") {
+  } else if (IsIdent("enum")) {
     // These are almost the same, just with different terminator:
     EnumDef *enum_def;
     ECHECK(ParseEnum(false, &enum_def));
@@ -1576,15 +1774,15 @@
       if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
       else ++it;
     }
-  } else if (attribute_ == "syntax") {  // Skip these.
+  } else if (IsIdent("syntax")) {  // Skip these.
     NEXT();
     EXPECT('=');
     EXPECT(kTokenStringConstant);
     EXPECT(';');
-  } else if (attribute_ == "option") {  // Skip these.
+  } else if (IsIdent("option")) {  // Skip these.
     ECHECK(ParseProtoOption());
     EXPECT(';');
-  } else if (attribute_ == "service") {  // Skip these.
+  } else if (IsIdent("service")) {  // Skip these.
     NEXT();
     EXPECT(kTokenIdentifier);
     ECHECK(ParseProtoCurliesOrIdent());
@@ -1599,11 +1797,10 @@
                                       bool inside_oneof) {
   EXPECT('{');
   while (token_ != '}') {
-    if (attribute_ == "message" || attribute_ == "extend" ||
-        attribute_ == "enum") {
+    if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) {
       // Nested declarations.
       ECHECK(ParseProtoDecl());
-    } else if (attribute_ == "extensions") {  // Skip these.
+    } else if (IsIdent("extensions")) {  // Skip these.
       NEXT();
       EXPECT(kTokenIntegerConstant);
       if (Is(kTokenIdentifier)) {
@@ -1611,14 +1808,13 @@
         NEXT();  // num
       }
       EXPECT(';');
-    } else if (attribute_ == "option") {  // Skip these.
+    } else if (IsIdent("option")) {  // Skip these.
       ECHECK(ParseProtoOption());
       EXPECT(';');
-    } else if (attribute_ == "reserved") {  // Skip these.
+    } else if (IsIdent("reserved")) {  // Skip these.
       NEXT();
-      EXPECT(kTokenIntegerConstant);
-      while (Is(',')) { NEXT(); EXPECT(kTokenIntegerConstant); }
-      EXPECT(';');
+      while (!Is(';')) { NEXT(); }  // A variety of formats, just skip.
+      NEXT();
     } else {
       std::vector<std::string> field_comment = doc_comment_;
       // Parse the qualifier.
@@ -1626,26 +1822,26 @@
       bool repeated = false;
       bool oneof = false;
       if (!inside_oneof) {
-        if (attribute_ == "optional") {
+        if (IsIdent("optional")) {
           // This is the default.
-          EXPECT(kTokenIdentifier);
-        } else if (attribute_ == "required") {
+          NEXT();
+        } else if (IsIdent("required")) {
           required = true;
-          EXPECT(kTokenIdentifier);
-        } else if (attribute_ == "repeated") {
+          NEXT();
+        } else if (IsIdent("repeated")) {
           repeated = true;
-          EXPECT(kTokenIdentifier);
-        } else if (attribute_ == "oneof") {
+          NEXT();
+        } else if (IsIdent("oneof")) {
           oneof = true;
-          EXPECT(kTokenIdentifier);
+          NEXT();
         } else {
           // can't error, proto3 allows decls without any of the above.
         }
       }
       StructDef *anonymous_struct = nullptr;
       Type type;
-      if (attribute_ == "group" || oneof) {
-        if (!oneof) EXPECT(kTokenIdentifier);
+      if (IsIdent("group") || oneof) {
+        if (!oneof) NEXT();
         auto name = "Anonymous" + NumToString(anonymous_counter++);
         ECHECK(StartStruct(name, &anonymous_struct));
         type = Type(BASE_TYPE_STRUCT, anonymous_struct);
@@ -1656,16 +1852,16 @@
       if (repeated) {
         type.element = type.base_type;
         type.base_type = BASE_TYPE_VECTOR;
+        if (type.element == BASE_TYPE_VECTOR) {
+          // We have a vector or vectors, which FlatBuffers doesn't support.
+          // For now make it a vector of string (since the source is likely
+          // "repeated bytes").
+          // TODO(wvo): A better solution would be to wrap this in a table.
+          type.element = BASE_TYPE_STRING;
+        }
       }
       std::string name = attribute_;
-      // Protos may use our keywords "attribute" & "namespace" as an identifier.
-      if (Is(kTokenAttribute) || Is(kTokenNameSpace)) {
-        NEXT();
-        // TODO: simpler to just not make these keywords?
-        name += "_";  // Have to make it not a keyword.
-      } else {
-        EXPECT(kTokenIdentifier);
-      }
+      EXPECT(kTokenIdentifier);
       if (!oneof) {
         // Parse the field id. Since we're just translating schemas, not
         // any kind of binary compatibility, we can safely ignore these, and
@@ -1753,22 +1949,29 @@
 
 // Parse a protobuf type, and map it to the corresponding FlatBuffer one.
 CheckedError Parser::ParseTypeFromProtoType(Type *type) {
-  struct type_lookup { const char *proto_type; BaseType fb_type; };
+  struct type_lookup { const char *proto_type; BaseType fb_type, element; };
   static type_lookup lookup[] = {
-    { "float", BASE_TYPE_FLOAT },  { "double", BASE_TYPE_DOUBLE },
-    { "int32", BASE_TYPE_INT },    { "int64", BASE_TYPE_LONG },
-    { "uint32", BASE_TYPE_UINT },  { "uint64", BASE_TYPE_ULONG },
-    { "sint32", BASE_TYPE_INT },   { "sint64", BASE_TYPE_LONG },
-    { "fixed32", BASE_TYPE_UINT }, { "fixed64", BASE_TYPE_ULONG },
-    { "sfixed32", BASE_TYPE_INT }, { "sfixed64", BASE_TYPE_LONG },
-    { "bool", BASE_TYPE_BOOL },
-    { "string", BASE_TYPE_STRING },
-    { "bytes", BASE_TYPE_STRING },
-    { nullptr, BASE_TYPE_NONE }
+    { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE },
+    { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE },
+    { "int32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+    { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+    { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE },
+    { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE },
+    { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE },
+    { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE },
+    { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE },
+    { "string", BASE_TYPE_STRING, BASE_TYPE_NONE },
+    { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR },
+    { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE }
   };
   for (auto tl = lookup; tl->proto_type; tl++) {
     if (attribute_ == tl->proto_type) {
       type->base_type = tl->fb_type;
+      type->element = tl->element;
       NEXT();
       return NoError();
     }
@@ -1780,100 +1983,232 @@
 
 CheckedError Parser::SkipAnyJsonValue() {
   switch (token_) {
-    case '{':
-      ECHECK(SkipJsonObject());
-      break;
+    case '{': {
+      size_t fieldn_outer = 0;
+      return ParseTableDelimiters(fieldn_outer, nullptr,
+                                  [](const std::string &,
+                                     size_t &fieldn, const StructDef *,
+                                     void *state) -> CheckedError {
+            auto *parser = static_cast<Parser *>(state);
+            ECHECK(parser->SkipAnyJsonValue());
+            fieldn++;
+            return NoError();
+          },
+          this);
+    }
+    case '[': {
+      size_t count = 0;
+      return ParseVectorDelimiters(count, [](size_t &,
+                                             void *state) -> CheckedError {
+          return static_cast<Parser *>(state)->SkipAnyJsonValue();
+        },
+        this);
+    }
     case kTokenStringConstant:
-      ECHECK(SkipJsonString());
+    case kTokenIntegerConstant:
+    case kTokenFloatConstant:
+      NEXT();
       break;
-    case '[':
-      ECHECK(SkipJsonArray());
+    default:
+      if (IsIdent("true") || IsIdent("false") || IsIdent("null")) { NEXT(); }
+      else return TokenError();
+  }
+  return NoError();
+}
+
+CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) {
+  switch (token_) {
+    case '{': {
+      std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
+          this, builder);
+      auto start = builder->StartMap();
+      size_t fieldn_outer = 0;
+      auto err = ParseTableDelimiters(fieldn_outer, nullptr,
+                                      [](const std::string &name,
+                                         size_t &fieldn, const StructDef *,
+                                         void *state) -> CheckedError {
+            auto *parser_and_builder =
+                static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
+                    state);
+            auto *parser = parser_and_builder->first;
+            auto *current_builder = parser_and_builder->second;
+            current_builder->Key(name);
+            ECHECK(parser->ParseFlexBufferValue(current_builder));
+            fieldn++;
+            return NoError();
+          },
+          &parser_and_builder_state);
+      ECHECK(err);
+      builder->EndMap(start);
+      break;
+    }
+    case '[':{
+      auto start = builder->StartVector();
+      size_t count = 0;
+      std::pair<Parser *, flexbuffers::Builder *> parser_and_builder_state(
+          this, builder);
+      ECHECK(ParseVectorDelimiters(count, [](size_t &,
+                                             void *state) -> CheckedError {
+            auto *parser_and_builder =
+                static_cast<std::pair<Parser *, flexbuffers::Builder *> *>(
+                    state);
+            return parser_and_builder->first->ParseFlexBufferValue(
+                parser_and_builder->second);
+          },
+          &parser_and_builder_state));
+      builder->EndVector(start, false, false);
+      break;
+    }
+    case kTokenStringConstant:
+      builder->String(attribute_);
+      EXPECT(kTokenStringConstant);
       break;
     case kTokenIntegerConstant:
+      builder->Int(StringToInt(attribute_.c_str()));
       EXPECT(kTokenIntegerConstant);
       break;
     case kTokenFloatConstant:
+      builder->Double(strtod(attribute_.c_str(), nullptr));
       EXPECT(kTokenFloatConstant);
       break;
     default:
-      return Error(std::string("Unexpected token:") + std::string(1, static_cast<char>(token_)));
+      if (IsIdent("true")) { builder->Bool(true); NEXT(); }
+      else if (IsIdent("false")) { builder->Bool(false); NEXT(); }
+      else if (IsIdent("null")) { builder->Null(); NEXT(); }
+      else return TokenError();
   }
   return NoError();
 }
 
-CheckedError Parser::SkipJsonObject() {
-  EXPECT('{');
-  size_t fieldn = 0;
-
-  for (;;) {
-    if ((!opts.strict_json || !fieldn) && Is('}')) break;
-
-    if (!Is(kTokenStringConstant)) {
-      EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier);
-    }
-    else {
-      NEXT();
-    }
-
-    EXPECT(':');
-    ECHECK(SkipAnyJsonValue());
-    fieldn++;
-
-    if (Is('}')) break;
-    EXPECT(',');
-  }
-
-  NEXT();
-  return NoError();
-}
-
-CheckedError Parser::SkipJsonArray() {
-  EXPECT('[');
-
-  for (;;) {
-    if (Is(']')) break;
-
-    ECHECK(SkipAnyJsonValue());
-
-    if (Is(']')) break;
-    EXPECT(',');
-  }
-
-  NEXT();
-  return NoError();
-}
-
-CheckedError Parser::SkipJsonString() {
-  EXPECT(kTokenStringConstant);
-  return NoError();
+bool Parser::ParseFlexBuffer(const char *source, const char *source_filename,
+                             flexbuffers::Builder *builder) {
+  auto ok = !StartParseFile(source, source_filename).Check() &&
+            !ParseFlexBufferValue(builder).Check();
+  if (ok) builder->Finish();
+  return ok;
 }
 
 bool Parser::Parse(const char *source, const char **include_paths,
                    const char *source_filename) {
-  return !DoParse(source, include_paths, source_filename).Check();
+  return !ParseRoot(source, include_paths, source_filename).Check();
 }
 
-CheckedError Parser::DoParse(const char *source, const char **include_paths,
-                             const char *source_filename) {
+CheckedError Parser::StartParseFile(const char *source, const char *source_filename) {
   file_being_parsed_ = source_filename ? source_filename : "";
+  source_ = cursor_ = source;
+  line_ = 1;
+  error_.clear();
+  ECHECK(SkipByteOrderMark());
+  NEXT();
+  if (Is(kTokenEof))
+      return Error("input file is empty");
+  return NoError();
+}
+
+CheckedError Parser::ParseRoot(const char *source, const char **include_paths,
+                             const char *source_filename) {
+  ECHECK(DoParse(source, include_paths, source_filename, nullptr));
+
+  // Check that all types were defined.
+  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ) {
+    auto &struct_def = **it;
+    if (struct_def.predecl) {
+      if (opts.proto_mode) {
+        // Protos allow enums to be used before declaration, so check if that
+        // is the case here.
+        EnumDef *enum_def = nullptr;
+        for (size_t components = struct_def.defined_namespace->
+                                   components.size() + 1;
+             components && !enum_def; components--) {
+          auto qualified_name = struct_def.defined_namespace->
+                                  GetFullyQualifiedName(struct_def.name,
+                                                        components - 1);
+          enum_def = LookupEnum(qualified_name);
+        }
+        if (enum_def) {
+          // This is pretty slow, but a simple solution for now.
+          auto initial_count = struct_def.refcount;
+          for (auto struct_it = structs_.vec.begin();
+                    struct_it != structs_.vec.end();
+                    ++struct_it) {
+            auto &sd = **struct_it;
+            for (auto field_it = sd.fields.vec.begin();
+                      field_it != sd.fields.vec.end();
+                      ++field_it) {
+              auto &field = **field_it;
+              if (field.value.type.struct_def == &struct_def) {
+                field.value.type.struct_def = nullptr;
+                field.value.type.enum_def = enum_def;
+                auto &bt = field.value.type.base_type == BASE_TYPE_VECTOR
+                           ? field.value.type.element
+                           : field.value.type.base_type;
+                assert(bt == BASE_TYPE_STRUCT);
+                bt = enum_def->underlying_type.base_type;
+                struct_def.refcount--;
+                enum_def->refcount++;
+              }
+            }
+          }
+          if (struct_def.refcount)
+            return Error("internal: " + NumToString(struct_def.refcount) + "/" +
+                         NumToString(initial_count) +
+                         " use(s) of pre-declaration enum not accounted for: "
+                         + enum_def->name);
+          structs_.dict.erase(structs_.dict.find(struct_def.name));
+          it = structs_.vec.erase(it);
+          delete &struct_def;
+          continue;  // Skip error.
+        }
+      }
+      auto err = "type referenced but not defined (check namespace): " +
+                 struct_def.name;
+      if (struct_def.original_location)
+        err += ", originally at: " + *struct_def.original_location;
+      return Error(err);
+    }
+    ++it;
+  }
+
+  // This check has to happen here and not earlier, because only now do we
+  // know for sure what the type of these are.
+  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
+    auto &enum_def = **it;
+    if (enum_def.is_union) {
+      for (auto val_it = enum_def.vals.vec.begin();
+           val_it != enum_def.vals.vec.end();
+           ++val_it) {
+        auto &val = **val_it;
+        if (!SupportsVectorOfUnions() &&
+            val.union_type.struct_def && val.union_type.struct_def->fixed)
+          return Error(
+                "only tables can be union elements in the generated language: "
+                + val.name);
+      }
+    }
+  }
+  return NoError();
+}
+
+CheckedError Parser::DoParse(const char *source,
+                                    const char **include_paths,
+                                    const char *source_filename,
+                                    const char *include_filename) {
   if (source_filename &&
       included_files_.find(source_filename) == included_files_.end()) {
-    included_files_[source_filename] = true;
+    included_files_[source_filename] = include_filename ? include_filename : "";
     files_included_per_file_[source_filename] = std::set<std::string>();
   }
   if (!include_paths) {
     static const char *current_directory[] = { "", nullptr };
     include_paths = current_directory;
   }
-  source_ = cursor_ = source;
-  line_ = 1;
-  error_.clear();
   field_stack_.clear();
   builder_.Clear();
   // Start with a blank namespace just in case this file doesn't have one.
-  namespaces_.push_back(new Namespace());
-  ECHECK(SkipByteOrderMark());
-  NEXT();
+  current_namespace_ = empty_namespace_;
+
+  ECHECK(StartParseFile(source, source_filename));
+
   // Includes must come before type declarations:
   for (;;) {
     // Parse pre-include proto statements if any:
@@ -1881,17 +2216,14 @@
         (attribute_ == "option" || attribute_ == "syntax" ||
          attribute_ == "package")) {
         ECHECK(ParseProtoDecl());
-    } else if (Is(kTokenNativeInclude)) {
+    } else if (IsIdent("native_include")) {
       NEXT();
-      native_included_files_.emplace_back(attribute_);
+      vector_emplace_back(&native_included_files_, attribute_);
       EXPECT(kTokenStringConstant);
-    } else if (Is(kTokenInclude) ||
-               (opts.proto_mode &&
-                attribute_ == "import" &&
-                Is(kTokenIdentifier))) {
+    } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) {
       NEXT();
       if (opts.proto_mode && attribute_ == "public") NEXT();
-      auto name = attribute_;
+      auto name = flatbuffers::PosixPath(attribute_.c_str());
       EXPECT(kTokenStringConstant);
       // Look for the file in include_paths.
       std::string filepath;
@@ -1909,9 +2241,15 @@
         std::string contents;
         if (!LoadFile(filepath.c_str(), true, &contents))
           return Error("unable to load include file: " + name);
-        ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str()));
+        ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(),
+                       name.c_str()));
         // We generally do not want to output code for any included files:
         if (!opts.generate_all) MarkGenerated();
+        // Reset these just in case the included file had them, and the
+        // parent doesn't.
+        root_struct_def_ = nullptr;
+        file_identifier_.clear();
+        file_extension_.clear();
         // This is the easiest way to continue this file after an include:
         // instead of saving and restoring all the state, we simply start the
         // file anew. This will cause it to encounter the same include
@@ -1919,7 +2257,7 @@
         // entered into included_files_.
         // This is recursive, but only go as deep as the number of include
         // statements.
-        return DoParse(source, include_paths, source_filename);
+        return DoParse(source, include_paths, source_filename, include_filename);
       }
       EXPECT(';');
     } else {
@@ -1930,7 +2268,7 @@
   while (token_ != kTokenEof) {
     if (opts.proto_mode) {
       ECHECK(ParseProtoDecl());
-    } else if (token_ == kTokenNameSpace) {
+    } else if (IsIdent("namespace")) {
       ECHECK(ParseNamespace());
     } else if (token_ == '{') {
       if (!root_struct_def_)
@@ -1942,11 +2280,11 @@
       ECHECK(ParseTable(*root_struct_def_, nullptr, &toff));
       builder_.Finish(Offset<Table>(toff),
                 file_identifier_.length() ? file_identifier_.c_str() : nullptr);
-    } else if (token_ == kTokenEnum) {
+    } else if (IsIdent("enum")) {
       ECHECK(ParseEnum(false, nullptr));
-    } else if (token_ == kTokenUnion) {
+    } else if (IsIdent("union")) {
       ECHECK(ParseEnum(true, nullptr));
-    } else if (token_ == kTokenRootType) {
+    } else if (IsIdent("root_type")) {
       NEXT();
       auto root_type = attribute_;
       EXPECT(kTokenIdentifier);
@@ -1956,7 +2294,7 @@
       if (root_struct_def_->fixed)
         return Error("root type must be a table");
       EXPECT(';');
-    } else if (token_ == kTokenFileIdentifier) {
+    } else if (IsIdent("file_identifier")) {
       NEXT();
       file_identifier_ = attribute_;
       EXPECT(kTokenStringConstant);
@@ -1966,42 +2304,25 @@
               NumToString(FlatBufferBuilder::kFileIdentifierLength) +
               " characters");
       EXPECT(';');
-    } else if (token_ == kTokenFileExtension) {
+    } else if (IsIdent("file_extension")) {
       NEXT();
       file_extension_ = attribute_;
       EXPECT(kTokenStringConstant);
       EXPECT(';');
-    } else if(token_ == kTokenInclude) {
+    } else if(IsIdent("include")) {
       return Error("includes must come before declarations");
-    } else if(token_ == kTokenAttribute) {
+    } else if(IsIdent("attribute")) {
       NEXT();
       auto name = attribute_;
       EXPECT(kTokenStringConstant);
       EXPECT(';');
       known_attributes_[name] = false;
-    } else if (token_ == kTokenService) {
+    } else if (IsIdent("rpc_service")) {
       ECHECK(ParseService());
     } else {
       ECHECK(ParseDecl());
     }
   }
-  for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) {
-    if ((*it)->predecl) {
-      return Error("type referenced but not defined: " + (*it)->name);
-    }
-  }
-  for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) {
-    auto &enum_def = **it;
-    if (enum_def.is_union) {
-      for (auto val_it = enum_def.vals.vec.begin();
-           val_it != enum_def.vals.vec.end();
-           ++val_it) {
-        auto &val = **val_it;
-        if (val.struct_def && val.struct_def->fixed)
-          return Error("only tables can be union elements: " + val.name);
-      }
-    }
-  }
   return NoError();
 }
 
@@ -2018,7 +2339,10 @@
     to_process.pop_front();
     included_files.insert(current);
 
-    auto new_files = files_included_per_file_.at(current);
+    // Workaround the lack of const accessor in C++98 maps.
+    auto &new_files =
+        (*const_cast<std::map<std::string, std::set<std::string>> *>(
+            &files_included_per_file_))[current];
     for (auto it = new_files.begin(); it != new_files.end(); ++it) {
       if (included_files.find(*it) == included_files.end())
         to_process.push_back(*it);
@@ -2141,9 +2465,11 @@
   return reflection::CreateEnumVal(*builder,
                                    builder->CreateString(name),
                                    value,
-                                   struct_def
-                                     ? struct_def->serialized_location
-                                     : 0);
+                                   union_type.struct_def
+                                     ? union_type.struct_def->
+                                         serialized_location
+                                     : 0,
+                                   union_type.Serialize(builder));
 }
 
 Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const {
@@ -2181,7 +2507,7 @@
     auto &struct_def = **sit;
     auto qualified_name =
         struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name);
-    auto struct_def_base = base.structs_.Lookup(qualified_name);
+    auto struct_def_base = base.LookupStruct(qualified_name);
     if (!struct_def_base) continue;
     for (auto fit = struct_def.fields.vec.begin();
              fit != struct_def.fields.vec.end(); ++fit) {
diff --git a/src/reflection.cpp b/src/reflection.cpp
index cb30c7f..6736ec7 100644
--- a/src/reflection.cpp
+++ b/src/reflection.cpp
@@ -87,8 +87,11 @@
             auto &fielddef = **it;
             if (!table_field->CheckField(fielddef.offset())) continue;
             auto val = GetAnyFieldS(*table_field, fielddef, schema);
-            if (fielddef.type()->base_type() == reflection::String)
-              val = "\"" + val + "\"";  // Doesn't deal with escape codes etc.
+            if (fielddef.type()->base_type() == reflection::String) {
+              std::string esc;
+              flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true);
+              val = esc;
+            }
             s += fielddef.name()->str();
             s += ": ";
             s += val;
@@ -162,15 +165,15 @@
   ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta,
                 std::vector<uint8_t> *flatbuf,
                 const reflection::Object *root_table = nullptr)
-     : schema_(schema), startptr_(flatbuf->data() + start),
+     : schema_(schema), startptr_(vector_data(*flatbuf) + start),
        delta_(delta), buf_(*flatbuf),
        dag_check_(flatbuf->size() / sizeof(uoffset_t), false) {
     auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1);
     delta_ = (delta_ + mask) & ~mask;
     if (!delta_) return;  // We can't shrink by less than largest_scalar_t.
     // Now change all the offsets by delta_.
-    auto root = GetAnyRoot(buf_.data());
-    Straddle<uoffset_t, 1>(buf_.data(), root, buf_.data());
+    auto root = GetAnyRoot(vector_data(buf_));
+    Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_));
     ResizeTable(root_table ? *root_table : *schema.root_table(), root);
     // We can now add or remove bytes at start.
     if (delta_ > 0) buf_.insert(buf_.begin() + start, delta_, 0);
@@ -197,7 +200,7 @@
   // will straddle and which won't.
   uint8_t &DagCheck(const void *offsetloc) {
     auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) -
-                   reinterpret_cast<const uoffset_t *>(buf_.data());
+                   reinterpret_cast<const uoffset_t *>(vector_data(buf_));
     return dag_check_[dag_idx];
   }
 
@@ -293,19 +296,19 @@
                       const reflection::Object *root_table) {
   auto delta = static_cast<int>(val.size()) - static_cast<int>(str->Length());
   auto str_start = static_cast<uoffset_t>(
-                     reinterpret_cast<const uint8_t *>(str) - flatbuf->data());
+      reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf));
   auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t));
   if (delta) {
     // Clear the old string, since we don't want parts of it remaining.
-    memset(flatbuf->data() + start, 0, str->Length());
+    memset(vector_data(*flatbuf) + start, 0, str->Length());
     // Different size, we must expand (or contract).
     ResizeContext(schema, start, delta, flatbuf, root_table);
     // Set the new length.
-    WriteScalar(flatbuf->data() + str_start,
+    WriteScalar(vector_data(*flatbuf) + str_start,
                 static_cast<uoffset_t>(val.size()));
   }
   // Copy new data. Safe because we created the right amount of space.
-  memcpy(flatbuf->data() + start, val.c_str(), val.size() + 1);
+  memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1);
 }
 
 uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize,
@@ -314,7 +317,8 @@
                          const reflection::Object *root_table) {
   auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems);
   auto delta_bytes = delta_elem * static_cast<int>(elem_size);
-  auto vec_start = reinterpret_cast<const uint8_t *>(vec) - flatbuf->data();
+  auto vec_start = reinterpret_cast<const uint8_t *>(vec) -
+      vector_data(*flatbuf);
   auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) +
                                       elem_size * num_elems);
   if (delta_bytes) {
@@ -322,16 +326,16 @@
       // Clear elements we're throwing away, since some might remain in the
       // buffer.
       auto size_clear = -delta_elem * elem_size;
-      memset(flatbuf->data() + start - size_clear, 0, size_clear);
+      memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear);
     }
     ResizeContext(schema, start, delta_bytes, flatbuf, root_table);
-    WriteScalar(flatbuf->data() + vec_start, newsize);  // Length field.
+    WriteScalar(vector_data(*flatbuf) + vec_start, newsize);  // Length field.
     // Set new elements to 0.. this can be overwritten by the caller.
     if (delta_elem > 0) {
-      memset(flatbuf->data() + start, 0, delta_elem * elem_size);
+      memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size);
     }
   }
-  return flatbuf->data() + start;
+  return vector_data(*flatbuf) + start;
 }
 
 const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf,
@@ -346,7 +350,7 @@
   // Insert the entire FlatBuffer minus the root pointer.
   flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen);
   auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t);
-  return flatbuf.data() + insertion_point + root_offset;
+  return vector_data(flatbuf) + insertion_point + root_offset;
 }
 
 void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef,
@@ -420,8 +424,8 @@
               offset = fbb.CreateVector(elements).o;
               break;
             }
-            // FALL-THRU:
           }
+          // FALL-THRU
           default: {  // Scalars and structs.
             auto element_size = GetTypeSize(element_base_type);
             if (elemobjectdef && elemobjectdef->is_struct())
@@ -458,8 +462,8 @@
                      subobjectdef.bytesize());
           break;
         }
-        // else: FALL-THRU:
       }
+      // ELSE FALL-THRU
       case reflection::Union:
       case reflection::String:
       case reflection::Vector:
@@ -477,7 +481,7 @@
     fbb.ClearOffsets();
     return fbb.EndStruct();
   } else {
-    return fbb.EndTable(start, static_cast<voffset_t>(fielddefs->size()));
+    return fbb.EndTable(start);
   }
 }
 
@@ -696,6 +700,9 @@
     }
   }
 
+  if (!v.EndTable())
+    return false;
+  
   return true;
 }
 
diff --git a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
index 6e76b07..0afe6b1 100644
--- a/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
+++ b/tests/FlatBuffers.Test/FlatBuffers.Test.csproj
@@ -80,6 +80,12 @@
     <Compile Include="..\MyGame\Example\Vec3.cs">
       <Link>MyGame\Example\Vec3.cs</Link>
     </Compile>
+    <Compile Include="..\MyGame\Example\Ability.cs">
+      <Link>MyGame\Example\Ability.cs</Link>
+    </Compile>
+    <Compile Include="..\MyGame\InParentNamespace.cs">
+      <Link>MyGame\InParentNamespace.cs</Link>
+    </Compile>
     <Compile Include="..\namespace_test\NamespaceA\NamespaceB\EnumInNestedNS.cs">
       <Link>NamespaceA\NamespaceB\EnumInNestedNS.cs</Link>
     </Compile>
@@ -119,4 +125,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>
\ No newline at end of file
diff --git a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
index d032d7e..ccd5b05 100644
--- a/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
+++ b/tests/FlatBuffers.Test/FlatBuffersExampleTests.cs
@@ -50,7 +50,7 @@
             Monster.StartMonster(fbb);
             Monster.AddName(fbb, names[2]);
             off[2] = Monster.EndMonster(fbb);
-            var sortMons = Monster.CreateMySortedVectorOfTables(fbb, off);
+            var sortMons = Monster.CreateSortedVectorOfMonster(fbb, off);
 
             // We set up the same values as monsterdata.json:
 
@@ -123,9 +123,9 @@
             Assert.AreEqual(monster.Testarrayoftables(2).Value.Name, "Wilma");
 
             // Example of searching for a table by the key
-            Assert.IsTrue(Monster.LookupByKey(sortMons, "Frodo", fbb.DataBuffer) != null);
-            Assert.IsTrue(Monster.LookupByKey(sortMons, "Barney", fbb.DataBuffer) != null);
-            Assert.IsTrue(Monster.LookupByKey(sortMons, "Wilma", fbb.DataBuffer)!= null);
+            Assert.IsTrue(monster.TestarrayoftablesByKey("Frodo") != null);
+            Assert.IsTrue(monster.TestarrayoftablesByKey("Barney") != null);
+            Assert.IsTrue(monster.TestarrayoftablesByKey("Wilma") != null);
 
             // testType is an existing field and mutating it should succeed
             Assert.AreEqual(monster.TestType, Any.Monster);
diff --git a/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
index e8182d7..d933246 100644
--- a/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
+++ b/tests/FlatBuffers.Test/FlatBuffersFuzzTests.cs
@@ -205,11 +205,11 @@
             builder.EndObject();
             Assert.ArrayEqual(new byte[]
             {
-                0, 0, 0, 0, 0, 0, // padding to 16 bytes
-                6, 0, // vtable bytes
+                // No padding.
+                4, 0, // vtable bytes
                 4, 0, // end of object from here
-                0, 0, // entry 0 is empty (default value)
-                6, 0, 0, 0, // int32 offset for start of vtable
+                // entry 0 is not stored (trimmed end of vtable)
+                4, 0, 0, 0, // int32 offset for start of vtable
             },
                 builder.DataBuffer.Data);
         }
diff --git a/tests/FlatBuffers.Test/NetTest.sh b/tests/FlatBuffers.Test/NetTest.sh
new file mode 100644
index 0000000..ea16e47
--- /dev/null
+++ b/tests/FlatBuffers.Test/NetTest.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+# Testing C# on Linux using Mono.
+
+mcs -out:fbnettest.exe ../../net/FlatBuffers/*.cs ../MyGame/Example/*.cs FlatBuffersTestClassAttribute.cs FlatBuffersTestMethodAttribute.cs Assert.cs FlatBuffersExampleTests.cs Program.cs ByteBufferTests.cs FlatBufferBuilderTests.cs FlatBuffersFuzzTests.cs FuzzTestData.cs Lcg.cs TestTable.cs
+./fbnettest.exe
+rm fbnettest.exe
+rm Resources/monsterdata_cstest.mon
+
diff --git a/tests/GoTest.sh b/tests/GoTest.sh
index 7be4aff..88e7a3f 100755
--- a/tests/GoTest.sh
+++ b/tests/GoTest.sh
@@ -20,7 +20,7 @@
 go_src=${go_path}/src
 
 # Emit Go code for the example schema in the test dir:
-../flatc -g monster_test.fbs
+../flatc -g -I include_test monster_test.fbs
 
 # Go requires a particular layout of files in order to link multiple packages.
 # Copy flatbuffer Go files to their own package directories to compile the
@@ -30,6 +30,9 @@
 mkdir -p ${go_src}/flatbuffers_test
 
 cp -a MyGame/Example/*.go ./go_gen/src/MyGame/Example/
+# do not compile the gRPC generated files, which are not tested by go_test.go
+# below, but have their own test.
+rm ./go_gen/src/MyGame/Example/*_grpc.go
 cp -a ../go/* ./go_gen/src/github.com/google/flatbuffers/go
 cp -a ./go_test.go ./go_gen/src/flatbuffers_test/
 
diff --git a/tests/JavaScriptTest.js b/tests/JavaScriptTest.js
index c97ed2d..7ed313a 100644
--- a/tests/JavaScriptTest.js
+++ b/tests/JavaScriptTest.js
@@ -3,7 +3,7 @@
 var fs = require('fs');
 
 var flatbuffers = require('../js/flatbuffers').flatbuffers;
-var MyGame = require('./monster_test_generated').MyGame;
+var MyGame = require(process.argv[2]).MyGame;
 
 function main() {
 
@@ -67,7 +67,7 @@
   // Tests mutation first.  This will verify that we did not trample any other
   // part of the byte buffer.
   testMutation(fbb.dataBuffer());
-  
+
   testBuffer(fbb.dataBuffer());
 
   test64bit();
@@ -156,7 +156,8 @@
   var mon2 = MyGame.Example.Monster.endMonster(fbb);
 
   MyGame.Example.Stat.startStat(fbb);
-  MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x12345678, 0x23456789));
+  // 2541551405100253985 = 0x87654321(low part) + 0x23456789 * 0x100000000(high part);
+  MyGame.Example.Stat.addVal(fbb, new flatbuffers.Long(0x87654321, 0x23456789));    // the low part is Uint32
   var stat = MyGame.Example.Stat.endStat(fbb);
 
   MyGame.Example.Monster.startMonster(fbb);
@@ -177,8 +178,7 @@
   var stat = mon.testempty();
   assert.strictEqual(stat != null, true);
   assert.strictEqual(stat.val() != null, true);
-  assert.strictEqual(stat.val().low, 0x12345678);
-  assert.strictEqual(stat.val().high, 0x23456789);
+  assert.strictEqual(stat.val().toFloat64(), 2541551405100253985);
 
   var mon2 = mon.enemy();
   assert.strictEqual(mon2 != null, true);
diff --git a/tests/JavaScriptTest.sh b/tests/JavaScriptTest.sh
index 75db007..c0286a0 100755
--- a/tests/JavaScriptTest.sh
+++ b/tests/JavaScriptTest.sh
@@ -15,5 +15,5 @@
 # limitations under the License.
 
 pushd "$(dirname $0)" >/dev/null
-../flatc -b monster_test.fbs unicode_test.json
-node JavaScriptTest
+../flatc -b -I include_test monster_test.fbs unicode_test.json
+node JavaScriptTest ./monster_test_generated
diff --git a/tests/JavaScriptUnionVectorTest.js b/tests/JavaScriptUnionVectorTest.js
new file mode 100644
index 0000000..d79669f
--- /dev/null
+++ b/tests/JavaScriptUnionVectorTest.js
@@ -0,0 +1,57 @@
+var assert = require('assert');
+
+var flatbuffers = require('../js/flatbuffers').flatbuffers;
+var Test = require(process.argv[2]);
+
+function main() {
+  var fbb = new flatbuffers.Builder();
+
+  var charTypes = [
+    Test.Character.Belle,
+    Test.Character.MuLan,
+    Test.Character.BookFan,
+  ];
+
+  Test.Attacker.startAttacker(fbb);
+  Test.Attacker.addSwordAttackDamage(fbb, 5);
+  var attackerOffset = Test.Attacker.endAttacker(fbb);
+
+  var charTypesOffset = Test.Movie.createCharactersTypeVector(fbb, charTypes);
+  var charsOffset = Test.Movie.createCharactersVector(
+    fbb,
+    [
+      Test.BookReader.createBookReader(fbb, 7),
+      attackerOffset,
+      Test.BookReader.createBookReader(fbb, 2),
+    ]
+  );
+
+  Test.Movie.startMovie(fbb);
+  Test.Movie.addCharactersType(fbb, charTypesOffset);
+  Test.Movie.addCharacters(fbb, charsOffset);
+  Test.Movie.finishMovieBuffer(fbb, Test.Movie.endMovie(fbb));
+
+  var buf = new flatbuffers.ByteBuffer(fbb.asUint8Array());
+
+  var movie = Test.Movie.getRootAsMovie(buf);
+
+  assert.strictEqual(movie.charactersTypeLength(), charTypes.length);
+  assert.strictEqual(movie.charactersLength(), movie.charactersTypeLength());
+
+  for (var i = 0; i < charTypes.length; ++i) {
+    assert.strictEqual(movie.charactersType(i), charTypes[i]);
+  }
+
+  var bookReader7 = movie.characters(0, new Test.BookReader());
+  assert.strictEqual(bookReader7.booksRead(), 7);
+
+  var attacker = movie.characters(1, new Test.Attacker());
+  assert.strictEqual(attacker.swordAttackDamage(), 5);
+
+  var bookReader2 = movie.characters(2, new Test.BookReader());
+  assert.strictEqual(bookReader2.booksRead(), 2);
+
+  console.log('FlatBuffers union vector test: completed successfully');
+}
+
+main();
diff --git a/tests/JavaTest.bat b/tests/JavaTest.bat
old mode 100755
new mode 100644
diff --git a/tests/JavaTest.java b/tests/JavaTest.java
old mode 100755
new mode 100644
index d53e973..9a5b676
--- a/tests/JavaTest.java
+++ b/tests/JavaTest.java
@@ -16,6 +16,8 @@
 
 import java.io.*;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
 import MyGame.Example.*;
 import NamespaceA.*;
 import NamespaceA.NamespaceB.*;
@@ -51,133 +53,7 @@
         // better for performance.
         FlatBufferBuilder fbb = new FlatBufferBuilder(1);
 
-        int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
-        int[] off = new int[3];
-        Monster.startMonster(fbb);
-        Monster.addName(fbb, names[0]);
-        off[0] = Monster.endMonster(fbb);
-        Monster.startMonster(fbb);
-        Monster.addName(fbb, names[1]);
-        off[1] = Monster.endMonster(fbb);
-        Monster.startMonster(fbb);
-        Monster.addName(fbb, names[2]);
-        off[2] = Monster.endMonster(fbb);
-        int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
-		
-        // We set up the same values as monsterdata.json:
-
-        int str = fbb.createString("MyMonster");
-
-        int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
-
-        int fred = fbb.createString("Fred");
-        Monster.startMonster(fbb);
-        Monster.addName(fbb, fred);
-        int mon2 = Monster.endMonster(fbb);
-
-        Monster.startTest4Vector(fbb, 2);
-        Test.createTest(fbb, (short)10, (byte)20);
-        Test.createTest(fbb, (short)30, (byte)40);
-        int test4 = fbb.endVector();
-
-        int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
-            fbb.createString("test1"),
-            fbb.createString("test2")
-        });
-
-        Monster.startMonster(fbb);
-        Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
-                                                 Color.Green, (short)5, (byte)6));
-        Monster.addHp(fbb, (short)80);
-        Monster.addName(fbb, str);
-        Monster.addInventory(fbb, inv);
-        Monster.addTestType(fbb, (byte)Any.Monster);
-        Monster.addTest(fbb, mon2);
-        Monster.addTest4(fbb, test4);
-        Monster.addTestarrayofstring(fbb, testArrayOfString);
-        Monster.addTestbool(fbb, false);
-        Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
-        Monster.addTestarrayoftables(fbb, sortMons);
-        int mon = Monster.endMonster(fbb);
-
-        Monster.finishMonsterBuffer(fbb, mon);
-
-        // Write the result to a file for debugging purposes:
-        // Note that the binaries are not necessarily identical, since the JSON
-        // parser may serialize in a slightly different order than the above
-        // Java code. They are functionally equivalent though.
-
-        try {
-            DataOutputStream os = new DataOutputStream(new FileOutputStream(
-                                           "monsterdata_java_wire.mon"));
-            os.write(fbb.dataBuffer().array(), fbb.dataBuffer().position(), fbb.offset());
-            os.close();
-        } catch(java.io.IOException e) {
-            System.out.println("FlatBuffers test: couldn't write file");
-            return;
-        }
-
-        // Test it:
-        TestExtendedBuffer(fbb.dataBuffer());
-
-        // Make sure it also works with read only ByteBuffers. This is slower,
-        // since creating strings incurs an additional copy
-        // (see Table.__string).
-        TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
-
-        TestEnums();
-
-        //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
-        // revert to original values after testing
-        Monster monster = Monster.getRootAsMonster(fbb.dataBuffer());
-
-        // mana is optional and does not exist in the buffer so the mutation should fail
-        // the mana field should retain its default value
-        TestEq(monster.mutateMana((short)10), false);
-        TestEq(monster.mana(), (short)150);
-		
-		// Accessing a vector of sorted by the key tables
-        TestEq(monster.testarrayoftables(0).name(), "Barney");
-        TestEq(monster.testarrayoftables(1).name(), "Frodo");
-        TestEq(monster.testarrayoftables(2).name(), "Wilma");
-		
-		// Example of searching for a table by the key
-        TestEq(Monster.lookupByKey(sortMons, "Frodo", fbb.dataBuffer()).name(), "Frodo");
-        TestEq(Monster.lookupByKey(sortMons, "Barney", fbb.dataBuffer()).name(), "Barney");
-        TestEq(Monster.lookupByKey(sortMons, "Wilma", fbb.dataBuffer()).name(), "Wilma");
-
-        // testType is an existing field and mutating it should succeed
-        TestEq(monster.testType(), (byte)Any.Monster);
-        TestEq(monster.mutateTestType(Any.NONE), true);
-        TestEq(monster.testType(), (byte)Any.NONE);
-        TestEq(monster.mutateTestType(Any.Monster), true);
-        TestEq(monster.testType(), (byte)Any.Monster);
-
-        //mutate the inventory vector
-        TestEq(monster.mutateInventory(0, 1), true);
-        TestEq(monster.mutateInventory(1, 2), true);
-        TestEq(monster.mutateInventory(2, 3), true);
-        TestEq(monster.mutateInventory(3, 4), true);
-        TestEq(monster.mutateInventory(4, 5), true);
-
-        for (int i = 0; i < monster.inventoryLength(); i++) {
-            TestEq(monster.inventory(i), i + 1);
-        }
-
-        //reverse mutation
-        TestEq(monster.mutateInventory(0, 0), true);
-        TestEq(monster.mutateInventory(1, 1), true);
-        TestEq(monster.mutateInventory(2, 2), true);
-        TestEq(monster.mutateInventory(3, 3), true);
-        TestEq(monster.mutateInventory(4, 4), true);
-
-        // get a struct field and edit one of its fields
-        Vec3 pos = monster.pos();
-        TestEq(pos.x(), 1.0f);
-        pos.mutateX(55.0f);
-        TestEq(pos.x(), 55.0f);
-        pos.mutateX(1.0f);
-        TestEq(pos.x(), 1.0f);
+        TestBuilderBasics(fbb);
 
         TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
 
@@ -189,6 +65,10 @@
 
         TestCreateUninitializedVector();
 
+        TestByteBufferFactory();
+
+        TestSizedInputStream();
+
         System.out.println("FlatBuffers test: completed successfully");
     }
 
@@ -201,7 +81,7 @@
 
     static void TestBuffer(ByteBuffer bb) {
         TestEq(Monster.MonsterBufferHasIdentifier(bb), true);
-        
+
         Monster monster = Monster.getRootAsMonster(bb);
 
         TestEq(monster.hp(), (short)80);
@@ -259,25 +139,25 @@
 
         TestEq(monster.testhashu32Fnv1(), Integer.MAX_VALUE + 1L);
     }
-    
+
     static void TestNamespaceNesting() {
         // reference / manipulate these to verify compilation
         FlatBufferBuilder fbb = new FlatBufferBuilder(1);
-        
+
         TableInNestedNS.startTableInNestedNS(fbb);
         TableInNestedNS.addFoo(fbb, 1234);
         int nestedTableOff = TableInNestedNS.endTableInNestedNS(fbb);
-        
-        TableInFirstNS.startTableInFirstNS(fbb);      
+
+        TableInFirstNS.startTableInFirstNS(fbb);
         TableInFirstNS.addFooTable(fbb, nestedTableOff);
         int off = TableInFirstNS.endTableInFirstNS(fbb);
     }
-    
+
     static void TestNestedFlatBuffer() {
         final String nestedMonsterName = "NestedMonsterName";
         final short nestedMonsterHp = 600;
         final short nestedMonsterMana = 1024;
-        
+
         FlatBufferBuilder fbb1 = new FlatBufferBuilder(16);
         int str1 = fbb1.createString(nestedMonsterName);
         Monster.startMonster(fbb1);
@@ -288,8 +168,8 @@
         Monster.finishMonsterBuffer(fbb1, monster1);
         byte[] fbb1Bytes = fbb1.sizedByteArray();
         fbb1 = null;
-        
-        FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);        
+
+        FlatBufferBuilder fbb2 = new FlatBufferBuilder(16);
         int str2 = fbb2.createString("My Monster");
         int nestedBuffer = Monster.createTestnestedflatbufferVector(fbb2, fbb1Bytes);
         Monster.startMonster(fbb2);
@@ -299,7 +179,7 @@
         Monster.addTestnestedflatbuffer(fbb2, nestedBuffer);
         int monster = Monster.endMonster(fbb2);
         Monster.finishMonsterBuffer(fbb2, monster);
-        
+
         // Now test the data extracted from the nested buffer
         Monster mons = Monster.getRootAsMonster(fbb2.dataBuffer());
         Monster nestedMonster = mons.testnestedflatbufferAsMonster();
@@ -347,6 +227,179 @@
         TestEq(ByteBuffer.wrap(inventory), monsterObject.inventoryAsByteBuffer());
     }
 
+    static void TestByteBufferFactory() {
+        final class MappedByteBufferFactory implements FlatBufferBuilder.ByteBufferFactory {
+            @Override
+            public ByteBuffer newByteBuffer(int capacity) {
+                ByteBuffer bb;
+                try {
+                    bb =  new RandomAccessFile("javatest.bin", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, capacity).order(ByteOrder.LITTLE_ENDIAN);
+                } catch(Throwable e) {
+                    System.out.println("FlatBuffers test: couldn't map ByteBuffer to a file");
+                    bb = null;
+                }
+                return bb;
+            }
+        }
+
+        FlatBufferBuilder fbb = new FlatBufferBuilder(1, new MappedByteBufferFactory());
+
+        TestBuilderBasics(fbb);
+    }
+
+    static void TestSizedInputStream() {
+        // Test on default FlatBufferBuilder that uses HeapByteBuffer
+        FlatBufferBuilder fbb = new FlatBufferBuilder(1);
+
+        TestBuilderBasics(fbb);
+
+        InputStream in = fbb.sizedInputStream();
+        byte[] array = fbb.sizedByteArray();
+        int count = 0;
+        int currentVal = 0;
+
+        while (currentVal != -1 && count < array.length) {
+            try {
+                currentVal = in.read();
+            } catch(java.io.IOException e) {
+                System.out.println("FlatBuffers test: couldn't read from InputStream");
+                return;
+            }
+            TestEq((byte)currentVal, array[count]);
+            count++;
+        }
+        TestEq(count, array.length);
+    }
+
+    static void TestBuilderBasics(FlatBufferBuilder fbb) {
+        int[] names = {fbb.createString("Frodo"), fbb.createString("Barney"), fbb.createString("Wilma")};
+        int[] off = new int[3];
+        Monster.startMonster(fbb);
+        Monster.addName(fbb, names[0]);
+        off[0] = Monster.endMonster(fbb);
+        Monster.startMonster(fbb);
+        Monster.addName(fbb, names[1]);
+        off[1] = Monster.endMonster(fbb);
+        Monster.startMonster(fbb);
+        Monster.addName(fbb, names[2]);
+        off[2] = Monster.endMonster(fbb);
+        int sortMons = fbb.createSortedVectorOfTables(new Monster(), off);
+
+        // We set up the same values as monsterdata.json:
+
+        int str = fbb.createString("MyMonster");
+
+        int inv = Monster.createInventoryVector(fbb, new byte[] { 0, 1, 2, 3, 4 });
+
+        int fred = fbb.createString("Fred");
+        Monster.startMonster(fbb);
+        Monster.addName(fbb, fred);
+        int mon2 = Monster.endMonster(fbb);
+
+        Monster.startTest4Vector(fbb, 2);
+        Test.createTest(fbb, (short)10, (byte)20);
+        Test.createTest(fbb, (short)30, (byte)40);
+        int test4 = fbb.endVector();
+
+        int testArrayOfString = Monster.createTestarrayofstringVector(fbb, new int[] {
+                fbb.createString("test1"),
+                fbb.createString("test2")
+        });
+
+        Monster.startMonster(fbb);
+        Monster.addPos(fbb, Vec3.createVec3(fbb, 1.0f, 2.0f, 3.0f, 3.0,
+                Color.Green, (short)5, (byte)6));
+        Monster.addHp(fbb, (short)80);
+        Monster.addName(fbb, str);
+        Monster.addInventory(fbb, inv);
+        Monster.addTestType(fbb, (byte)Any.Monster);
+        Monster.addTest(fbb, mon2);
+        Monster.addTest4(fbb, test4);
+        Monster.addTestarrayofstring(fbb, testArrayOfString);
+        Monster.addTestbool(fbb, false);
+        Monster.addTesthashu32Fnv1(fbb, Integer.MAX_VALUE + 1L);
+        Monster.addTestarrayoftables(fbb, sortMons);
+        int mon = Monster.endMonster(fbb);
+
+        Monster.finishMonsterBuffer(fbb, mon);
+
+        // Write the result to a file for debugging purposes:
+        // Note that the binaries are not necessarily identical, since the JSON
+        // parser may serialize in a slightly different order than the above
+        // Java code. They are functionally equivalent though.
+
+        try {
+            FileChannel fc = new FileOutputStream("monsterdata_java_wire.mon").getChannel();
+            fc.write(fbb.dataBuffer().duplicate());
+            fc.close();
+        } catch(java.io.IOException e) {
+            System.out.println("FlatBuffers test: couldn't write file");
+            return;
+        }
+
+        // Test it:
+        TestExtendedBuffer(fbb.dataBuffer());
+
+        // Make sure it also works with read only ByteBuffers. This is slower,
+        // since creating strings incurs an additional copy
+        // (see Table.__string).
+        TestExtendedBuffer(fbb.dataBuffer().asReadOnlyBuffer());
+
+        TestEnums();
+
+        //Attempt to mutate Monster fields and check whether the buffer has been mutated properly
+        // revert to original values after testing
+        Monster monster = Monster.getRootAsMonster(fbb.dataBuffer());
+
+        // mana is optional and does not exist in the buffer so the mutation should fail
+        // the mana field should retain its default value
+        TestEq(monster.mutateMana((short)10), false);
+        TestEq(monster.mana(), (short)150);
+
+        // Accessing a vector of sorted by the key tables
+        TestEq(monster.testarrayoftables(0).name(), "Barney");
+        TestEq(monster.testarrayoftables(1).name(), "Frodo");
+        TestEq(monster.testarrayoftables(2).name(), "Wilma");
+
+        // Example of searching for a table by the key
+        TestEq(monster.testarrayoftablesByKey("Frodo").name(), "Frodo");
+        TestEq(monster.testarrayoftablesByKey("Barney").name(), "Barney");
+        TestEq(monster.testarrayoftablesByKey("Wilma").name(), "Wilma");
+
+        // testType is an existing field and mutating it should succeed
+        TestEq(monster.testType(), (byte)Any.Monster);
+        TestEq(monster.mutateTestType(Any.NONE), true);
+        TestEq(monster.testType(), (byte)Any.NONE);
+        TestEq(monster.mutateTestType(Any.Monster), true);
+        TestEq(monster.testType(), (byte)Any.Monster);
+
+        //mutate the inventory vector
+        TestEq(monster.mutateInventory(0, 1), true);
+        TestEq(monster.mutateInventory(1, 2), true);
+        TestEq(monster.mutateInventory(2, 3), true);
+        TestEq(monster.mutateInventory(3, 4), true);
+        TestEq(monster.mutateInventory(4, 5), true);
+
+        for (int i = 0; i < monster.inventoryLength(); i++) {
+            TestEq(monster.inventory(i), i + 1);
+        }
+
+        //reverse mutation
+        TestEq(monster.mutateInventory(0, 0), true);
+        TestEq(monster.mutateInventory(1, 1), true);
+        TestEq(monster.mutateInventory(2, 2), true);
+        TestEq(monster.mutateInventory(3, 3), true);
+        TestEq(monster.mutateInventory(4, 4), true);
+
+        // get a struct field and edit one of its fields
+        Vec3 pos = monster.pos();
+        TestEq(pos.x(), 1.0f);
+        pos.mutateX(55.0f);
+        TestEq(pos.x(), 55.0f);
+        pos.mutateX(1.0f);
+        TestEq(pos.x(), 1.0f);
+    }
+
     static <T> void TestEq(T a, T b) {
         if (!a.equals(b)) {
             System.out.println("" + a.getClass().getName() + " " + b.getClass().getName());
diff --git a/tests/JavaTest.sh b/tests/JavaTest.sh
index 40e854b..a5a049e 100755
--- a/tests/JavaTest.sh
+++ b/tests/JavaTest.sh
@@ -14,31 +14,30 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+set -o errexit
+
 echo Compile then run the Java test.
 
 java -version
 
-testdir=$(readlink -fn `dirname $0`)
-thisdir=$(readlink -fn `pwd`)
+testdir="$(readlink -fn "$(dirname "$0")")"
 
-targetdir=${testdir}/target
-
-if [[ "$testdir" != "$thisdir" ]]; then
-	echo error: must be run from inside the ${testdir} directory
-	echo you ran it from ${thisdir}
-	exit 1
-fi
-
-find .. -type f -name "*.class" -exec rm  {} \;
+targetdir="${testdir}/target"
 
 if [[ -e "${targetdir}" ]]; then
-    echo "clean target"
-    rm -rf ${targetdir}
+    echo "cleaning target"
+    rm -rf "${targetdir}"
 fi
 
-mkdir ${targetdir}
+mkdir -v "${targetdir}"
 
-javac -d ${targetdir} -classpath ${testdir}/../java:${testdir}:${testdir}/namespace_test JavaTest.java
-java -classpath ${targetdir} JavaTest
+if ! find "${testdir}/../java" -type f -name "*.class" -delete; then
+    echo "failed to clean .class files from java directory" >&2
+    exit 1
+fi
 
-rm -rf ${targetdir}
+javac -d "${targetdir}" -classpath "${testdir}/../java:${testdir}:${testdir}/namespace_test" "${testdir}/JavaTest.java"
+
+(cd "${testdir}" && java -classpath "${targetdir}" JavaTest )
+
+rm -rf "${targetdir}"
diff --git a/tests/MyGame/Example/Ability.cs b/tests/MyGame/Example/Ability.cs
new file mode 100644
index 0000000..17dce4e
--- /dev/null
+++ b/tests/MyGame/Example/Ability.cs
@@ -0,0 +1,32 @@
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct Ability : IFlatbufferObject
+{
+  private Struct __p;
+  public ByteBuffer ByteBuffer { get { return __p.bb; } }
+  public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+  public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public uint Id { get { return __p.bb.GetUint(__p.bb_pos + 0); } }
+  public void MutateId(uint id) { __p.bb.PutUint(__p.bb_pos + 0, id); }
+  public uint Distance { get { return __p.bb.GetUint(__p.bb_pos + 4); } }
+  public void MutateDistance(uint distance) { __p.bb.PutUint(__p.bb_pos + 4, distance); }
+
+  public static Offset<Ability> CreateAbility(FlatBufferBuilder builder, uint Id, uint Distance) {
+    builder.Prep(4, 8);
+    builder.PutUint(Distance);
+    builder.PutUint(Id);
+    return new Offset<Ability>(builder.Offset);
+  }
+};
+
+
+}
diff --git a/tests/MyGame/Example/Ability.go b/tests/MyGame/Example/Ability.go
new file mode 100644
index 0000000..2ea8665
--- /dev/null
+++ b/tests/MyGame/Example/Ability.go
@@ -0,0 +1,41 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package Example
+
+import (
+	flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type Ability struct {
+	_tab flatbuffers.Struct
+}
+
+func (rcv *Ability) Init(buf []byte, i flatbuffers.UOffsetT) {
+	rcv._tab.Bytes = buf
+	rcv._tab.Pos = i
+}
+
+func (rcv *Ability) Table() flatbuffers.Table {
+	return rcv._tab.Table
+}
+
+func (rcv *Ability) Id() uint32 {
+	return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(0))
+}
+func (rcv *Ability) MutateId(n uint32) bool {
+	return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(0), n)
+}
+
+func (rcv *Ability) Distance() uint32 {
+	return rcv._tab.GetUint32(rcv._tab.Pos + flatbuffers.UOffsetT(4))
+}
+func (rcv *Ability) MutateDistance(n uint32) bool {
+	return rcv._tab.MutateUint32(rcv._tab.Pos+flatbuffers.UOffsetT(4), n)
+}
+
+func CreateAbility(builder *flatbuffers.Builder, id uint32, distance uint32) flatbuffers.UOffsetT {
+	builder.Prep(4, 8)
+	builder.PrependUint32(distance)
+	builder.PrependUint32(id)
+	return builder.Offset()
+}
diff --git a/tests/MyGame/Example/Ability.java b/tests/MyGame/Example/Ability.java
new file mode 100644
index 0000000..5e1c90e
--- /dev/null
+++ b/tests/MyGame/Example/Ability.java
@@ -0,0 +1,27 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class Ability extends Struct {
+  public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+  public Ability __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public long id() { return (long)bb.getInt(bb_pos + 0) & 0xFFFFFFFFL; }
+  public void mutateId(long id) { bb.putInt(bb_pos + 0, (int)id); }
+  public long distance() { return (long)bb.getInt(bb_pos + 4) & 0xFFFFFFFFL; }
+  public void mutateDistance(long distance) { bb.putInt(bb_pos + 4, (int)distance); }
+
+  public static int createAbility(FlatBufferBuilder builder, long id, long distance) {
+    builder.prep(4, 8);
+    builder.putInt((int)distance);
+    builder.putInt((int)id);
+    return builder.offset();
+  }
+}
+
diff --git a/tests/MyGame/Example/Ability.php b/tests/MyGame/Example/Ability.php
new file mode 100644
index 0000000..c09eca3
--- /dev/null
+++ b/tests/MyGame/Example/Ability.php
@@ -0,0 +1,52 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Ability extends Struct
+{
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return Ability
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return uint
+     */
+    public function GetId()
+    {
+        return $this->bb->getUint($this->bb_pos + 0);
+    }
+
+    /**
+     * @return uint
+     */
+    public function GetDistance()
+    {
+        return $this->bb->getUint($this->bb_pos + 4);
+    }
+
+
+    /**
+     * @return int offset
+     */
+    public static function createAbility(FlatBufferBuilder $builder, $id, $distance)
+    {
+        $builder->prep(4, 8);
+        $builder->putUint($distance);
+        $builder->putUint($id);
+        return $builder->offset();
+    }
+}
diff --git a/tests/MyGame/Example/Ability.py b/tests/MyGame/Example/Ability.py
new file mode 100644
index 0000000..3c4776e
--- /dev/null
+++ b/tests/MyGame/Example/Ability.py
@@ -0,0 +1,23 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class Ability(object):
+    __slots__ = ['_tab']
+
+    # Ability
+    def Init(self, buf, pos):
+        self._tab = flatbuffers.table.Table(buf, pos)
+
+    # Ability
+    def Id(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(0))
+    # Ability
+    def Distance(self): return self._tab.Get(flatbuffers.number_types.Uint32Flags, self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(4))
+
+def CreateAbility(builder, id, distance):
+    builder.Prep(4, 8)
+    builder.PrependUint32(distance)
+    builder.PrependUint32(id)
+    return builder.Offset()
diff --git a/tests/MyGame/Example/Any.cs b/tests/MyGame/Example/Any.cs
index 8fdc2fc..8393853 100644
--- a/tests/MyGame/Example/Any.cs
+++ b/tests/MyGame/Example/Any.cs
@@ -1,4 +1,6 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
diff --git a/tests/MyGame/Example/Color.cs b/tests/MyGame/Example/Color.cs
index 625d040..f40d60b 100644
--- a/tests/MyGame/Example/Color.cs
+++ b/tests/MyGame/Example/Color.cs
@@ -1,4 +1,6 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
diff --git a/tests/MyGame/Example/Monster.cs b/tests/MyGame/Example/Monster.cs
index 30f4922..ed43659 100644
--- a/tests/MyGame/Example/Monster.cs
+++ b/tests/MyGame/Example/Monster.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 /// an example documentation comment: monster object
 public struct Monster : IFlatbufferObject
@@ -41,6 +43,7 @@
   /// multiline too
   public Monster? Testarrayoftables(int j) { int o = __p.__offset(26); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(__p.__vector(o) + j * 4), __p.bb) : null; }
   public int TestarrayoftablesLength { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public Monster? TestarrayoftablesByKey(string key) { int o = __p.__offset(26); return o != 0 ? Monster.__lookup_by_key(__p.__vector(o), key, __p.bb) : null; }
   public Monster? Enemy { get { int o = __p.__offset(28); return o != 0 ? (Monster?)(new Monster()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
   public byte Testnestedflatbuffer(int j) { int o = __p.__offset(30); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
   public int TestnestedflatbufferLength { get { int o = __p.__offset(30); return o != 0 ? __p.__vector_len(o) : 0; } }
@@ -78,8 +81,25 @@
   public bool MutateTestf3(float testf3) { int o = __p.__offset(58); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf3); return true; } else { return false; } }
   public string Testarrayofstring2(int j) { int o = __p.__offset(60); return o != 0 ? __p.__string(__p.__vector(o) + j * 4) : null; }
   public int Testarrayofstring2Length { get { int o = __p.__offset(60); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public Ability? Testarrayofsortedstruct(int j) { int o = __p.__offset(62); return o != 0 ? (Ability?)(new Ability()).__assign(__p.__vector(o) + j * 8, __p.bb) : null; }
+  public int TestarrayofsortedstructLength { get { int o = __p.__offset(62); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public byte Flex(int j) { int o = __p.__offset(64); return o != 0 ? __p.bb.Get(__p.__vector(o) + j * 1) : (byte)0; }
+  public int FlexLength { get { int o = __p.__offset(64); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetFlexBytes() { return __p.__vector_as_arraysegment(64); }
+  public bool MutateFlex(int j, byte flex) { int o = __p.__offset(64); if (o != 0) { __p.bb.Put(__p.__vector(o) + j * 1, flex); return true; } else { return false; } }
+  public Test? Test5(int j) { int o = __p.__offset(66); return o != 0 ? (Test?)(new Test()).__assign(__p.__vector(o) + j * 4, __p.bb) : null; }
+  public int Test5Length { get { int o = __p.__offset(66); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public long VectorOfLongs(int j) { int o = __p.__offset(68); return o != 0 ? __p.bb.GetLong(__p.__vector(o) + j * 8) : (long)0; }
+  public int VectorOfLongsLength { get { int o = __p.__offset(68); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetVectorOfLongsBytes() { return __p.__vector_as_arraysegment(68); }
+  public bool MutateVectorOfLongs(int j, long vector_of_longs) { int o = __p.__offset(68); if (o != 0) { __p.bb.PutLong(__p.__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+  public double VectorOfDoubles(int j) { int o = __p.__offset(70); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+  public int VectorOfDoublesLength { get { int o = __p.__offset(70); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetVectorOfDoublesBytes() { return __p.__vector_as_arraysegment(70); }
+  public bool MutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __p.__offset(70); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
+  public MyGame.InParentNamespace? ParentNamespaceTest { get { int o = __p.__offset(72); return o != 0 ? (MyGame.InParentNamespace?)(new MyGame.InParentNamespace()).__assign(__p.__indirect(o + __p.bb_pos), __p.bb) : null; } }
 
-  public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
+  public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(35); }
   public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
   public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
   public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
@@ -121,6 +141,20 @@
   public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); }
   public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
   public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
+  public static void AddTestarrayofsortedstruct(FlatBufferBuilder builder, VectorOffset testarrayofsortedstructOffset) { builder.AddOffset(29, testarrayofsortedstructOffset.Value, 0); }
+  public static void StartTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 4); }
+  public static void AddFlex(FlatBufferBuilder builder, VectorOffset flexOffset) { builder.AddOffset(30, flexOffset.Value, 0); }
+  public static VectorOffset CreateFlexVector(FlatBufferBuilder builder, byte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddByte(data[i]); return builder.EndVector(); }
+  public static void StartFlexVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+  public static void AddTest5(FlatBufferBuilder builder, VectorOffset test5Offset) { builder.AddOffset(31, test5Offset.Value, 0); }
+  public static void StartTest5Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 2); }
+  public static void AddVectorOfLongs(FlatBufferBuilder builder, VectorOffset vectorOfLongsOffset) { builder.AddOffset(32, vectorOfLongsOffset.Value, 0); }
+  public static VectorOffset CreateVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddLong(data[i]); return builder.EndVector(); }
+  public static void StartVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+  public static void AddVectorOfDoubles(FlatBufferBuilder builder, VectorOffset vectorOfDoublesOffset) { builder.AddOffset(33, vectorOfDoublesOffset.Value, 0); }
+  public static VectorOffset CreateVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+  public static void StartVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+  public static void AddParentNamespaceTest(FlatBufferBuilder builder, Offset<MyGame.InParentNamespace> parentNamespaceTestOffset) { builder.AddOffset(34, parentNamespaceTestOffset.Value, 0); }
   public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
     int o = builder.EndObject();
     builder.Required(o, 10);  // name
@@ -128,17 +162,15 @@
   }
   public static void FinishMonsterBuffer(FlatBufferBuilder builder, Offset<Monster> offset) { builder.Finish(offset.Value, "MONS"); }
 
-  public static VectorOffset CreateMySortedVectorOfTables(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
+  public static VectorOffset CreateSortedVectorOfMonster(FlatBufferBuilder builder, Offset<Monster>[] offsets) {
     Array.Sort(offsets, (Offset<Monster> o1, Offset<Monster> o2) => Table.CompareStrings(Table.__offset(10, o1.Value, builder.DataBuffer), Table.__offset(10, o2.Value, builder.DataBuffer), builder.DataBuffer));
     return builder.CreateVectorOfTables(offsets);
   }
 
-  public static Monster? LookupByKey(VectorOffset vectorOffset, string key, ByteBuffer bb) {
+  public static Monster? __lookup_by_key(int vectorLocation, string key, ByteBuffer bb) {
     byte[] byteKey = System.Text.Encoding.UTF8.GetBytes(key);
-    int vectorLocation = bb.Length - vectorOffset.Value;
-    int span = bb.GetInt(vectorLocation);
+    int span = bb.GetInt(vectorLocation - 4);
     int start = 0;
-    vectorLocation += 4;
     while (span != 0) {
       int middle = span / 2;
       int tableOffset = Table.__indirect(vectorLocation + 4 * (start + middle), bb);
diff --git a/tests/MyGame/Example/Monster.go b/tests/MyGame/Example/Monster.go
index ba3ae0f..04e5852 100644
--- a/tests/MyGame/Example/Monster.go
+++ b/tests/MyGame/Example/Monster.go
@@ -419,8 +419,118 @@
 	return 0
 }
 
+func (rcv *Monster) Testarrayofsortedstruct(obj *Ability, j int) bool {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
+	if o != 0 {
+		x := rcv._tab.Vector(o)
+		x += flatbuffers.UOffsetT(j) * 8
+		obj.Init(rcv._tab.Bytes, x)
+		return true
+	}
+	return false
+}
+
+func (rcv *Monster) TestarrayofsortedstructLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(62))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) Flex(j int) byte {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetByte(a + flatbuffers.UOffsetT(j*1))
+	}
+	return 0
+}
+
+func (rcv *Monster) FlexLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) FlexBytes() []byte {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(64))
+	if o != 0 {
+		return rcv._tab.ByteVector(o + rcv._tab.Pos)
+	}
+	return nil
+}
+
+func (rcv *Monster) Test5(obj *Test, j int) bool {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(66))
+	if o != 0 {
+		x := rcv._tab.Vector(o)
+		x += flatbuffers.UOffsetT(j) * 4
+		obj.Init(rcv._tab.Bytes, x)
+		return true
+	}
+	return false
+}
+
+func (rcv *Monster) Test5Length() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(66))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfLongs(j int) int64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetInt64(a + flatbuffers.UOffsetT(j*8))
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfLongsLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(68))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfDoubles(j int) float64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetFloat64(a + flatbuffers.UOffsetT(j*8))
+	}
+	return 0
+}
+
+func (rcv *Monster) VectorOfDoublesLength() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(70))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *Monster) ParentNamespaceTest(obj *InParentNamespace) *InParentNamespace {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(72))
+	if o != 0 {
+		x := rcv._tab.Indirect(o + rcv._tab.Pos)
+		if obj == nil {
+			obj = new(InParentNamespace)
+		}
+		obj.Init(rcv._tab.Bytes, x)
+		return obj
+	}
+	return nil
+}
+
 func MonsterStart(builder *flatbuffers.Builder) {
-	builder.StartObject(29)
+	builder.StartObject(35)
 }
 func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) {
 	builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0)
@@ -527,6 +637,39 @@
 func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
 	return builder.StartVector(4, numElems, 4)
 }
+func MonsterAddTestarrayofsortedstruct(builder *flatbuffers.Builder, testarrayofsortedstruct flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(29, flatbuffers.UOffsetT(testarrayofsortedstruct), 0)
+}
+func MonsterStartTestarrayofsortedstructVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 4)
+}
+func MonsterAddFlex(builder *flatbuffers.Builder, flex flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(30, flatbuffers.UOffsetT(flex), 0)
+}
+func MonsterStartFlexVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(1, numElems, 1)
+}
+func MonsterAddTest5(builder *flatbuffers.Builder, test5 flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(31, flatbuffers.UOffsetT(test5), 0)
+}
+func MonsterStartTest5Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(4, numElems, 2)
+}
+func MonsterAddVectorOfLongs(builder *flatbuffers.Builder, vectorOfLongs flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(32, flatbuffers.UOffsetT(vectorOfLongs), 0)
+}
+func MonsterStartVectorOfLongsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddVectorOfDoubles(builder *flatbuffers.Builder, vectorOfDoubles flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(33, flatbuffers.UOffsetT(vectorOfDoubles), 0)
+}
+func MonsterStartVectorOfDoublesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 8)
+}
+func MonsterAddParentNamespaceTest(builder *flatbuffers.Builder, parentNamespaceTest flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(34, flatbuffers.UOffsetT(parentNamespaceTest), 0)
+}
 func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
 	return builder.EndObject()
 }
diff --git a/tests/MyGame/Example/Monster.java b/tests/MyGame/Example/Monster.java
index 10a9aa4..3d97b77 100644
--- a/tests/MyGame/Example/Monster.java
+++ b/tests/MyGame/Example/Monster.java
@@ -47,6 +47,7 @@
   public Monster testarrayoftables(int j) { return testarrayoftables(new Monster(), j); }
   public Monster testarrayoftables(Monster obj, int j) { int o = __offset(26); return o != 0 ? obj.__assign(__indirect(__vector(o) + j * 4), bb) : null; }
   public int testarrayoftablesLength() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
+  public Monster testarrayoftablesByKey(String key) { int o = __offset(26); return o != 0 ? Monster.__lookup_by_key(__vector(o), key, bb) : null; }
   public Monster enemy() { return enemy(new Monster()); }
   public Monster enemy(Monster obj) { int o = __offset(28); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
   public int testnestedflatbuffer(int j) { int o = __offset(30); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
@@ -87,8 +88,28 @@
   public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } }
   public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
   public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; }
+  public Ability testarrayofsortedstruct(int j) { return testarrayofsortedstruct(new Ability(), j); }
+  public Ability testarrayofsortedstruct(Ability obj, int j) { int o = __offset(62); return o != 0 ? obj.__assign(__vector(o) + j * 8, bb) : null; }
+  public int testarrayofsortedstructLength() { int o = __offset(62); return o != 0 ? __vector_len(o) : 0; }
+  public int flex(int j) { int o = __offset(64); return o != 0 ? bb.get(__vector(o) + j * 1) & 0xFF : 0; }
+  public int flexLength() { int o = __offset(64); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer flexAsByteBuffer() { return __vector_as_bytebuffer(64, 1); }
+  public boolean mutateFlex(int j, int flex) { int o = __offset(64); if (o != 0) { bb.put(__vector(o) + j * 1, (byte)flex); return true; } else { return false; } }
+  public Test test5(int j) { return test5(new Test(), j); }
+  public Test test5(Test obj, int j) { int o = __offset(66); return o != 0 ? obj.__assign(__vector(o) + j * 4, bb) : null; }
+  public int test5Length() { int o = __offset(66); return o != 0 ? __vector_len(o) : 0; }
+  public long vectorOfLongs(int j) { int o = __offset(68); return o != 0 ? bb.getLong(__vector(o) + j * 8) : 0; }
+  public int vectorOfLongsLength() { int o = __offset(68); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer vectorOfLongsAsByteBuffer() { return __vector_as_bytebuffer(68, 8); }
+  public boolean mutateVectorOfLongs(int j, long vector_of_longs) { int o = __offset(68); if (o != 0) { bb.putLong(__vector(o) + j * 8, vector_of_longs); return true; } else { return false; } }
+  public double vectorOfDoubles(int j) { int o = __offset(70); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+  public int vectorOfDoublesLength() { int o = __offset(70); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer vectorOfDoublesAsByteBuffer() { return __vector_as_bytebuffer(70, 8); }
+  public boolean mutateVectorOfDoubles(int j, double vector_of_doubles) { int o = __offset(70); if (o != 0) { bb.putDouble(__vector(o) + j * 8, vector_of_doubles); return true; } else { return false; } }
+  public MyGame.InParentNamespace parentNamespaceTest() { return parentNamespaceTest(new MyGame.InParentNamespace()); }
+  public MyGame.InParentNamespace parentNamespaceTest(MyGame.InParentNamespace obj) { int o = __offset(72); return o != 0 ? obj.__assign(__indirect(o + bb_pos), bb) : null; }
 
-  public static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); }
+  public static void startMonster(FlatBufferBuilder builder) { builder.startObject(35); }
   public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
   public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
   public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
@@ -130,6 +151,20 @@
   public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); }
   public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
   public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
+  public static void addTestarrayofsortedstruct(FlatBufferBuilder builder, int testarrayofsortedstructOffset) { builder.addOffset(29, testarrayofsortedstructOffset, 0); }
+  public static void startTestarrayofsortedstructVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 4); }
+  public static void addFlex(FlatBufferBuilder builder, int flexOffset) { builder.addOffset(30, flexOffset, 0); }
+  public static int createFlexVector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+  public static void startFlexVector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static void addTest5(FlatBufferBuilder builder, int test5Offset) { builder.addOffset(31, test5Offset, 0); }
+  public static void startTest5Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 2); }
+  public static void addVectorOfLongs(FlatBufferBuilder builder, int vectorOfLongsOffset) { builder.addOffset(32, vectorOfLongsOffset, 0); }
+  public static int createVectorOfLongsVector(FlatBufferBuilder builder, long[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addLong(data[i]); return builder.endVector(); }
+  public static void startVectorOfLongsVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+  public static void addVectorOfDoubles(FlatBufferBuilder builder, int vectorOfDoublesOffset) { builder.addOffset(33, vectorOfDoublesOffset, 0); }
+  public static int createVectorOfDoublesVector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+  public static void startVectorOfDoublesVector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+  public static void addParentNamespaceTest(FlatBufferBuilder builder, int parentNamespaceTestOffset) { builder.addOffset(34, parentNamespaceTestOffset, 0); }
   public static int endMonster(FlatBufferBuilder builder) {
     int o = builder.endObject();
     builder.required(o, 10);  // name
@@ -140,16 +175,14 @@
   @Override
   protected int keysCompare(Integer o1, Integer o2, ByteBuffer _bb) { return compareStrings(__offset(10, o1, _bb), __offset(10, o2, _bb), _bb); }
 
-  public static Monster lookupByKey(int vectorOffset, String key, ByteBuffer bb) {
+  public static Monster __lookup_by_key(int vectorLocation, String key, ByteBuffer bb) {
     byte[] byteKey = key.getBytes(Table.UTF8_CHARSET.get());
-    int vectorLocation = bb.array().length - vectorOffset;
-    int span = bb.getInt(vectorLocation);
+    int span = bb.getInt(vectorLocation - 4);
     int start = 0;
-    vectorLocation += 4;
     while (span != 0) {
       int middle = span / 2;
       int tableOffset = __indirect(vectorLocation + 4 * (start + middle), bb);
-      int comp = compareStrings(__offset(10, bb.array().length - tableOffset, bb), byteKey, bb);
+      int comp = compareStrings(__offset(10, bb.capacity() - tableOffset, bb), byteKey, bb);
       if (comp > 0) {
         span = middle;
       } else if (comp < 0) {
diff --git a/tests/MyGame/Example/Monster.php b/tests/MyGame/Example/Monster.php
index c06cffb..eb66de8 100644
--- a/tests/MyGame/Example/Monster.php
+++ b/tests/MyGame/Example/Monster.php
@@ -380,21 +380,131 @@
     }
 
     /**
+     * @returnVectorOffset
+     */
+    public function getTestarrayofsortedstruct($j)
+    {
+        $o = $this->__offset(62);
+        $obj = new Ability();
+        return $o != 0 ? $obj->init($this->__vector($o) + $j *8, $this->bb) : null;
+    }
+
+    /**
+     * @return int
+     */
+    public function getTestarrayofsortedstructLength()
+    {
+        $o = $this->__offset(62);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return byte
+     */
+    public function getFlex($j)
+    {
+        $o = $this->__offset(64);
+        return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getFlexLength()
+    {
+        $o = $this->__offset(64);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @return string
+     */
+    public function getFlexBytes()
+    {
+        return $this->__vector_as_bytes(64);
+    }
+
+    /**
+     * @returnVectorOffset
+     */
+    public function getTest5($j)
+    {
+        $o = $this->__offset(66);
+        $obj = new Test();
+        return $o != 0 ? $obj->init($this->__vector($o) + $j *4, $this->bb) : null;
+    }
+
+    /**
+     * @return int
+     */
+    public function getTest5Length()
+    {
+        $o = $this->__offset(66);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return long
+     */
+    public function getVectorOfLongs($j)
+    {
+        $o = $this->__offset(68);
+        return $o != 0 ? $this->bb->getLong($this->__vector($o) + $j * 8) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getVectorOfLongsLength()
+    {
+        $o = $this->__offset(68);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return double
+     */
+    public function getVectorOfDoubles($j)
+    {
+        $o = $this->__offset(70);
+        return $o != 0 ? $this->bb->getDouble($this->__vector($o) + $j * 8) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getVectorOfDoublesLength()
+    {
+        $o = $this->__offset(70);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    public function getParentNamespaceTest()
+    {
+        $obj = new InParentNamespace();
+        $o = $this->__offset(72);
+        return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
+    }
+
+    /**
      * @param FlatBufferBuilder $builder
      * @return void
      */
     public static function startMonster(FlatBufferBuilder $builder)
     {
-        $builder->StartObject(29);
+        $builder->StartObject(35);
     }
 
     /**
      * @param FlatBufferBuilder $builder
      * @return Monster
      */
-    public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2)
+    public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2, $testarrayofsortedstruct, $flex, $test5, $vector_of_longs, $vector_of_doubles, $parent_namespace_test)
     {
-        $builder->startObject(29);
+        $builder->startObject(35);
         self::addPos($builder, $pos);
         self::addMana($builder, $mana);
         self::addHp($builder, $hp);
@@ -423,6 +533,12 @@
         self::addTestf2($builder, $testf2);
         self::addTestf3($builder, $testf3);
         self::addTestarrayofstring2($builder, $testarrayofstring2);
+        self::addTestarrayofsortedstruct($builder, $testarrayofsortedstruct);
+        self::addFlex($builder, $flex);
+        self::addTest5($builder, $test5);
+        self::addVectorOfLongs($builder, $vector_of_longs);
+        self::addVectorOfDoubles($builder, $vector_of_doubles);
+        self::addParentNamespaceTest($builder, $parent_namespace_test);
         $o = $builder->endObject();
         $builder->required($o, 10);  // name
         return $o;
@@ -873,6 +989,186 @@
 
     /**
      * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addTestarrayofsortedstruct(FlatBufferBuilder $builder, $testarrayofsortedstruct)
+    {
+        $builder->addOffsetX(29, $testarrayofsortedstruct, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createTestarrayofsortedstructVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 4);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addOffset($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startTestarrayofsortedstructVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 4);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addFlex(FlatBufferBuilder $builder, $flex)
+    {
+        $builder->addOffsetX(30, $flex, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createFlexVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(1, count($data), 1);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addByte($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startFlexVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(1, $numElems, 1);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addTest5(FlatBufferBuilder $builder, $test5)
+    {
+        $builder->addOffsetX(31, $test5, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createTest5Vector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(4, count($data), 2);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addOffset($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startTest5Vector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(4, $numElems, 2);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addVectorOfLongs(FlatBufferBuilder $builder, $vectorOfLongs)
+    {
+        $builder->addOffsetX(32, $vectorOfLongs, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createVectorOfLongsVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 8);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addLong($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startVectorOfLongsVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 8);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addVectorOfDoubles(FlatBufferBuilder $builder, $vectorOfDoubles)
+    {
+        $builder->addOffsetX(33, $vectorOfDoubles, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createVectorOfDoublesVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 8);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addDouble($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startVectorOfDoublesVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 8);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int
+     * @return void
+     */
+    public static function addParentNamespaceTest(FlatBufferBuilder $builder, $parentNamespaceTest)
+    {
+        $builder->addOffsetX(34, $parentNamespaceTest, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
      * @return int table offset
      */
     public static function endMonster(FlatBufferBuilder $builder)
diff --git a/tests/MyGame/Example/Monster.py b/tests/MyGame/Example/Monster.py
index a7a7836..fc834ed 100644
--- a/tests/MyGame/Example/Monster.py
+++ b/tests/MyGame/Example/Monster.py
@@ -49,7 +49,7 @@
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
         if o != 0:
             return self._tab.String(o + self._tab.Pos)
-        return ""
+        return bytes()
 
     # Monster
     def Inventory(self, j):
@@ -60,6 +60,13 @@
         return 0
 
     # Monster
+    def InventoryAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
+    # Monster
     def InventoryLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
         if o != 0:
@@ -166,6 +173,13 @@
         return 0
 
     # Monster
+    def TestnestedflatbufferAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
+    # Monster
     def TestnestedflatbufferLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
         if o != 0:
@@ -255,6 +269,13 @@
         return 0
 
     # Monster
+    def TestarrayofboolsAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.BoolFlags, o)
+        return 0
+
+    # Monster
     def TestarrayofboolsLength(self):
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(52))
         if o != 0:
@@ -297,7 +318,122 @@
             return self._tab.VectorLen(o)
         return 0
 
-def MonsterStart(builder): builder.StartObject(29)
+    # Monster
+    def Testarrayofsortedstruct(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
+        if o != 0:
+            x = self._tab.Vector(o)
+            x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 8
+            from .Ability import Ability
+            obj = Ability()
+            obj.Init(self._tab.Bytes, x)
+            return obj
+        return None
+
+    # Monster
+    def TestarrayofsortedstructLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(62))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def Flex(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Uint8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+        return 0
+
+    # Monster
+    def FlexAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
+        return 0
+
+    # Monster
+    def FlexLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(64))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def Test5(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(66))
+        if o != 0:
+            x = self._tab.Vector(o)
+            x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * 4
+            from .Test import Test
+            obj = Test()
+            obj.Init(self._tab.Bytes, x)
+            return obj
+        return None
+
+    # Monster
+    def Test5Length(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(66))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def VectorOfLongs(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Int64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+        return 0
+
+    # Monster
+    def VectorOfLongsAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int64Flags, o)
+        return 0
+
+    # Monster
+    def VectorOfLongsLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(68))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def VectorOfDoubles(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+        return 0
+
+    # Monster
+    def VectorOfDoublesAsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+        return 0
+
+    # Monster
+    def VectorOfDoublesLength(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(70))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # Monster
+    def ParentNamespaceTest(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(72))
+        if o != 0:
+            x = self._tab.Indirect(o + self._tab.Pos)
+            from .InParentNamespace import InParentNamespace
+            obj = InParentNamespace()
+            obj.Init(self._tab.Bytes, x)
+            return obj
+        return None
+
+def MonsterStart(builder): builder.StartObject(35)
 def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
 def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
 def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
@@ -333,4 +469,15 @@
 def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0)
 def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0)
 def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4)
+def MonsterAddTestarrayofsortedstruct(builder, testarrayofsortedstruct): builder.PrependUOffsetTRelativeSlot(29, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofsortedstruct), 0)
+def MonsterStartTestarrayofsortedstructVector(builder, numElems): return builder.StartVector(8, numElems, 4)
+def MonsterAddFlex(builder, flex): builder.PrependUOffsetTRelativeSlot(30, flatbuffers.number_types.UOffsetTFlags.py_type(flex), 0)
+def MonsterStartFlexVector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def MonsterAddTest5(builder, test5): builder.PrependUOffsetTRelativeSlot(31, flatbuffers.number_types.UOffsetTFlags.py_type(test5), 0)
+def MonsterStartTest5Vector(builder, numElems): return builder.StartVector(4, numElems, 2)
+def MonsterAddVectorOfLongs(builder, vectorOfLongs): builder.PrependUOffsetTRelativeSlot(32, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfLongs), 0)
+def MonsterStartVectorOfLongsVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddVectorOfDoubles(builder, vectorOfDoubles): builder.PrependUOffsetTRelativeSlot(33, flatbuffers.number_types.UOffsetTFlags.py_type(vectorOfDoubles), 0)
+def MonsterStartVectorOfDoublesVector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def MonsterAddParentNamespaceTest(builder, parentNamespaceTest): builder.PrependUOffsetTRelativeSlot(34, flatbuffers.number_types.UOffsetTFlags.py_type(parentNamespaceTest), 0)
 def MonsterEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Stat.cs b/tests/MyGame/Example/Stat.cs
index 0fb5bd0..e1fd572 100644
--- a/tests/MyGame/Example/Stat.cs
+++ b/tests/MyGame/Example/Stat.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct Stat : IFlatbufferObject
 {
diff --git a/tests/MyGame/Example/Stat.py b/tests/MyGame/Example/Stat.py
index b0e251d..2e0cc05 100644
--- a/tests/MyGame/Example/Stat.py
+++ b/tests/MyGame/Example/Stat.py
@@ -23,7 +23,7 @@
         o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
         if o != 0:
             return self._tab.String(o + self._tab.Pos)
-        return ""
+        return bytes()
 
     # Stat
     def Val(self):
diff --git a/tests/MyGame/Example/Test.cs b/tests/MyGame/Example/Test.cs
index 92c3b91..1842131 100644
--- a/tests/MyGame/Example/Test.cs
+++ b/tests/MyGame/Example/Test.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct Test : IFlatbufferObject
 {
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.cs b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
index bff3864..f24d6ea 100644
--- a/tests/MyGame/Example/TestSimpleTableWithEnum.cs
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public partial struct TestSimpleTableWithEnum : IFlatbufferObject
 {
diff --git a/tests/MyGame/Example/TypeAliases.cs b/tests/MyGame/Example/TypeAliases.cs
new file mode 100644
index 0000000..f03c142
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.cs
@@ -0,0 +1,102 @@
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame.Example
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct TypeAliases : IFlatbufferObject
+{
+  private Table __p;
+  public ByteBuffer ByteBuffer { get { return __p.bb; } }
+  public static TypeAliases GetRootAsTypeAliases(ByteBuffer _bb) { return GetRootAsTypeAliases(_bb, new TypeAliases()); }
+  public static TypeAliases GetRootAsTypeAliases(ByteBuffer _bb, TypeAliases obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+  public TypeAliases __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public sbyte I8 { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetSbyte(o + __p.bb_pos) : (sbyte)0; } }
+  public bool MutateI8(sbyte i8) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutSbyte(o + __p.bb_pos, i8); return true; } else { return false; } }
+  public byte U8 { get { int o = __p.__offset(6); return o != 0 ? __p.bb.Get(o + __p.bb_pos) : (byte)0; } }
+  public bool MutateU8(byte u8) { int o = __p.__offset(6); if (o != 0) { __p.bb.Put(o + __p.bb_pos, u8); return true; } else { return false; } }
+  public short I16 { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetShort(o + __p.bb_pos) : (short)0; } }
+  public bool MutateI16(short i16) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutShort(o + __p.bb_pos, i16); return true; } else { return false; } }
+  public ushort U16 { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetUshort(o + __p.bb_pos) : (ushort)0; } }
+  public bool MutateU16(ushort u16) { int o = __p.__offset(10); if (o != 0) { __p.bb.PutUshort(o + __p.bb_pos, u16); return true; } else { return false; } }
+  public int I32 { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetInt(o + __p.bb_pos) : (int)0; } }
+  public bool MutateI32(int i32) { int o = __p.__offset(12); if (o != 0) { __p.bb.PutInt(o + __p.bb_pos, i32); return true; } else { return false; } }
+  public uint U32 { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetUint(o + __p.bb_pos) : (uint)0; } }
+  public bool MutateU32(uint u32) { int o = __p.__offset(14); if (o != 0) { __p.bb.PutUint(o + __p.bb_pos, u32); return true; } else { return false; } }
+  public long I64 { get { int o = __p.__offset(16); return o != 0 ? __p.bb.GetLong(o + __p.bb_pos) : (long)0; } }
+  public bool MutateI64(long i64) { int o = __p.__offset(16); if (o != 0) { __p.bb.PutLong(o + __p.bb_pos, i64); return true; } else { return false; } }
+  public ulong U64 { get { int o = __p.__offset(18); return o != 0 ? __p.bb.GetUlong(o + __p.bb_pos) : (ulong)0; } }
+  public bool MutateU64(ulong u64) { int o = __p.__offset(18); if (o != 0) { __p.bb.PutUlong(o + __p.bb_pos, u64); return true; } else { return false; } }
+  public float F32 { get { int o = __p.__offset(20); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)0.0f; } }
+  public bool MutateF32(float f32) { int o = __p.__offset(20); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, f32); return true; } else { return false; } }
+  public double F64 { get { int o = __p.__offset(22); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)0.0; } }
+  public bool MutateF64(double f64) { int o = __p.__offset(22); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, f64); return true; } else { return false; } }
+  public sbyte V8(int j) { int o = __p.__offset(24); return o != 0 ? __p.bb.GetSbyte(__p.__vector(o) + j * 1) : (sbyte)0; }
+  public int V8Length { get { int o = __p.__offset(24); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetV8Bytes() { return __p.__vector_as_arraysegment(24); }
+  public bool MutateV8(int j, sbyte v8) { int o = __p.__offset(24); if (o != 0) { __p.bb.PutSbyte(__p.__vector(o) + j * 1, v8); return true; } else { return false; } }
+  public double Vf64(int j) { int o = __p.__offset(26); return o != 0 ? __p.bb.GetDouble(__p.__vector(o) + j * 8) : (double)0; }
+  public int Vf64Length { get { int o = __p.__offset(26); return o != 0 ? __p.__vector_len(o) : 0; } }
+  public ArraySegment<byte>? GetVf64Bytes() { return __p.__vector_as_arraysegment(26); }
+  public bool MutateVf64(int j, double vf64) { int o = __p.__offset(26); if (o != 0) { __p.bb.PutDouble(__p.__vector(o) + j * 8, vf64); return true; } else { return false; } }
+
+  public static Offset<TypeAliases> CreateTypeAliases(FlatBufferBuilder builder,
+      sbyte i8 = 0,
+      byte u8 = 0,
+      short i16 = 0,
+      ushort u16 = 0,
+      int i32 = 0,
+      uint u32 = 0,
+      long i64 = 0,
+      ulong u64 = 0,
+      float f32 = 0.0f,
+      double f64 = 0.0,
+      VectorOffset v8Offset = default(VectorOffset),
+      VectorOffset vf64Offset = default(VectorOffset)) {
+    builder.StartObject(12);
+    TypeAliases.AddF64(builder, f64);
+    TypeAliases.AddU64(builder, u64);
+    TypeAliases.AddI64(builder, i64);
+    TypeAliases.AddVf64(builder, vf64Offset);
+    TypeAliases.AddV8(builder, v8Offset);
+    TypeAliases.AddF32(builder, f32);
+    TypeAliases.AddU32(builder, u32);
+    TypeAliases.AddI32(builder, i32);
+    TypeAliases.AddU16(builder, u16);
+    TypeAliases.AddI16(builder, i16);
+    TypeAliases.AddU8(builder, u8);
+    TypeAliases.AddI8(builder, i8);
+    return TypeAliases.EndTypeAliases(builder);
+  }
+
+  public static void StartTypeAliases(FlatBufferBuilder builder) { builder.StartObject(12); }
+  public static void AddI8(FlatBufferBuilder builder, sbyte i8) { builder.AddSbyte(0, i8, 0); }
+  public static void AddU8(FlatBufferBuilder builder, byte u8) { builder.AddByte(1, u8, 0); }
+  public static void AddI16(FlatBufferBuilder builder, short i16) { builder.AddShort(2, i16, 0); }
+  public static void AddU16(FlatBufferBuilder builder, ushort u16) { builder.AddUshort(3, u16, 0); }
+  public static void AddI32(FlatBufferBuilder builder, int i32) { builder.AddInt(4, i32, 0); }
+  public static void AddU32(FlatBufferBuilder builder, uint u32) { builder.AddUint(5, u32, 0); }
+  public static void AddI64(FlatBufferBuilder builder, long i64) { builder.AddLong(6, i64, 0); }
+  public static void AddU64(FlatBufferBuilder builder, ulong u64) { builder.AddUlong(7, u64, 0); }
+  public static void AddF32(FlatBufferBuilder builder, float f32) { builder.AddFloat(8, f32, 0.0f); }
+  public static void AddF64(FlatBufferBuilder builder, double f64) { builder.AddDouble(9, f64, 0.0); }
+  public static void AddV8(FlatBufferBuilder builder, VectorOffset v8Offset) { builder.AddOffset(10, v8Offset.Value, 0); }
+  public static VectorOffset CreateV8Vector(FlatBufferBuilder builder, sbyte[] data) { builder.StartVector(1, data.Length, 1); for (int i = data.Length - 1; i >= 0; i--) builder.AddSbyte(data[i]); return builder.EndVector(); }
+  public static void StartV8Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(1, numElems, 1); }
+  public static void AddVf64(FlatBufferBuilder builder, VectorOffset vf64Offset) { builder.AddOffset(11, vf64Offset.Value, 0); }
+  public static VectorOffset CreateVf64Vector(FlatBufferBuilder builder, double[] data) { builder.StartVector(8, data.Length, 8); for (int i = data.Length - 1; i >= 0; i--) builder.AddDouble(data[i]); return builder.EndVector(); }
+  public static void StartVf64Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(8, numElems, 8); }
+  public static Offset<TypeAliases> EndTypeAliases(FlatBufferBuilder builder) {
+    int o = builder.EndObject();
+    return new Offset<TypeAliases>(o);
+  }
+};
+
+
+}
diff --git a/tests/MyGame/Example/TypeAliases.go b/tests/MyGame/Example/TypeAliases.go
new file mode 100644
index 0000000..c64c287
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.go
@@ -0,0 +1,230 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package Example
+
+import (
+	flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type TypeAliases struct {
+	_tab flatbuffers.Table
+}
+
+func GetRootAsTypeAliases(buf []byte, offset flatbuffers.UOffsetT) *TypeAliases {
+	n := flatbuffers.GetUOffsetT(buf[offset:])
+	x := &TypeAliases{}
+	x.Init(buf, n+offset)
+	return x
+}
+
+func (rcv *TypeAliases) Init(buf []byte, i flatbuffers.UOffsetT) {
+	rcv._tab.Bytes = buf
+	rcv._tab.Pos = i
+}
+
+func (rcv *TypeAliases) Table() flatbuffers.Table {
+	return rcv._tab
+}
+
+func (rcv *TypeAliases) I8() int8 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
+	if o != 0 {
+		return rcv._tab.GetInt8(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateI8(n int8) bool {
+	return rcv._tab.MutateInt8Slot(4, n)
+}
+
+func (rcv *TypeAliases) U8() byte {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
+	if o != 0 {
+		return rcv._tab.GetByte(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateU8(n byte) bool {
+	return rcv._tab.MutateByteSlot(6, n)
+}
+
+func (rcv *TypeAliases) I16() int16 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(8))
+	if o != 0 {
+		return rcv._tab.GetInt16(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateI16(n int16) bool {
+	return rcv._tab.MutateInt16Slot(8, n)
+}
+
+func (rcv *TypeAliases) U16() uint16 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(10))
+	if o != 0 {
+		return rcv._tab.GetUint16(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateU16(n uint16) bool {
+	return rcv._tab.MutateUint16Slot(10, n)
+}
+
+func (rcv *TypeAliases) I32() int32 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(12))
+	if o != 0 {
+		return rcv._tab.GetInt32(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateI32(n int32) bool {
+	return rcv._tab.MutateInt32Slot(12, n)
+}
+
+func (rcv *TypeAliases) U32() uint32 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(14))
+	if o != 0 {
+		return rcv._tab.GetUint32(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateU32(n uint32) bool {
+	return rcv._tab.MutateUint32Slot(14, n)
+}
+
+func (rcv *TypeAliases) I64() int64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(16))
+	if o != 0 {
+		return rcv._tab.GetInt64(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateI64(n int64) bool {
+	return rcv._tab.MutateInt64Slot(16, n)
+}
+
+func (rcv *TypeAliases) U64() uint64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
+	if o != 0 {
+		return rcv._tab.GetUint64(o + rcv._tab.Pos)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) MutateU64(n uint64) bool {
+	return rcv._tab.MutateUint64Slot(18, n)
+}
+
+func (rcv *TypeAliases) F32() float32 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(20))
+	if o != 0 {
+		return rcv._tab.GetFloat32(o + rcv._tab.Pos)
+	}
+	return 0.0
+}
+
+func (rcv *TypeAliases) MutateF32(n float32) bool {
+	return rcv._tab.MutateFloat32Slot(20, n)
+}
+
+func (rcv *TypeAliases) F64() float64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(22))
+	if o != 0 {
+		return rcv._tab.GetFloat64(o + rcv._tab.Pos)
+	}
+	return 0.0
+}
+
+func (rcv *TypeAliases) MutateF64(n float64) bool {
+	return rcv._tab.MutateFloat64Slot(22, n)
+}
+
+func (rcv *TypeAliases) V8(j int) int8 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetInt8(a + flatbuffers.UOffsetT(j*1))
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) V8Length() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) Vf64(j int) float64 {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+	if o != 0 {
+		a := rcv._tab.Vector(o)
+		return rcv._tab.GetFloat64(a + flatbuffers.UOffsetT(j*8))
+	}
+	return 0
+}
+
+func (rcv *TypeAliases) Vf64Length() int {
+	o := flatbuffers.UOffsetT(rcv._tab.Offset(26))
+	if o != 0 {
+		return rcv._tab.VectorLen(o)
+	}
+	return 0
+}
+
+func TypeAliasesStart(builder *flatbuffers.Builder) {
+	builder.StartObject(12)
+}
+func TypeAliasesAddI8(builder *flatbuffers.Builder, i8 int8) {
+	builder.PrependInt8Slot(0, i8, 0)
+}
+func TypeAliasesAddU8(builder *flatbuffers.Builder, u8 byte) {
+	builder.PrependByteSlot(1, u8, 0)
+}
+func TypeAliasesAddI16(builder *flatbuffers.Builder, i16 int16) {
+	builder.PrependInt16Slot(2, i16, 0)
+}
+func TypeAliasesAddU16(builder *flatbuffers.Builder, u16 uint16) {
+	builder.PrependUint16Slot(3, u16, 0)
+}
+func TypeAliasesAddI32(builder *flatbuffers.Builder, i32 int32) {
+	builder.PrependInt32Slot(4, i32, 0)
+}
+func TypeAliasesAddU32(builder *flatbuffers.Builder, u32 uint32) {
+	builder.PrependUint32Slot(5, u32, 0)
+}
+func TypeAliasesAddI64(builder *flatbuffers.Builder, i64 int64) {
+	builder.PrependInt64Slot(6, i64, 0)
+}
+func TypeAliasesAddU64(builder *flatbuffers.Builder, u64 uint64) {
+	builder.PrependUint64Slot(7, u64, 0)
+}
+func TypeAliasesAddF32(builder *flatbuffers.Builder, f32 float32) {
+	builder.PrependFloat32Slot(8, f32, 0.0)
+}
+func TypeAliasesAddF64(builder *flatbuffers.Builder, f64 float64) {
+	builder.PrependFloat64Slot(9, f64, 0.0)
+}
+func TypeAliasesAddV8(builder *flatbuffers.Builder, v8 flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(10, flatbuffers.UOffsetT(v8), 0)
+}
+func TypeAliasesStartV8Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(1, numElems, 1)
+}
+func TypeAliasesAddVf64(builder *flatbuffers.Builder, vf64 flatbuffers.UOffsetT) {
+	builder.PrependUOffsetTSlot(11, flatbuffers.UOffsetT(vf64), 0)
+}
+func TypeAliasesStartVf64Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT {
+	return builder.StartVector(8, numElems, 8)
+}
+func TypeAliasesEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+	return builder.EndObject()
+}
diff --git a/tests/MyGame/Example/TypeAliases.java b/tests/MyGame/Example/TypeAliases.java
new file mode 100644
index 0000000..a5cff0c
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.java
@@ -0,0 +1,97 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame.Example;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class TypeAliases extends Table {
+  public static TypeAliases getRootAsTypeAliases(ByteBuffer _bb) { return getRootAsTypeAliases(_bb, new TypeAliases()); }
+  public static TypeAliases getRootAsTypeAliases(ByteBuffer _bb, TypeAliases obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+  public TypeAliases __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public byte i8() { int o = __offset(4); return o != 0 ? bb.get(o + bb_pos) : 0; }
+  public boolean mutateI8(byte i8) { int o = __offset(4); if (o != 0) { bb.put(o + bb_pos, i8); return true; } else { return false; } }
+  public int u8() { int o = __offset(6); return o != 0 ? bb.get(o + bb_pos) & 0xFF : 0; }
+  public boolean mutateU8(int u8) { int o = __offset(6); if (o != 0) { bb.put(o + bb_pos, (byte)u8); return true; } else { return false; } }
+  public short i16() { int o = __offset(8); return o != 0 ? bb.getShort(o + bb_pos) : 0; }
+  public boolean mutateI16(short i16) { int o = __offset(8); if (o != 0) { bb.putShort(o + bb_pos, i16); return true; } else { return false; } }
+  public int u16() { int o = __offset(10); return o != 0 ? bb.getShort(o + bb_pos) & 0xFFFF : 0; }
+  public boolean mutateU16(int u16) { int o = __offset(10); if (o != 0) { bb.putShort(o + bb_pos, (short)u16); return true; } else { return false; } }
+  public int i32() { int o = __offset(12); return o != 0 ? bb.getInt(o + bb_pos) : 0; }
+  public boolean mutateI32(int i32) { int o = __offset(12); if (o != 0) { bb.putInt(o + bb_pos, i32); return true; } else { return false; } }
+  public long u32() { int o = __offset(14); return o != 0 ? (long)bb.getInt(o + bb_pos) & 0xFFFFFFFFL : 0L; }
+  public boolean mutateU32(long u32) { int o = __offset(14); if (o != 0) { bb.putInt(o + bb_pos, (int)u32); return true; } else { return false; } }
+  public long i64() { int o = __offset(16); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+  public boolean mutateI64(long i64) { int o = __offset(16); if (o != 0) { bb.putLong(o + bb_pos, i64); return true; } else { return false; } }
+  public long u64() { int o = __offset(18); return o != 0 ? bb.getLong(o + bb_pos) : 0L; }
+  public boolean mutateU64(long u64) { int o = __offset(18); if (o != 0) { bb.putLong(o + bb_pos, u64); return true; } else { return false; } }
+  public float f32() { int o = __offset(20); return o != 0 ? bb.getFloat(o + bb_pos) : 0.0f; }
+  public boolean mutateF32(float f32) { int o = __offset(20); if (o != 0) { bb.putFloat(o + bb_pos, f32); return true; } else { return false; } }
+  public double f64() { int o = __offset(22); return o != 0 ? bb.getDouble(o + bb_pos) : 0.0; }
+  public boolean mutateF64(double f64) { int o = __offset(22); if (o != 0) { bb.putDouble(o + bb_pos, f64); return true; } else { return false; } }
+  public byte v8(int j) { int o = __offset(24); return o != 0 ? bb.get(__vector(o) + j * 1) : 0; }
+  public int v8Length() { int o = __offset(24); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer v8AsByteBuffer() { return __vector_as_bytebuffer(24, 1); }
+  public boolean mutateV8(int j, byte v8) { int o = __offset(24); if (o != 0) { bb.put(__vector(o) + j * 1, v8); return true; } else { return false; } }
+  public double vf64(int j) { int o = __offset(26); return o != 0 ? bb.getDouble(__vector(o) + j * 8) : 0; }
+  public int vf64Length() { int o = __offset(26); return o != 0 ? __vector_len(o) : 0; }
+  public ByteBuffer vf64AsByteBuffer() { return __vector_as_bytebuffer(26, 8); }
+  public boolean mutateVf64(int j, double vf64) { int o = __offset(26); if (o != 0) { bb.putDouble(__vector(o) + j * 8, vf64); return true; } else { return false; } }
+
+  public static int createTypeAliases(FlatBufferBuilder builder,
+      byte i8,
+      int u8,
+      short i16,
+      int u16,
+      int i32,
+      long u32,
+      long i64,
+      long u64,
+      float f32,
+      double f64,
+      int v8Offset,
+      int vf64Offset) {
+    builder.startObject(12);
+    TypeAliases.addF64(builder, f64);
+    TypeAliases.addU64(builder, u64);
+    TypeAliases.addI64(builder, i64);
+    TypeAliases.addVf64(builder, vf64Offset);
+    TypeAliases.addV8(builder, v8Offset);
+    TypeAliases.addF32(builder, f32);
+    TypeAliases.addU32(builder, u32);
+    TypeAliases.addI32(builder, i32);
+    TypeAliases.addU16(builder, u16);
+    TypeAliases.addI16(builder, i16);
+    TypeAliases.addU8(builder, u8);
+    TypeAliases.addI8(builder, i8);
+    return TypeAliases.endTypeAliases(builder);
+  }
+
+  public static void startTypeAliases(FlatBufferBuilder builder) { builder.startObject(12); }
+  public static void addI8(FlatBufferBuilder builder, byte i8) { builder.addByte(0, i8, 0); }
+  public static void addU8(FlatBufferBuilder builder, int u8) { builder.addByte(1, (byte)u8, (byte)0); }
+  public static void addI16(FlatBufferBuilder builder, short i16) { builder.addShort(2, i16, 0); }
+  public static void addU16(FlatBufferBuilder builder, int u16) { builder.addShort(3, (short)u16, (short)0); }
+  public static void addI32(FlatBufferBuilder builder, int i32) { builder.addInt(4, i32, 0); }
+  public static void addU32(FlatBufferBuilder builder, long u32) { builder.addInt(5, (int)u32, (int)0L); }
+  public static void addI64(FlatBufferBuilder builder, long i64) { builder.addLong(6, i64, 0L); }
+  public static void addU64(FlatBufferBuilder builder, long u64) { builder.addLong(7, u64, 0L); }
+  public static void addF32(FlatBufferBuilder builder, float f32) { builder.addFloat(8, f32, 0.0f); }
+  public static void addF64(FlatBufferBuilder builder, double f64) { builder.addDouble(9, f64, 0.0); }
+  public static void addV8(FlatBufferBuilder builder, int v8Offset) { builder.addOffset(10, v8Offset, 0); }
+  public static int createV8Vector(FlatBufferBuilder builder, byte[] data) { builder.startVector(1, data.length, 1); for (int i = data.length - 1; i >= 0; i--) builder.addByte(data[i]); return builder.endVector(); }
+  public static void startV8Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(1, numElems, 1); }
+  public static void addVf64(FlatBufferBuilder builder, int vf64Offset) { builder.addOffset(11, vf64Offset, 0); }
+  public static int createVf64Vector(FlatBufferBuilder builder, double[] data) { builder.startVector(8, data.length, 8); for (int i = data.length - 1; i >= 0; i--) builder.addDouble(data[i]); return builder.endVector(); }
+  public static void startVf64Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(8, numElems, 8); }
+  public static int endTypeAliases(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+}
+
diff --git a/tests/MyGame/Example/TypeAliases.php b/tests/MyGame/Example/TypeAliases.php
new file mode 100644
index 0000000..ecf804d
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.php
@@ -0,0 +1,387 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame\Example;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class TypeAliases extends Table
+{
+    /**
+     * @param ByteBuffer $bb
+     * @return TypeAliases
+     */
+    public static function getRootAsTypeAliases(ByteBuffer $bb)
+    {
+        $obj = new TypeAliases();
+        return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+    }
+
+    public static function TypeAliasesIdentifier()
+    {
+        return "MONS";
+    }
+
+    public static function TypeAliasesBufferHasIdentifier(ByteBuffer $buf)
+    {
+        return self::__has_identifier($buf, self::TypeAliasesIdentifier());
+    }
+
+    public static function TypeAliasesExtension()
+    {
+        return "mon";
+    }
+
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return TypeAliases
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return sbyte
+     */
+    public function getI8()
+    {
+        $o = $this->__offset(4);
+        return $o != 0 ? $this->bb->getSbyte($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return byte
+     */
+    public function getU8()
+    {
+        $o = $this->__offset(6);
+        return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return short
+     */
+    public function getI16()
+    {
+        $o = $this->__offset(8);
+        return $o != 0 ? $this->bb->getShort($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return ushort
+     */
+    public function getU16()
+    {
+        $o = $this->__offset(10);
+        return $o != 0 ? $this->bb->getUshort($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getI32()
+    {
+        $o = $this->__offset(12);
+        return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return uint
+     */
+    public function getU32()
+    {
+        $o = $this->__offset(14);
+        return $o != 0 ? $this->bb->getUint($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return long
+     */
+    public function getI64()
+    {
+        $o = $this->__offset(16);
+        return $o != 0 ? $this->bb->getLong($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return ulong
+     */
+    public function getU64()
+    {
+        $o = $this->__offset(18);
+        return $o != 0 ? $this->bb->getUlong($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @return float
+     */
+    public function getF32()
+    {
+        $o = $this->__offset(20);
+        return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 0.0;
+    }
+
+    /**
+     * @return double
+     */
+    public function getF64()
+    {
+        $o = $this->__offset(22);
+        return $o != 0 ? $this->bb->getDouble($o + $this->bb_pos) : 0.0;
+    }
+
+    /**
+     * @param int offset
+     * @return sbyte
+     */
+    public function getV8($j)
+    {
+        $o = $this->__offset(24);
+        return $o != 0 ? $this->bb->getSbyte($this->__vector($o) + $j * 1) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getV8Length()
+    {
+        $o = $this->__offset(24);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return double
+     */
+    public function getVf64($j)
+    {
+        $o = $this->__offset(26);
+        return $o != 0 ? $this->bb->getDouble($this->__vector($o) + $j * 8) : 0;
+    }
+
+    /**
+     * @return int
+     */
+    public function getVf64Length()
+    {
+        $o = $this->__offset(26);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return void
+     */
+    public static function startTypeAliases(FlatBufferBuilder $builder)
+    {
+        $builder->StartObject(12);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return TypeAliases
+     */
+    public static function createTypeAliases(FlatBufferBuilder $builder, $i8, $u8, $i16, $u16, $i32, $u32, $i64, $u64, $f32, $f64, $v8, $vf64)
+    {
+        $builder->startObject(12);
+        self::addI8($builder, $i8);
+        self::addU8($builder, $u8);
+        self::addI16($builder, $i16);
+        self::addU16($builder, $u16);
+        self::addI32($builder, $i32);
+        self::addU32($builder, $u32);
+        self::addI64($builder, $i64);
+        self::addU64($builder, $u64);
+        self::addF32($builder, $f32);
+        self::addF64($builder, $f64);
+        self::addV8($builder, $v8);
+        self::addVf64($builder, $vf64);
+        $o = $builder->endObject();
+        return $o;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param sbyte
+     * @return void
+     */
+    public static function addI8(FlatBufferBuilder $builder, $i8)
+    {
+        $builder->addSbyteX(0, $i8, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param byte
+     * @return void
+     */
+    public static function addU8(FlatBufferBuilder $builder, $u8)
+    {
+        $builder->addByteX(1, $u8, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param short
+     * @return void
+     */
+    public static function addI16(FlatBufferBuilder $builder, $i16)
+    {
+        $builder->addShortX(2, $i16, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param ushort
+     * @return void
+     */
+    public static function addU16(FlatBufferBuilder $builder, $u16)
+    {
+        $builder->addUshortX(3, $u16, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int
+     * @return void
+     */
+    public static function addI32(FlatBufferBuilder $builder, $i32)
+    {
+        $builder->addIntX(4, $i32, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param uint
+     * @return void
+     */
+    public static function addU32(FlatBufferBuilder $builder, $u32)
+    {
+        $builder->addUintX(5, $u32, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param long
+     * @return void
+     */
+    public static function addI64(FlatBufferBuilder $builder, $i64)
+    {
+        $builder->addLongX(6, $i64, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param ulong
+     * @return void
+     */
+    public static function addU64(FlatBufferBuilder $builder, $u64)
+    {
+        $builder->addUlongX(7, $u64, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param float
+     * @return void
+     */
+    public static function addF32(FlatBufferBuilder $builder, $f32)
+    {
+        $builder->addFloatX(8, $f32, 0.0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param double
+     * @return void
+     */
+    public static function addF64(FlatBufferBuilder $builder, $f64)
+    {
+        $builder->addDoubleX(9, $f64, 0.0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addV8(FlatBufferBuilder $builder, $v8)
+    {
+        $builder->addOffsetX(10, $v8, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createV8Vector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(1, count($data), 1);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addSbyte($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startV8Vector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(1, $numElems, 1);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addVf64(FlatBufferBuilder $builder, $vf64)
+    {
+        $builder->addOffsetX(11, $vf64, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createVf64Vector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(8, count($data), 8);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addDouble($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startVf64Vector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(8, $numElems, 8);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return int table offset
+     */
+    public static function endTypeAliases(FlatBufferBuilder $builder)
+    {
+        $o = $builder->endObject();
+        return $o;
+    }
+}
diff --git a/tests/MyGame/Example/TypeAliases.py b/tests/MyGame/Example/TypeAliases.py
new file mode 100644
index 0000000..707e53f
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.py
@@ -0,0 +1,150 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: Example
+
+import flatbuffers
+
+class TypeAliases(object):
+    __slots__ = ['_tab']
+
+    @classmethod
+    def GetRootAsTypeAliases(cls, buf, offset):
+        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+        x = TypeAliases()
+        x.Init(buf, n + offset)
+        return x
+
+    # TypeAliases
+    def Init(self, buf, pos):
+        self._tab = flatbuffers.table.Table(buf, pos)
+
+    # TypeAliases
+    def I8(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Int8Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def U8(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Uint8Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def I16(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Int16Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def U16(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Uint16Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def I32(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Int32Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def U32(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Uint32Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def I64(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(16))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Int64Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def U64(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(18))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Uint64Flags, o + self._tab.Pos)
+        return 0
+
+    # TypeAliases
+    def F32(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(20))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+        return 0.0
+
+    # TypeAliases
+    def F64(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(22))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+        return 0.0
+
+    # TypeAliases
+    def V8(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Int8Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 1))
+        return 0
+
+    # TypeAliases
+    def V8AsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Int8Flags, o)
+        return 0
+
+    # TypeAliases
+    def V8Length(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(24))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+    # TypeAliases
+    def Vf64(self, j):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+        if o != 0:
+            a = self._tab.Vector(o)
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 8))
+        return 0
+
+    # TypeAliases
+    def Vf64AsNumpy(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+        if o != 0:
+            return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Float64Flags, o)
+        return 0
+
+    # TypeAliases
+    def Vf64Length(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(26))
+        if o != 0:
+            return self._tab.VectorLen(o)
+        return 0
+
+def TypeAliasesStart(builder): builder.StartObject(12)
+def TypeAliasesAddI8(builder, i8): builder.PrependInt8Slot(0, i8, 0)
+def TypeAliasesAddU8(builder, u8): builder.PrependUint8Slot(1, u8, 0)
+def TypeAliasesAddI16(builder, i16): builder.PrependInt16Slot(2, i16, 0)
+def TypeAliasesAddU16(builder, u16): builder.PrependUint16Slot(3, u16, 0)
+def TypeAliasesAddI32(builder, i32): builder.PrependInt32Slot(4, i32, 0)
+def TypeAliasesAddU32(builder, u32): builder.PrependUint32Slot(5, u32, 0)
+def TypeAliasesAddI64(builder, i64): builder.PrependInt64Slot(6, i64, 0)
+def TypeAliasesAddU64(builder, u64): builder.PrependUint64Slot(7, u64, 0)
+def TypeAliasesAddF32(builder, f32): builder.PrependFloat32Slot(8, f32, 0.0)
+def TypeAliasesAddF64(builder, f64): builder.PrependFloat64Slot(9, f64, 0.0)
+def TypeAliasesAddV8(builder, v8): builder.PrependUOffsetTRelativeSlot(10, flatbuffers.number_types.UOffsetTFlags.py_type(v8), 0)
+def TypeAliasesStartV8Vector(builder, numElems): return builder.StartVector(1, numElems, 1)
+def TypeAliasesAddVf64(builder, vf64): builder.PrependUOffsetTRelativeSlot(11, flatbuffers.number_types.UOffsetTFlags.py_type(vf64), 0)
+def TypeAliasesStartVf64Vector(builder, numElems): return builder.StartVector(8, numElems, 8)
+def TypeAliasesEnd(builder): return builder.EndObject()
diff --git a/tests/MyGame/Example/Vec3.cs b/tests/MyGame/Example/Vec3.cs
index 0552543..e1669f9 100644
--- a/tests/MyGame/Example/Vec3.cs
+++ b/tests/MyGame/Example/Vec3.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct Vec3 : IFlatbufferObject
 {
diff --git a/tests/MyGame/Example2/Monster.cs b/tests/MyGame/Example2/Monster.cs
index 2a0b6de..e880ebb 100644
--- a/tests/MyGame/Example2/Monster.cs
+++ b/tests/MyGame/Example2/Monster.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace MyGame.Example2
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct Monster : IFlatbufferObject
 {
diff --git a/tests/MyGame/Example2/__init__.py b/tests/MyGame/Example2/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/MyGame/Example2/__init__.py
diff --git a/tests/MyGame/InParentNamespace.cs b/tests/MyGame/InParentNamespace.cs
new file mode 100644
index 0000000..7b8ffc2
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.cs
@@ -0,0 +1,29 @@
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct InParentNamespace : IFlatbufferObject
+{
+  private Table __p;
+  public ByteBuffer ByteBuffer { get { return __p.bb; } }
+  public static InParentNamespace GetRootAsInParentNamespace(ByteBuffer _bb) { return GetRootAsInParentNamespace(_bb, new InParentNamespace()); }
+  public static InParentNamespace GetRootAsInParentNamespace(ByteBuffer _bb, InParentNamespace obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+  public InParentNamespace __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+  public static void StartInParentNamespace(FlatBufferBuilder builder) { builder.StartObject(0); }
+  public static Offset<InParentNamespace> EndInParentNamespace(FlatBufferBuilder builder) {
+    int o = builder.EndObject();
+    return new Offset<InParentNamespace>(o);
+  }
+};
+
+
+}
diff --git a/tests/MyGame/InParentNamespace.go b/tests/MyGame/InParentNamespace.go
new file mode 100644
index 0000000..341b05c
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.go
@@ -0,0 +1,34 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame
+
+import (
+	flatbuffers "github.com/google/flatbuffers/go"
+)
+
+type InParentNamespace struct {
+	_tab flatbuffers.Table
+}
+
+func GetRootAsInParentNamespace(buf []byte, offset flatbuffers.UOffsetT) *InParentNamespace {
+	n := flatbuffers.GetUOffsetT(buf[offset:])
+	x := &InParentNamespace{}
+	x.Init(buf, n+offset)
+	return x
+}
+
+func (rcv *InParentNamespace) Init(buf []byte, i flatbuffers.UOffsetT) {
+	rcv._tab.Bytes = buf
+	rcv._tab.Pos = i
+}
+
+func (rcv *InParentNamespace) Table() flatbuffers.Table {
+	return rcv._tab
+}
+
+func InParentNamespaceStart(builder *flatbuffers.Builder) {
+	builder.StartObject(0)
+}
+func InParentNamespaceEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
+	return builder.EndObject()
+}
diff --git a/tests/MyGame/InParentNamespace.java b/tests/MyGame/InParentNamespace.java
new file mode 100644
index 0000000..5ac27c2
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.java
@@ -0,0 +1,24 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")
+public final class InParentNamespace extends Table {
+  public static InParentNamespace getRootAsInParentNamespace(ByteBuffer _bb) { return getRootAsInParentNamespace(_bb, new InParentNamespace()); }
+  public static InParentNamespace getRootAsInParentNamespace(ByteBuffer _bb, InParentNamespace obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+  public InParentNamespace __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+
+  public static void startInParentNamespace(FlatBufferBuilder builder) { builder.startObject(0); }
+  public static int endInParentNamespace(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+}
+
diff --git a/tests/MyGame/InParentNamespace.php b/tests/MyGame/InParentNamespace.php
new file mode 100644
index 0000000..e13a4f3
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.php
@@ -0,0 +1,79 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+namespace MyGame;
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class InParentNamespace extends Table
+{
+    /**
+     * @param ByteBuffer $bb
+     * @return InParentNamespace
+     */
+    public static function getRootAsInParentNamespace(ByteBuffer $bb)
+    {
+        $obj = new InParentNamespace();
+        return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+    }
+
+    public static function InParentNamespaceIdentifier()
+    {
+        return "MONS";
+    }
+
+    public static function InParentNamespaceBufferHasIdentifier(ByteBuffer $buf)
+    {
+        return self::__has_identifier($buf, self::InParentNamespaceIdentifier());
+    }
+
+    public static function InParentNamespaceExtension()
+    {
+        return "mon";
+    }
+
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return InParentNamespace
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return void
+     */
+    public static function startInParentNamespace(FlatBufferBuilder $builder)
+    {
+        $builder->StartObject(0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return InParentNamespace
+     */
+    public static function createInParentNamespace(FlatBufferBuilder $builder, )
+    {
+        $builder->startObject(0);
+        $o = $builder->endObject();
+        return $o;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return int table offset
+     */
+    public static function endInParentNamespace(FlatBufferBuilder $builder)
+    {
+        $o = $builder->endObject();
+        return $o;
+    }
+}
diff --git a/tests/MyGame/InParentNamespace.py b/tests/MyGame/InParentNamespace.py
new file mode 100644
index 0000000..428d9a9
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.py
@@ -0,0 +1,22 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: MyGame
+
+import flatbuffers
+
+class InParentNamespace(object):
+    __slots__ = ['_tab']
+
+    @classmethod
+    def GetRootAsInParentNamespace(cls, buf, offset):
+        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+        x = InParentNamespace()
+        x.Init(buf, n + offset)
+        return x
+
+    # InParentNamespace
+    def Init(self, buf, pos):
+        self._tab = flatbuffers.table.Table(buf, pos)
+
+def InParentNamespaceStart(builder): builder.StartObject(0)
+def InParentNamespaceEnd(builder): return builder.EndObject()
diff --git a/tests/PythonTest.sh b/tests/PythonTest.sh
index 00fee7c..e4dbe8d 100755
--- a/tests/PythonTest.sh
+++ b/tests/PythonTest.sh
@@ -20,7 +20,7 @@
 runtime_library_dir=${test_dir}/../python
 
 # Emit Python code for the example schema in the test dir:
-${test_dir}/../flatc -p -o ${gen_code_path} monster_test.fbs
+${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_test.fbs
 
 # Syntax: run_tests <interpreter> <benchmark vtable dedupes>
 #                   <benchmark read count> <benchmark build count>
diff --git a/tests/TestAll.sh b/tests/TestAll.sh
new file mode 100644
index 0000000..463eb73
--- /dev/null
+++ b/tests/TestAll.sh
@@ -0,0 +1,45 @@
+echo "************************ Java:"
+
+sh JavaTest.sh
+
+echo "************************ Go:"
+
+sh GoTest.sh
+
+echo "************************ Python:"
+
+sh PythonTest.sh
+
+echo "************************ JavaScript:"
+
+sh JavaScriptTest.sh
+sh JavaScriptUnionVectorTest.sh
+
+echo "************************ TypeScript:"
+
+sh TypeScriptTest.sh
+
+echo "************************ C++:"
+
+cd ..
+./flattests
+cd tests
+
+echo "************************ C#:"
+
+cd FlatBuffers.Test
+sh NetTest.sh
+cd ..
+
+echo "************************ PHP:"
+
+php phpTest.php
+sh phpUnionVectorTest.sh
+
+echo "************************ C:"
+
+echo "(in a different repo)"
+
+echo "************************ Swift:"
+
+echo "(in a different repo)"
diff --git a/tests/TypeScriptTest.sh b/tests/TypeScriptTest.sh
new file mode 100755
index 0000000..fa650a4
--- /dev/null
+++ b/tests/TypeScriptTest.sh
@@ -0,0 +1,33 @@
+#!/bin/sh
+#
+# Copyright 2016 Google Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+pushd "$(dirname $0)" >/dev/null
+
+npm install @types/flatbuffers
+
+../flatc --ts --no-fb-import --gen-mutable -o ts -I include_test monster_test.fbs
+../flatc -b -I include_test monster_test.fbs unicode_test.json
+tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/monster_test_generated.ts
+node JavaScriptTest ./ts/monster_test_generated
+
+../flatc --ts --js --no-fb-import -o ts union_vector/union_vector.fbs
+
+# test JS version first, then transpile and rerun for TS
+node JavaScriptUnionVectorTest ./ts/union_vector_generated
+tsc --strict --noUnusedParameters --noUnusedLocals --noImplicitReturns --strictNullChecks ts/union_vector_generated.ts
+node JavaScriptUnionVectorTest ./ts/union_vector_generated
+
+npm uninstall @types/flatbuffers
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index e7660a2..1437c7c 100644
--- a/tests/generate_code.bat
+++ b/tests/generate_code.bat
@@ -15,6 +15,13 @@
 set buildtype=Release
 if "%1"=="-b" set buildtype=%2
 
-..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
-..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
-..\%buildtype%\flatc.exe --binary --schema monster_test.fbs
+..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr  -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
+..\%buildtype%\flatc.exe -b --schema --bfbs-comments -I include_test monster_test.fbs
+..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs
+cd ../samples
+..\%buildtype%\flatc.exe --cpp --gen-mutable --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
+cd ../reflection
+
+cd ../tests
\ No newline at end of file
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index a5354eb..4b6db29 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -14,11 +14,11 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --gen-object-api --no-includes monster_test.fbs monsterdata_test.json
-../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
-../flatc --cpp -o union_vector ./union_vector/union_vector.fbs
-../flatc -b --schema --bfbs-comments monster_test.fbs
+../flatc --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr  --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr  -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
+../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
+../flatc --jsonschema --schema -I include_test monster_test.fbs
 cd ../samples
-../flatc --cpp --gen-mutable --gen-object-api monster.fbs
+../flatc --cpp --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
 cd ../reflection
-sh generate_code.sh
diff --git a/tests/go_test.go b/tests/go_test.go
index 2aa375a..1eb92a0 100644
--- a/tests/go_test.go
+++ b/tests/go_test.go
@@ -715,10 +715,10 @@
 	b.PrependBoolSlot(0, false, false)
 	b.EndObject()
 	check([]byte{
-		6, 0, // vtable bytes
+		4, 0, // vtable bytes
 		4, 0, // end of object from here
-		0, 0, // entry 1 is zero
-		6, 0, 0, 0, // offset for start of vtable (int32)
+		// entry 1 is zero and not stored.
+		4, 0, 0, 0, // offset for start of vtable (int32)
 	})
 
 	// test 10: vtable with one int16
diff --git a/tests/include_test/include_test1.fbs b/tests/include_test/include_test1.fbs
new file mode 100644
index 0000000..804856a
--- /dev/null
+++ b/tests/include_test/include_test1.fbs
@@ -0,0 +1,7 @@
+include "sub/include_test2.fbs";
+include "sub/include_test2.fbs";  // should be skipped
+include "include_test1.fbs";  // should be skipped
+
+table TableA {
+  b:MyGame.OtherNameSpace.TableB;
+}
diff --git a/tests/include_test/sub/include_test2.fbs b/tests/include_test/sub/include_test2.fbs
new file mode 100644
index 0000000..3257ffc
--- /dev/null
+++ b/tests/include_test/sub/include_test2.fbs
@@ -0,0 +1,12 @@
+include "include_test1.fbs";
+include "sub/include_test2.fbs";    // should be skipped
+
+namespace MyGame.OtherNameSpace;
+
+enum FromInclude:long { IncludeVal }
+
+struct Unused {}
+
+table TableB {
+  a:TableA;
+}
diff --git a/tests/include_test1.fbs b/tests/include_test1.fbs
deleted file mode 100644
index 11aebe8..0000000
--- a/tests/include_test1.fbs
+++ /dev/null
@@ -1,5 +0,0 @@
-include "include_test2.fbs";
-include "include_test2.fbs";  // should be skipped
-include "include_test1.fbs";  // should be skipped
-
-
diff --git a/tests/include_test2.fbs b/tests/include_test2.fbs
deleted file mode 100644
index d22c0d9..0000000
--- a/tests/include_test2.fbs
+++ /dev/null
@@ -1,9 +0,0 @@
-include "include_test2.fbs";    // should be skipped
-
-namespace MyGame.OtherNameSpace;
-
-enum FromInclude:long { IncludeVal }
-
-struct Unused {}
-
-
diff --git a/tests/javatest.bin b/tests/javatest.bin
new file mode 100644
index 0000000..77835c7
--- /dev/null
+++ b/tests/javatest.bin
Binary files differ
diff --git a/tests/monster_test.bfbs b/tests/monster_test.bfbs
index 21f3c00..2e247eb 100644
--- a/tests/monster_test.bfbs
+++ b/tests/monster_test.bfbs
Binary files differ
diff --git a/tests/monster_test.fbs b/tests/monster_test.fbs
old mode 100755
new mode 100644
index 050bcea..53493a1
--- a/tests/monster_test.fbs
+++ b/tests/monster_test.fbs
@@ -2,6 +2,10 @@
 
 include "include_test1.fbs";
 
+namespace MyGame;
+
+table InParentNamespace {}
+
 namespace MyGame.Example2;
 
 table Monster {}  // Test having same name as below, but in different namespace.
@@ -29,6 +33,11 @@
   test3:Test;
 }
 
+struct Ability {
+  id:uint(key);
+  distance:uint;
+}
+
 table Stat {
   id:string;
   val:long;
@@ -50,9 +59,11 @@
   testarrayofstring:[string] (id: 10);
   testarrayofstring2:[string] (id: 28);
   testarrayofbools:[bool] (id: 24);
+  testarrayofsortedstruct:[Ability] (id: 29);
   enemy:MyGame.Example.Monster (id:12);  // Test referring by full namespace.
   test:Any (id: 8);
   test4:[Test] (id: 9);
+  test5:[Test] (id: 31);
   testnestedflatbuffer:[ubyte] (id:13, nested_flatbuffer: "Monster");
   testempty:Stat (id:14);
   testbool:bool (id:15);
@@ -67,6 +78,25 @@
   testf:float = 3.14159 (id:25);
   testf2:float = 3 (id:26);
   testf3:float (id:27);
+  flex:[ubyte] (id:30, flexbuffer);
+  vector_of_longs:[long] (id:32);
+  vector_of_doubles:[double] (id:33);
+  parent_namespace_test:InParentNamespace (id:34);
+}
+
+table TypeAliases {
+    i8:int8;
+    u8:uint8;
+    i16:int16;
+    u16:uint16;
+    i32:int32;
+    u32:uint32;
+    i64:int64;
+    u64:uint64;
+    f32:float32;
+    f64:float64;
+    v8:[int8];
+    vf64:[float64];
 }
 
 rpc_service MonsterStorage {
diff --git a/tests/monster_test.grpc.fb.cc b/tests/monster_test.grpc.fb.cc
index c8ed1f5..90b2764 100644
--- a/tests/monster_test.grpc.fb.cc
+++ b/tests/monster_test.grpc.fb.cc
@@ -1,4 +1,4 @@
-// Generated by the gRPC protobuf plugin.
+// Generated by the gRPC C++ plugin.
 // If you make any local change, they will be lost.
 // source: monster_test
 
@@ -13,7 +13,6 @@
 #include <grpc++/impl/codegen/rpc_service_method.h>
 #include <grpc++/impl/codegen/service_type.h>
 #include <grpc++/impl/codegen/sync_stream.h>
-
 namespace MyGame {
 namespace Example {
 
@@ -32,47 +31,46 @@
   , rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::RpcMethod::SERVER_STREAMING, channel)
   {}
   
-::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) {
+::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) {
   return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
 }
 
-::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
-  return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>(channel_.get(), cq, rpcmethod_Store_, context, request);
+::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+  return ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>::Create(channel_.get(), cq, rpcmethod_Store_, context, request);
 }
 
-::grpc::ClientReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) {
-  return new ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>(channel_.get(), rpcmethod_Retrieve_, context, request);
+::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+  return new ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>(channel_.get(), rpcmethod_Retrieve_, context, request);
 }
 
-::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
-  return new ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>(channel_.get(), cq, rpcmethod_Retrieve_, context, request, tag);
+::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+  return ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>::Create(channel_.get(), cq, rpcmethod_Retrieve_, context, request, tag);
 }
 
 MonsterStorage::Service::Service() {
-  (void)MonsterStorage_method_names;
   AddMethod(new ::grpc::RpcServiceMethod(
       MonsterStorage_method_names[0],
       ::grpc::RpcMethod::NORMAL_RPC,
-      new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Monster>, flatbuffers::BufferRef<Stat>>(
+      new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(
           std::mem_fn(&MonsterStorage::Service::Store), this)));
   AddMethod(new ::grpc::RpcServiceMethod(
       MonsterStorage_method_names[1],
       ::grpc::RpcMethod::SERVER_STREAMING,
-      new ::grpc::ServerStreamingHandler< MonsterStorage::Service, flatbuffers::BufferRef<Stat>, flatbuffers::BufferRef<Monster>>(
+      new ::grpc::ServerStreamingHandler< MonsterStorage::Service, flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(
           std::mem_fn(&MonsterStorage::Service::Retrieve), this)));
 }
 
 MonsterStorage::Service::~Service() {
 }
 
-::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) {
+::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) {
   (void) context;
   (void) request;
   (void) response;
   return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
 }
 
-::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) {
+::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) {
   (void) context;
   (void) request;
   (void) writer;
diff --git a/tests/monster_test.grpc.fb.h b/tests/monster_test.grpc.fb.h
index 8228d7a..1942317 100644
--- a/tests/monster_test.grpc.fb.h
+++ b/tests/monster_test.grpc.fb.h
@@ -1,14 +1,16 @@
-// Generated by the gRPC protobuf plugin.
+// Generated by the gRPC C++ plugin.
 // If you make any local change, they will be lost.
 // source: monster_test
 #ifndef GRPC_monster_5ftest__INCLUDED
 #define GRPC_monster_5ftest__INCLUDED
 
-#include "monster_test_generated.h"
 #include "flatbuffers/grpc.h"
+#include "monster_test_generated.h"
 
 #include <grpc++/impl/codegen/async_stream.h>
 #include <grpc++/impl/codegen/async_unary_call.h>
+#include <grpc++/impl/codegen/method_handler_impl.h>
+#include <grpc++/impl/codegen/proto_utils.h>
 #include <grpc++/impl/codegen/rpc_method.h>
 #include <grpc++/impl/codegen/service_type.h>
 #include <grpc++/impl/codegen/status.h>
@@ -26,45 +28,48 @@
 namespace MyGame {
 namespace Example {
 
-class MonsterStorage GRPC_FINAL {
+class MonsterStorage final {
  public:
+  static constexpr char const* service_full_name() {
+    return "MyGame.Example.MonsterStorage";
+  }
   class StubInterface {
    public:
     virtual ~StubInterface() {}
-    virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) = 0;
-    std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
-      return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
+    virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) = 0;
+    std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
     }
-    std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) {
-      return std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>>(RetrieveRaw(context, request));
+    std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+      return std::unique_ptr< ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
     }
-    std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
-      return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
+    std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+      return std::unique_ptr< ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
     }
   private:
-    virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
-    virtual ::grpc::ClientReaderInterface< flatbuffers::BufferRef<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) = 0;
-    virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
+    virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
+    virtual ::grpc::ClientReaderInterface< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) = 0;
+    virtual ::grpc::ClientAsyncReaderInterface< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) = 0;
   };
-  class Stub GRPC_FINAL : public StubInterface {
+  class Stub final : public StubInterface {
    public:
     Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
-    ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) GRPC_OVERRIDE;
-    std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
-      return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
+    ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, flatbuffers::grpc::Message<Stat>* response) override;
+    std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) {
+      return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>>(AsyncStoreRaw(context, request, cq));
     }
-    std::unique_ptr< ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) {
-      return std::unique_ptr< ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>>(RetrieveRaw(context, request));
+    std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>> Retrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) {
+      return std::unique_ptr< ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>>(RetrieveRaw(context, request));
     }
-    std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
-      return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
+    std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) {
+      return std::unique_ptr< ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>>(AsyncRetrieveRaw(context, request, cq, tag));
     }
   
    private:
     std::shared_ptr< ::grpc::ChannelInterface> channel_;
-    ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE;
-    ::grpc::ClientReader< flatbuffers::BufferRef<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request) GRPC_OVERRIDE;
-    ::grpc::ClientAsyncReader< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) GRPC_OVERRIDE;
+    ::grpc::ClientAsyncResponseReader< flatbuffers::grpc::Message<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Monster>& request, ::grpc::CompletionQueue* cq) override;
+    ::grpc::ClientReader< flatbuffers::grpc::Message<Monster>>* RetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request) override;
+    ::grpc::ClientAsyncReader< flatbuffers::grpc::Message<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::grpc::Message<Stat>& request, ::grpc::CompletionQueue* cq, void* tag) override;
     const ::grpc::RpcMethod rpcmethod_Store_;
     const ::grpc::RpcMethod rpcmethod_Retrieve_;
   };
@@ -74,8 +79,8 @@
    public:
     Service();
     virtual ~Service();
-    virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response);
-    virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer);
+    virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response);
+    virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer);
   };
   template <class BaseClass>
   class WithAsyncMethod_Store : public BaseClass {
@@ -85,15 +90,15 @@
     WithAsyncMethod_Store() {
       ::grpc::Service::MarkMethodAsync(0);
     }
-    ~WithAsyncMethod_Store() GRPC_OVERRIDE {
+    ~WithAsyncMethod_Store() override {
       BaseClassMustBeDerivedFromService(this);
     }
     // disable synchronous version of this method
-    ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
+    ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
       abort();
       return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
     }
-    void RequestStore(::grpc::ServerContext* context, flatbuffers::BufferRef<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+    void RequestStore(::grpc::ServerContext* context, flatbuffers::grpc::Message<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::grpc::Message<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
       ::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
     }
   };
@@ -105,15 +110,15 @@
     WithAsyncMethod_Retrieve() {
       ::grpc::Service::MarkMethodAsync(1);
     }
-    ~WithAsyncMethod_Retrieve() GRPC_OVERRIDE {
+    ~WithAsyncMethod_Retrieve() override {
       BaseClassMustBeDerivedFromService(this);
     }
     // disable synchronous version of this method
-    ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) GRPC_FINAL GRPC_OVERRIDE {
+    ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
       abort();
       return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
     }
-    void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::BufferRef<Stat>* request, ::grpc::ServerAsyncWriter< flatbuffers::BufferRef<Monster>>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
+    void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerAsyncWriter< flatbuffers::grpc::Message<Monster>>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
       ::grpc::Service::RequestAsyncServerStreaming(1, context, request, writer, new_call_cq, notification_cq, tag);
     }
   };
@@ -126,11 +131,11 @@
     WithGenericMethod_Store() {
       ::grpc::Service::MarkMethodGeneric(0);
     }
-    ~WithGenericMethod_Store() GRPC_OVERRIDE {
+    ~WithGenericMethod_Store() override {
       BaseClassMustBeDerivedFromService(this);
     }
     // disable synchronous version of this method
-    ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
+    ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
       abort();
       return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
     }
@@ -143,15 +148,58 @@
     WithGenericMethod_Retrieve() {
       ::grpc::Service::MarkMethodGeneric(1);
     }
-    ~WithGenericMethod_Retrieve() GRPC_OVERRIDE {
+    ~WithGenericMethod_Retrieve() override {
       BaseClassMustBeDerivedFromService(this);
     }
     // disable synchronous version of this method
-    ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, ::grpc::ServerWriter< flatbuffers::BufferRef<Monster>>* writer) GRPC_FINAL GRPC_OVERRIDE {
+    ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
       abort();
       return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
     }
   };
+  template <class BaseClass>
+  class WithStreamedUnaryMethod_Store : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service *service) {}
+   public:
+    WithStreamedUnaryMethod_Store() {
+      ::grpc::Service::MarkMethodStreamed(0,
+        new ::grpc::StreamedUnaryHandler< flatbuffers::grpc::Message<Monster>, flatbuffers::grpc::Message<Stat>>(std::bind(&WithStreamedUnaryMethod_Store<BaseClass>::StreamedStore, this, std::placeholders::_1, std::placeholders::_2)));
+    }
+    ~WithStreamedUnaryMethod_Store() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable regular version of this method
+    ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Monster>* request, flatbuffers::grpc::Message<Stat>* response) final override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    // replace default version of method with streamed unary
+    virtual ::grpc::Status StreamedStore(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< flatbuffers::grpc::Message<Monster>,flatbuffers::grpc::Message<Stat>>* server_unary_streamer) = 0;
+  };
+  typedef   WithStreamedUnaryMethod_Store<  Service   >   StreamedUnaryService;
+  template <class BaseClass>
+  class WithSplitStreamingMethod_Retrieve : public BaseClass {
+   private:
+    void BaseClassMustBeDerivedFromService(const Service *service) {}
+   public:
+    WithSplitStreamingMethod_Retrieve() {
+      ::grpc::Service::MarkMethodStreamed(1,
+        new ::grpc::SplitServerStreamingHandler< flatbuffers::grpc::Message<Stat>, flatbuffers::grpc::Message<Monster>>(std::bind(&WithSplitStreamingMethod_Retrieve<BaseClass>::StreamedRetrieve, this, std::placeholders::_1, std::placeholders::_2)));
+    }
+    ~WithSplitStreamingMethod_Retrieve() override {
+      BaseClassMustBeDerivedFromService(this);
+    }
+    // disable regular version of this method
+    ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::grpc::Message<Stat>* request, ::grpc::ServerWriter< flatbuffers::grpc::Message<Monster>>* writer) final override {
+      abort();
+      return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
+    }
+    // replace default version of method with split streamed
+    virtual ::grpc::Status StreamedRetrieve(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< flatbuffers::grpc::Message<Stat>,flatbuffers::grpc::Message<Monster>>* server_split_streamer) = 0;
+  };
+  typedef   WithSplitStreamingMethod_Retrieve<  Service   >   SplitStreamedService;
+  typedef   WithStreamedUnaryMethod_Store<  WithSplitStreamingMethod_Retrieve<  Service   >   >   StreamedService;
 };
 
 }  // namespace Example
diff --git a/tests/monster_test.schema.json b/tests/monster_test.schema.json
new file mode 100644
index 0000000..62880ab
--- /dev/null
+++ b/tests/monster_test.schema.json
@@ -0,0 +1,155 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "definitions": {
+    "MyGame_OtherNameSpace_FromInclude" : {
+      "type" : "string",
+      "enum": ["IncludeVal"]
+    },
+    "MyGame_Example_Color" : {
+      "type" : "string",
+      "enum": ["Red", "Green", "Blue"]
+    },
+    "MyGame_Example_Any" : {
+      "type" : "string",
+      "enum": ["NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster"]
+    },
+    "MyGame_OtherNameSpace_Unused" : {
+      "type" : "object",
+      "properties" : {
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_OtherNameSpace_TableB" : {
+      "type" : "object",
+      "properties" : {
+        "a" : { "$ref" : "#/definitions/TableA" }
+      },
+      "additionalProperties" : false
+    },
+    "TableA" : {
+      "type" : "object",
+      "properties" : {
+        "b" : { "$ref" : "#/definitions/MyGame_OtherNameSpace_TableB" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_InParentNamespace" : {
+      "type" : "object",
+      "properties" : {
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example2_Monster" : {
+      "type" : "object",
+      "properties" : {
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_Test" : {
+      "type" : "object",
+      "properties" : {
+        "a" : { "type" : "number" },
+        "b" : { "type" : "number" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_TestSimpleTableWithEnum" : {
+      "type" : "object",
+      "properties" : {
+        "color" : { "$ref" : "#/definitions/MyGame_Example_Color" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_Vec3" : {
+      "type" : "object",
+      "properties" : {
+        "x" : { "type" : "number" },
+        "y" : { "type" : "number" },
+        "z" : { "type" : "number" },
+        "test1" : { "type" : "number" },
+        "test2" : { "$ref" : "#/definitions/MyGame_Example_Color" },
+        "test3" : { "$ref" : "#/definitions/MyGame_Example_Test" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_Ability" : {
+      "type" : "object",
+      "properties" : {
+        "id" : { "type" : "number" },
+        "distance" : { "type" : "number" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_Stat" : {
+      "type" : "object",
+      "properties" : {
+        "id" : { "type" : "string" },
+        "val" : { "type" : "number" },
+        "count" : { "type" : "number" }
+      },
+      "additionalProperties" : false
+    },
+    "MyGame_Example_Monster" : {
+      "type" : "object",
+      "description" : " an example documentation comment: monster object",
+      "properties" : {
+        "pos" : { "$ref" : "#/definitions/MyGame_Example_Vec3" },
+        "mana" : { "type" : "number" },
+        "hp" : { "type" : "number" },
+        "name" : { "type" : "string" },
+        "friendly" : { "type" : "boolean" },
+        "inventory" : { "type" : "array", "items" : { "type" : "number" } },
+        "color" : { "$ref" : "#/definitions/MyGame_Example_Color" },
+        "test_type" : { "$ref" : "#/definitions/MyGame_Example_Any" },
+        "test" : { "anyOf": [{ "$ref" : "#/definitions/MyGame_Example_Monster" },{ "$ref" : "#/definitions/MyGame_Example_TestSimpleTableWithEnum" },{ "$ref" : "#/definitions/MyGame_Example2_Monster" }] },
+        "test4" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" } },
+        "testarrayofstring" : { "type" : "array", "items" : { "type" : "string" } },
+        "testarrayoftables" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Monster" } },
+        "enemy" : { "$ref" : "#/definitions/MyGame_Example_Monster" },
+        "testnestedflatbuffer" : { "type" : "array", "items" : { "type" : "number" } },
+        "testempty" : { "$ref" : "#/definitions/MyGame_Example_Stat" },
+        "testbool" : { "type" : "boolean" },
+        "testhashs32_fnv1" : { "type" : "number" },
+        "testhashu32_fnv1" : { "type" : "number" },
+        "testhashs64_fnv1" : { "type" : "number" },
+        "testhashu64_fnv1" : { "type" : "number" },
+        "testhashs32_fnv1a" : { "type" : "number" },
+        "testhashu32_fnv1a" : { "type" : "number" },
+        "testhashs64_fnv1a" : { "type" : "number" },
+        "testhashu64_fnv1a" : { "type" : "number" },
+        "testarrayofbools" : { "type" : "array", "items" : { "type" : "boolean" } },
+        "testf" : { "type" : "number" },
+        "testf2" : { "type" : "number" },
+        "testf3" : { "type" : "number" },
+        "testarrayofstring2" : { "type" : "array", "items" : { "type" : "string" } },
+        "testarrayofsortedstruct" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Ability" } },
+        "flex" : { "type" : "array", "items" : { "type" : "number" } },
+        "test5" : { "type" : "array", "items" : { "$ref" : "#/definitions/MyGame_Example_Test" } },
+        "vector_of_longs" : { "type" : "array", "items" : { "type" : "number" } },
+        "vector_of_doubles" : { "type" : "array", "items" : { "type" : "number" } },
+        "parent_namespace_test" : { "$ref" : "#/definitions/MyGame_InParentNamespace" }
+      },
+      "required" : ["name"],
+      "additionalProperties" : false
+    },
+    "MyGame_Example_TypeAliases" : {
+      "type" : "object",
+      "properties" : {
+        "i8" : { "type" : "number" },
+        "u8" : { "type" : "number" },
+        "i16" : { "type" : "number" },
+        "u16" : { "type" : "number" },
+        "i32" : { "type" : "number" },
+        "u32" : { "type" : "number" },
+        "i64" : { "type" : "number" },
+        "u64" : { "type" : "number" },
+        "f32" : { "type" : "number" },
+        "f64" : { "type" : "number" },
+        "v8" : { "type" : "array", "items" : { "type" : "number" } },
+        "vf64" : { "type" : "array", "items" : { "type" : "number" } }
+      },
+      "additionalProperties" : false
+    }
+  },
+  "$ref" : "#/definitions/MyGame_Example_Monster"
+}
diff --git a/tests/monster_test_generated.h b/tests/monster_test_generated.h
index ee94536..14a2ae8 100644
--- a/tests/monster_test_generated.h
+++ b/tests/monster_test_generated.h
@@ -5,8 +5,13 @@
 #define FLATBUFFERS_GENERATED_MONSTERTEST_MYGAME_EXAMPLE_H_
 
 #include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/flexbuffers.h"
 
 namespace MyGame {
+
+struct InParentNamespace;
+struct InParentNamespaceT;
+
 namespace Example2 {
 
 struct Monster;
@@ -23,12 +28,17 @@
 
 struct Vec3;
 
+struct Ability;
+
 struct Stat;
 struct StatT;
 
 struct Monster;
 struct MonsterT;
 
+struct TypeAliases;
+struct TypeAliasesT;
+
 enum Color {
   Color_Red = 1,
   Color_Green = 2,
@@ -37,6 +47,15 @@
   Color_ANY = 11
 };
 
+inline Color (&EnumValuesColor())[3] {
+  static Color values[] = {
+    Color_Red,
+    Color_Green,
+    Color_Blue
+  };
+  return values;
+}
+
 inline const char **EnumNamesColor() {
   static const char *names[] = {
     "Red",
@@ -66,6 +85,16 @@
   Any_MAX = Any_MyGame_Example2_Monster
 };
 
+inline Any (&EnumValuesAny())[4] {
+  static Any values[] = {
+    Any_NONE,
+    Any_Monster,
+    Any_TestSimpleTableWithEnum,
+    Any_MyGame_Example2_Monster
+  };
+  return values;
+}
+
 inline const char **EnumNamesAny() {
   static const char *names[] = {
     "NONE",
@@ -100,40 +129,58 @@
 
 struct AnyUnion {
   Any type;
-  flatbuffers::NativeTable *table;
+  void *value;
 
-  AnyUnion() : type(Any_NONE), table(nullptr) {}
-  AnyUnion(AnyUnion&& u):
-    type(std::move(u.type)), table(std::move(u.table)) {}
-  AnyUnion(const AnyUnion &);
-  AnyUnion &operator=(const AnyUnion &);
+  AnyUnion() : type(Any_NONE), value(nullptr) {}
+  AnyUnion(AnyUnion&& u) FLATBUFFERS_NOEXCEPT :
+    type(Any_NONE), value(nullptr)
+    { std::swap(type, u.type); std::swap(value, u.value); }
+  AnyUnion(const AnyUnion &) FLATBUFFERS_NOEXCEPT;
+  AnyUnion &operator=(const AnyUnion &u) FLATBUFFERS_NOEXCEPT
+    { AnyUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+  AnyUnion &operator=(AnyUnion &&u) FLATBUFFERS_NOEXCEPT
+    { std::swap(type, u.type); std::swap(value, u.value); return *this; }
   ~AnyUnion() { Reset(); }
 
   void Reset();
 
+#ifndef FLATBUFFERS_CPP98_STL
   template <typename T>
-  void Set(T&& value) {
+  void Set(T&& val) {
     Reset();
     type = AnyTraits<typename T::TableType>::enum_value;
     if (type != Any_NONE) {
-      table = new T(std::forward<T>(value));
+      value = new T(std::forward<T>(val));
     }
   }
+#endif  // FLATBUFFERS_CPP98_STL
 
-  static flatbuffers::NativeTable *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
+  static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
   flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
 
   MonsterT *AsMonster() {
     return type == Any_Monster ?
-      reinterpret_cast<MonsterT *>(table) : nullptr;
+      reinterpret_cast<MonsterT *>(value) : nullptr;
+  }
+  const MonsterT *AsMonster() const {
+    return type == Any_Monster ?
+      reinterpret_cast<const MonsterT *>(value) : nullptr;
   }
   TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() {
     return type == Any_TestSimpleTableWithEnum ?
-      reinterpret_cast<TestSimpleTableWithEnumT *>(table) : nullptr;
+      reinterpret_cast<TestSimpleTableWithEnumT *>(value) : nullptr;
+  }
+  const TestSimpleTableWithEnumT *AsTestSimpleTableWithEnum() const {
+    return type == Any_TestSimpleTableWithEnum ?
+      reinterpret_cast<const TestSimpleTableWithEnumT *>(value) : nullptr;
   }
   MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() {
     return type == Any_MyGame_Example2_Monster ?
-      reinterpret_cast<MyGame::Example2::MonsterT *>(table) : nullptr;
+      reinterpret_cast<MyGame::Example2::MonsterT *>(value) : nullptr;
+  }
+  const MyGame::Example2::MonsterT *AsMyGame_Example2_Monster() const {
+    return type == Any_MyGame_Example2_Monster ?
+      reinterpret_cast<const MyGame::Example2::MonsterT *>(value) : nullptr;
   }
 };
 
@@ -150,9 +197,6 @@
   Test() {
     memset(this, 0, sizeof(Test));
   }
-  Test(const Test &_o) {
-    memcpy(this, &_o, sizeof(Test));
-  }
   Test(int16_t _a, int8_t _b)
       : a_(flatbuffers::EndianScalar(_a)),
         b_(flatbuffers::EndianScalar(_b)),
@@ -190,9 +234,6 @@
   Vec3() {
     memset(this, 0, sizeof(Vec3));
   }
-  Vec3(const Vec3 &_o) {
-    memcpy(this, &_o, sizeof(Vec3));
-  }
   Vec3(float _x, float _y, float _z, double _test1, Color _test2, const Test &_test3)
       : x_(flatbuffers::EndianScalar(_x)),
         y_(flatbuffers::EndianScalar(_y)),
@@ -240,14 +281,89 @@
   const Test &test3() const {
     return test3_;
   }
-  const Test &mutable_test3() {
+  Test &mutable_test3() {
     return test3_;
   }
 };
 STRUCT_END(Vec3, 32);
 
+MANUALLY_ALIGNED_STRUCT(4) Ability FLATBUFFERS_FINAL_CLASS {
+ private:
+  uint32_t id_;
+  uint32_t distance_;
+
+ public:
+  Ability() {
+    memset(this, 0, sizeof(Ability));
+  }
+  Ability(uint32_t _id, uint32_t _distance)
+      : id_(flatbuffers::EndianScalar(_id)),
+        distance_(flatbuffers::EndianScalar(_distance)) {
+  }
+  uint32_t id() const {
+    return flatbuffers::EndianScalar(id_);
+  }
+  void mutate_id(uint32_t _id) {
+    flatbuffers::WriteScalar(&id_, _id);
+  }
+  bool KeyCompareLessThan(const Ability *o) const {
+    return id() < o->id();
+  }
+  int KeyCompareWithValue(uint32_t val) const {
+    const auto key = id();
+    return static_cast<int>(key > val) - static_cast<int>(key < val);
+  }
+  uint32_t distance() const {
+    return flatbuffers::EndianScalar(distance_);
+  }
+  void mutate_distance(uint32_t _distance) {
+    flatbuffers::WriteScalar(&distance_, _distance);
+  }
+};
+STRUCT_END(Ability, 8);
+
 }  // namespace Example
 
+struct InParentNamespaceT : public flatbuffers::NativeTable {
+  typedef InParentNamespace TableType;
+  InParentNamespaceT() {
+  }
+};
+
+struct InParentNamespace FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef InParentNamespaceT NativeTableType;
+  bool Verify(flatbuffers::Verifier &verifier) const {
+    return VerifyTableStart(verifier) &&
+           verifier.EndTable();
+  }
+  InParentNamespaceT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(InParentNamespaceT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<InParentNamespace> Pack(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct InParentNamespaceBuilder {
+  flatbuffers::FlatBufferBuilder &fbb_;
+  flatbuffers::uoffset_t start_;
+  explicit InParentNamespaceBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+        : fbb_(_fbb) {
+    start_ = fbb_.StartTable();
+  }
+  InParentNamespaceBuilder &operator=(const InParentNamespaceBuilder &);
+  flatbuffers::Offset<InParentNamespace> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<InParentNamespace>(end);
+    return o;
+  }
+};
+
+inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(
+    flatbuffers::FlatBufferBuilder &_fbb) {
+  InParentNamespaceBuilder builder_(_fbb);
+  return builder_.Finish();
+}
+
+flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
 namespace Example2 {
 
 struct MonsterT : public flatbuffers::NativeTable {
@@ -270,13 +386,13 @@
 struct MonsterBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
-  MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   MonsterBuilder &operator=(const MonsterBuilder &);
   flatbuffers::Offset<Monster> Finish() {
-    const auto end = fbb_.EndTable(start_, 0);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Monster>(end);
     return o;
   }
@@ -311,7 +427,7 @@
     return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2));
   }
   bool mutate_color(Color _color) {
-    return SetField(VT_COLOR, static_cast<int8_t>(_color));
+    return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 2);
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
@@ -329,13 +445,13 @@
   void add_color(Color color) {
     fbb_.AddElement<int8_t>(TestSimpleTableWithEnum::VT_COLOR, static_cast<int8_t>(color), 2);
   }
-  TestSimpleTableWithEnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit TestSimpleTableWithEnumBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   TestSimpleTableWithEnumBuilder &operator=(const TestSimpleTableWithEnumBuilder &);
   flatbuffers::Offset<TestSimpleTableWithEnum> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<TestSimpleTableWithEnum>(end);
     return o;
   }
@@ -379,17 +495,17 @@
     return GetField<int64_t>(VT_VAL, 0);
   }
   bool mutate_val(int64_t _val) {
-    return SetField(VT_VAL, _val);
+    return SetField<int64_t>(VT_VAL, _val, 0);
   }
   uint16_t count() const {
     return GetField<uint16_t>(VT_COUNT, 0);
   }
   bool mutate_count(uint16_t _count) {
-    return SetField(VT_COUNT, _count);
+    return SetField<uint16_t>(VT_COUNT, _count, 0);
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ID) &&
+           VerifyOffset(verifier, VT_ID) &&
            verifier.Verify(id()) &&
            VerifyField<int64_t>(verifier, VT_VAL) &&
            VerifyField<uint16_t>(verifier, VT_COUNT) &&
@@ -412,13 +528,13 @@
   void add_count(uint16_t count) {
     fbb_.AddElement<uint16_t>(Stat::VT_COUNT, count, 0);
   }
-  StatBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit StatBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   StatBuilder &operator=(const StatBuilder &);
   flatbuffers::Offset<Stat> Finish() {
-    const auto end = fbb_.EndTable(start_, 3);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Stat>(end);
     return o;
   }
@@ -452,7 +568,7 @@
 
 struct MonsterT : public flatbuffers::NativeTable {
   typedef Monster TableType;
-  std::unique_ptr<Vec3> pos;
+  flatbuffers::unique_ptr<Vec3> pos;
   int16_t mana;
   int16_t hp;
   std::string name;
@@ -461,10 +577,10 @@
   AnyUnion test;
   std::vector<Test> test4;
   std::vector<std::string> testarrayofstring;
-  std::vector<std::unique_ptr<MonsterT>> testarrayoftables;
-  std::unique_ptr<MonsterT> enemy;
+  std::vector<flatbuffers::unique_ptr<MonsterT>> testarrayoftables;
+  flatbuffers::unique_ptr<MonsterT> enemy;
   std::vector<uint8_t> testnestedflatbuffer;
-  std::unique_ptr<StatT> testempty;
+  flatbuffers::unique_ptr<StatT> testempty;
   bool testbool;
   int32_t testhashs32_fnv1;
   uint32_t testhashu32_fnv1;
@@ -479,6 +595,12 @@
   float testf2;
   float testf3;
   std::vector<std::string> testarrayofstring2;
+  std::vector<Ability> testarrayofsortedstruct;
+  std::vector<uint8_t> flex;
+  std::vector<Test> test5;
+  std::vector<int64_t> vector_of_longs;
+  std::vector<double> vector_of_doubles;
+  flatbuffers::unique_ptr<MyGame::InParentNamespaceT> parent_namespace_test;
   MonsterT()
       : mana(150),
         hp(100),
@@ -529,7 +651,13 @@
     VT_TESTF = 54,
     VT_TESTF2 = 56,
     VT_TESTF3 = 58,
-    VT_TESTARRAYOFSTRING2 = 60
+    VT_TESTARRAYOFSTRING2 = 60,
+    VT_TESTARRAYOFSORTEDSTRUCT = 62,
+    VT_FLEX = 64,
+    VT_TEST5 = 66,
+    VT_VECTOR_OF_LONGS = 68,
+    VT_VECTOR_OF_DOUBLES = 70,
+    VT_PARENT_NAMESPACE_TEST = 72
   };
   const Vec3 *pos() const {
     return GetStruct<const Vec3 *>(VT_POS);
@@ -541,13 +669,13 @@
     return GetField<int16_t>(VT_MANA, 150);
   }
   bool mutate_mana(int16_t _mana) {
-    return SetField(VT_MANA, _mana);
+    return SetField<int16_t>(VT_MANA, _mana, 150);
   }
   int16_t hp() const {
     return GetField<int16_t>(VT_HP, 100);
   }
   bool mutate_hp(int16_t _hp) {
-    return SetField(VT_HP, _hp);
+    return SetField<int16_t>(VT_HP, _hp, 100);
   }
   const flatbuffers::String *name() const {
     return GetPointer<const flatbuffers::String *>(VT_NAME);
@@ -571,17 +699,27 @@
     return static_cast<Color>(GetField<int8_t>(VT_COLOR, 8));
   }
   bool mutate_color(Color _color) {
-    return SetField(VT_COLOR, static_cast<int8_t>(_color));
+    return SetField<int8_t>(VT_COLOR, static_cast<int8_t>(_color), 8);
   }
   Any test_type() const {
     return static_cast<Any>(GetField<uint8_t>(VT_TEST_TYPE, 0));
   }
   bool mutate_test_type(Any _test_type) {
-    return SetField(VT_TEST_TYPE, static_cast<uint8_t>(_test_type));
+    return SetField<uint8_t>(VT_TEST_TYPE, static_cast<uint8_t>(_test_type), 0);
   }
   const void *test() const {
     return GetPointer<const void *>(VT_TEST);
   }
+  template<typename T> const T *test_as() const;
+  const Monster *test_as_Monster() const {
+    return test_type() == Any_Monster ? static_cast<const Monster *>(test()) : nullptr;
+  }
+  const TestSimpleTableWithEnum *test_as_TestSimpleTableWithEnum() const {
+    return test_type() == Any_TestSimpleTableWithEnum ? static_cast<const TestSimpleTableWithEnum *>(test()) : nullptr;
+  }
+  const MyGame::Example2::Monster *test_as_MyGame_Example2_Monster() const {
+    return test_type() == Any_MyGame_Example2_Monster ? static_cast<const MyGame::Example2::Monster *>(test()) : nullptr;
+  }
   void *mutable_test() {
     return GetPointer<void *>(VT_TEST);
   }
@@ -618,7 +756,7 @@
     return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_TESTNESTEDFLATBUFFER);
   }
   const MyGame::Example::Monster *testnestedflatbuffer_nested_root() const {
-    const uint8_t* data = testnestedflatbuffer()->Data();
+    auto data = testnestedflatbuffer()->Data();
     return flatbuffers::GetRoot<MyGame::Example::Monster>(data);
   }
   const Stat *testempty() const {
@@ -631,55 +769,55 @@
     return GetField<uint8_t>(VT_TESTBOOL, 0) != 0;
   }
   bool mutate_testbool(bool _testbool) {
-    return SetField(VT_TESTBOOL, static_cast<uint8_t>(_testbool));
+    return SetField<uint8_t>(VT_TESTBOOL, static_cast<uint8_t>(_testbool), 0);
   }
   int32_t testhashs32_fnv1() const {
     return GetField<int32_t>(VT_TESTHASHS32_FNV1, 0);
   }
   bool mutate_testhashs32_fnv1(int32_t _testhashs32_fnv1) {
-    return SetField(VT_TESTHASHS32_FNV1, _testhashs32_fnv1);
+    return SetField<int32_t>(VT_TESTHASHS32_FNV1, _testhashs32_fnv1, 0);
   }
   uint32_t testhashu32_fnv1() const {
     return GetField<uint32_t>(VT_TESTHASHU32_FNV1, 0);
   }
   bool mutate_testhashu32_fnv1(uint32_t _testhashu32_fnv1) {
-    return SetField(VT_TESTHASHU32_FNV1, _testhashu32_fnv1);
+    return SetField<uint32_t>(VT_TESTHASHU32_FNV1, _testhashu32_fnv1, 0);
   }
   int64_t testhashs64_fnv1() const {
     return GetField<int64_t>(VT_TESTHASHS64_FNV1, 0);
   }
   bool mutate_testhashs64_fnv1(int64_t _testhashs64_fnv1) {
-    return SetField(VT_TESTHASHS64_FNV1, _testhashs64_fnv1);
+    return SetField<int64_t>(VT_TESTHASHS64_FNV1, _testhashs64_fnv1, 0);
   }
   uint64_t testhashu64_fnv1() const {
     return GetField<uint64_t>(VT_TESTHASHU64_FNV1, 0);
   }
   bool mutate_testhashu64_fnv1(uint64_t _testhashu64_fnv1) {
-    return SetField(VT_TESTHASHU64_FNV1, _testhashu64_fnv1);
+    return SetField<uint64_t>(VT_TESTHASHU64_FNV1, _testhashu64_fnv1, 0);
   }
   int32_t testhashs32_fnv1a() const {
     return GetField<int32_t>(VT_TESTHASHS32_FNV1A, 0);
   }
   bool mutate_testhashs32_fnv1a(int32_t _testhashs32_fnv1a) {
-    return SetField(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a);
+    return SetField<int32_t>(VT_TESTHASHS32_FNV1A, _testhashs32_fnv1a, 0);
   }
   uint32_t testhashu32_fnv1a() const {
     return GetField<uint32_t>(VT_TESTHASHU32_FNV1A, 0);
   }
   bool mutate_testhashu32_fnv1a(uint32_t _testhashu32_fnv1a) {
-    return SetField(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a);
+    return SetField<uint32_t>(VT_TESTHASHU32_FNV1A, _testhashu32_fnv1a, 0);
   }
   int64_t testhashs64_fnv1a() const {
     return GetField<int64_t>(VT_TESTHASHS64_FNV1A, 0);
   }
   bool mutate_testhashs64_fnv1a(int64_t _testhashs64_fnv1a) {
-    return SetField(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a);
+    return SetField<int64_t>(VT_TESTHASHS64_FNV1A, _testhashs64_fnv1a, 0);
   }
   uint64_t testhashu64_fnv1a() const {
     return GetField<uint64_t>(VT_TESTHASHU64_FNV1A, 0);
   }
   bool mutate_testhashu64_fnv1a(uint64_t _testhashu64_fnv1a) {
-    return SetField(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a);
+    return SetField<uint64_t>(VT_TESTHASHU64_FNV1A, _testhashu64_fnv1a, 0);
   }
   const flatbuffers::Vector<uint8_t> *testarrayofbools() const {
     return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_TESTARRAYOFBOOLS);
@@ -691,19 +829,19 @@
     return GetField<float>(VT_TESTF, 3.14159f);
   }
   bool mutate_testf(float _testf) {
-    return SetField(VT_TESTF, _testf);
+    return SetField<float>(VT_TESTF, _testf, 3.14159f);
   }
   float testf2() const {
     return GetField<float>(VT_TESTF2, 3.0f);
   }
   bool mutate_testf2(float _testf2) {
-    return SetField(VT_TESTF2, _testf2);
+    return SetField<float>(VT_TESTF2, _testf2, 3.0f);
   }
   float testf3() const {
     return GetField<float>(VT_TESTF3, 0.0f);
   }
   bool mutate_testf3(float _testf3) {
-    return SetField(VT_TESTF3, _testf3);
+    return SetField<float>(VT_TESTF3, _testf3, 0.0f);
   }
   const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const {
     return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
@@ -711,32 +849,72 @@
   flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() {
     return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2);
   }
+  const flatbuffers::Vector<const Ability *> *testarrayofsortedstruct() const {
+    return GetPointer<const flatbuffers::Vector<const Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
+  }
+  flatbuffers::Vector<const Ability *> *mutable_testarrayofsortedstruct() {
+    return GetPointer<flatbuffers::Vector<const Ability *> *>(VT_TESTARRAYOFSORTEDSTRUCT);
+  }
+  const flatbuffers::Vector<uint8_t> *flex() const {
+    return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_FLEX);
+  }
+  flatbuffers::Vector<uint8_t> *mutable_flex() {
+    return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_FLEX);
+  }
+  flexbuffers::Reference flex_flexbuffer_root() const {
+    auto v = flex();
+    return flexbuffers::GetRoot(v->Data(), v->size());
+  }
+  const flatbuffers::Vector<const Test *> *test5() const {
+    return GetPointer<const flatbuffers::Vector<const Test *> *>(VT_TEST5);
+  }
+  flatbuffers::Vector<const Test *> *mutable_test5() {
+    return GetPointer<flatbuffers::Vector<const Test *> *>(VT_TEST5);
+  }
+  const flatbuffers::Vector<int64_t> *vector_of_longs() const {
+    return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+  }
+  flatbuffers::Vector<int64_t> *mutable_vector_of_longs() {
+    return GetPointer<flatbuffers::Vector<int64_t> *>(VT_VECTOR_OF_LONGS);
+  }
+  const flatbuffers::Vector<double> *vector_of_doubles() const {
+    return GetPointer<const flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+  }
+  flatbuffers::Vector<double> *mutable_vector_of_doubles() {
+    return GetPointer<flatbuffers::Vector<double> *>(VT_VECTOR_OF_DOUBLES);
+  }
+  const MyGame::InParentNamespace *parent_namespace_test() const {
+    return GetPointer<const MyGame::InParentNamespace *>(VT_PARENT_NAMESPACE_TEST);
+  }
+  MyGame::InParentNamespace *mutable_parent_namespace_test() {
+    return GetPointer<MyGame::InParentNamespace *>(VT_PARENT_NAMESPACE_TEST);
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<Vec3>(verifier, VT_POS) &&
            VerifyField<int16_t>(verifier, VT_MANA) &&
            VerifyField<int16_t>(verifier, VT_HP) &&
-           VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_NAME) &&
+           VerifyOffsetRequired(verifier, VT_NAME) &&
            verifier.Verify(name()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_INVENTORY) &&
+           VerifyOffset(verifier, VT_INVENTORY) &&
            verifier.Verify(inventory()) &&
            VerifyField<int8_t>(verifier, VT_COLOR) &&
            VerifyField<uint8_t>(verifier, VT_TEST_TYPE) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TEST) &&
+           VerifyOffset(verifier, VT_TEST) &&
            VerifyAny(verifier, test(), test_type()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TEST4) &&
+           VerifyOffset(verifier, VT_TEST4) &&
            verifier.Verify(test4()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING) &&
+           VerifyOffset(verifier, VT_TESTARRAYOFSTRING) &&
            verifier.Verify(testarrayofstring()) &&
            verifier.VerifyVectorOfStrings(testarrayofstring()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFTABLES) &&
+           VerifyOffset(verifier, VT_TESTARRAYOFTABLES) &&
            verifier.Verify(testarrayoftables()) &&
            verifier.VerifyVectorOfTables(testarrayoftables()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_ENEMY) &&
+           VerifyOffset(verifier, VT_ENEMY) &&
            verifier.VerifyTable(enemy()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTNESTEDFLATBUFFER) &&
+           VerifyOffset(verifier, VT_TESTNESTEDFLATBUFFER) &&
            verifier.Verify(testnestedflatbuffer()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTEMPTY) &&
+           VerifyOffset(verifier, VT_TESTEMPTY) &&
            verifier.VerifyTable(testempty()) &&
            VerifyField<uint8_t>(verifier, VT_TESTBOOL) &&
            VerifyField<int32_t>(verifier, VT_TESTHASHS32_FNV1) &&
@@ -747,14 +925,26 @@
            VerifyField<uint32_t>(verifier, VT_TESTHASHU32_FNV1A) &&
            VerifyField<int64_t>(verifier, VT_TESTHASHS64_FNV1A) &&
            VerifyField<uint64_t>(verifier, VT_TESTHASHU64_FNV1A) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFBOOLS) &&
+           VerifyOffset(verifier, VT_TESTARRAYOFBOOLS) &&
            verifier.Verify(testarrayofbools()) &&
            VerifyField<float>(verifier, VT_TESTF) &&
            VerifyField<float>(verifier, VT_TESTF2) &&
            VerifyField<float>(verifier, VT_TESTF3) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING2) &&
+           VerifyOffset(verifier, VT_TESTARRAYOFSTRING2) &&
            verifier.Verify(testarrayofstring2()) &&
            verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
+           VerifyOffset(verifier, VT_TESTARRAYOFSORTEDSTRUCT) &&
+           verifier.Verify(testarrayofsortedstruct()) &&
+           VerifyOffset(verifier, VT_FLEX) &&
+           verifier.Verify(flex()) &&
+           VerifyOffset(verifier, VT_TEST5) &&
+           verifier.Verify(test5()) &&
+           VerifyOffset(verifier, VT_VECTOR_OF_LONGS) &&
+           verifier.Verify(vector_of_longs()) &&
+           VerifyOffset(verifier, VT_VECTOR_OF_DOUBLES) &&
+           verifier.Verify(vector_of_doubles()) &&
+           VerifyOffset(verifier, VT_PARENT_NAMESPACE_TEST) &&
+           verifier.VerifyTable(parent_namespace_test()) &&
            verifier.EndTable();
   }
   MonsterT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -762,6 +952,18 @@
   static flatbuffers::Offset<Monster> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 };
 
+template<> inline const Monster *Monster::test_as<Monster>() const {
+  return test_as_Monster();
+}
+
+template<> inline const TestSimpleTableWithEnum *Monster::test_as<TestSimpleTableWithEnum>() const {
+  return test_as_TestSimpleTableWithEnum();
+}
+
+template<> inline const MyGame::Example2::Monster *Monster::test_as<MyGame::Example2::Monster>() const {
+  return test_as_MyGame_Example2_Monster();
+}
+
 struct MonsterBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
@@ -849,13 +1051,31 @@
   void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) {
     fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2);
   }
-  MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  void add_testarrayofsortedstruct(flatbuffers::Offset<flatbuffers::Vector<const Ability *>> testarrayofsortedstruct) {
+    fbb_.AddOffset(Monster::VT_TESTARRAYOFSORTEDSTRUCT, testarrayofsortedstruct);
+  }
+  void add_flex(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex) {
+    fbb_.AddOffset(Monster::VT_FLEX, flex);
+  }
+  void add_test5(flatbuffers::Offset<flatbuffers::Vector<const Test *>> test5) {
+    fbb_.AddOffset(Monster::VT_TEST5, test5);
+  }
+  void add_vector_of_longs(flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs) {
+    fbb_.AddOffset(Monster::VT_VECTOR_OF_LONGS, vector_of_longs);
+  }
+  void add_vector_of_doubles(flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles) {
+    fbb_.AddOffset(Monster::VT_VECTOR_OF_DOUBLES, vector_of_doubles);
+  }
+  void add_parent_namespace_test(flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test) {
+    fbb_.AddOffset(Monster::VT_PARENT_NAMESPACE_TEST, parent_namespace_test);
+  }
+  explicit MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   MonsterBuilder &operator=(const MonsterBuilder &);
   flatbuffers::Offset<Monster> Finish() {
-    const auto end = fbb_.EndTable(start_, 29);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Monster>(end);
     fbb_.Required(o, Monster::VT_NAME);
     return o;
@@ -891,12 +1111,24 @@
     float testf = 3.14159f,
     float testf2 = 3.0f,
     float testf3 = 0.0f,
-    flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0) {
+    flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0,
+    flatbuffers::Offset<flatbuffers::Vector<const Ability *>> testarrayofsortedstruct = 0,
+    flatbuffers::Offset<flatbuffers::Vector<uint8_t>> flex = 0,
+    flatbuffers::Offset<flatbuffers::Vector<const Test *>> test5 = 0,
+    flatbuffers::Offset<flatbuffers::Vector<int64_t>> vector_of_longs = 0,
+    flatbuffers::Offset<flatbuffers::Vector<double>> vector_of_doubles = 0,
+    flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test = 0) {
   MonsterBuilder builder_(_fbb);
   builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
   builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
   builder_.add_testhashu64_fnv1(testhashu64_fnv1);
   builder_.add_testhashs64_fnv1(testhashs64_fnv1);
+  builder_.add_parent_namespace_test(parent_namespace_test);
+  builder_.add_vector_of_doubles(vector_of_doubles);
+  builder_.add_vector_of_longs(vector_of_longs);
+  builder_.add_test5(test5);
+  builder_.add_flex(flex);
+  builder_.add_testarrayofsortedstruct(testarrayofsortedstruct);
   builder_.add_testarrayofstring2(testarrayofstring2);
   builder_.add_testf3(testf3);
   builder_.add_testf2(testf2);
@@ -953,7 +1185,13 @@
     float testf = 3.14159f,
     float testf2 = 3.0f,
     float testf3 = 0.0f,
-    const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr) {
+    const std::vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2 = nullptr,
+    const std::vector<const Ability *> *testarrayofsortedstruct = nullptr,
+    const std::vector<uint8_t> *flex = nullptr,
+    const std::vector<const Test *> *test5 = nullptr,
+    const std::vector<int64_t> *vector_of_longs = nullptr,
+    const std::vector<double> *vector_of_doubles = nullptr,
+    flatbuffers::Offset<MyGame::InParentNamespace> parent_namespace_test = 0) {
   return MyGame::Example::CreateMonster(
       _fbb,
       pos,
@@ -983,13 +1221,294 @@
       testf,
       testf2,
       testf3,
-      testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0);
+      testarrayofstring2 ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*testarrayofstring2) : 0,
+      testarrayofsortedstruct ? _fbb.CreateVector<const Ability *>(*testarrayofsortedstruct) : 0,
+      flex ? _fbb.CreateVector<uint8_t>(*flex) : 0,
+      test5 ? _fbb.CreateVector<const Test *>(*test5) : 0,
+      vector_of_longs ? _fbb.CreateVector<int64_t>(*vector_of_longs) : 0,
+      vector_of_doubles ? _fbb.CreateVector<double>(*vector_of_doubles) : 0,
+      parent_namespace_test);
 }
 
 flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 
+struct TypeAliasesT : public flatbuffers::NativeTable {
+  typedef TypeAliases TableType;
+  int8_t i8;
+  uint8_t u8;
+  int16_t i16;
+  uint16_t u16;
+  int32_t i32;
+  uint32_t u32;
+  int64_t i64;
+  uint64_t u64;
+  float f32;
+  double f64;
+  std::vector<int8_t> v8;
+  std::vector<double> vf64;
+  TypeAliasesT()
+      : i8(0),
+        u8(0),
+        i16(0),
+        u16(0),
+        i32(0),
+        u32(0),
+        i64(0),
+        u64(0),
+        f32(0.0f),
+        f64(0.0) {
+  }
+};
+
+struct TypeAliases FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef TypeAliasesT NativeTableType;
+  enum {
+    VT_I8 = 4,
+    VT_U8 = 6,
+    VT_I16 = 8,
+    VT_U16 = 10,
+    VT_I32 = 12,
+    VT_U32 = 14,
+    VT_I64 = 16,
+    VT_U64 = 18,
+    VT_F32 = 20,
+    VT_F64 = 22,
+    VT_V8 = 24,
+    VT_VF64 = 26
+  };
+  int8_t i8() const {
+    return GetField<int8_t>(VT_I8, 0);
+  }
+  bool mutate_i8(int8_t _i8) {
+    return SetField<int8_t>(VT_I8, _i8, 0);
+  }
+  uint8_t u8() const {
+    return GetField<uint8_t>(VT_U8, 0);
+  }
+  bool mutate_u8(uint8_t _u8) {
+    return SetField<uint8_t>(VT_U8, _u8, 0);
+  }
+  int16_t i16() const {
+    return GetField<int16_t>(VT_I16, 0);
+  }
+  bool mutate_i16(int16_t _i16) {
+    return SetField<int16_t>(VT_I16, _i16, 0);
+  }
+  uint16_t u16() const {
+    return GetField<uint16_t>(VT_U16, 0);
+  }
+  bool mutate_u16(uint16_t _u16) {
+    return SetField<uint16_t>(VT_U16, _u16, 0);
+  }
+  int32_t i32() const {
+    return GetField<int32_t>(VT_I32, 0);
+  }
+  bool mutate_i32(int32_t _i32) {
+    return SetField<int32_t>(VT_I32, _i32, 0);
+  }
+  uint32_t u32() const {
+    return GetField<uint32_t>(VT_U32, 0);
+  }
+  bool mutate_u32(uint32_t _u32) {
+    return SetField<uint32_t>(VT_U32, _u32, 0);
+  }
+  int64_t i64() const {
+    return GetField<int64_t>(VT_I64, 0);
+  }
+  bool mutate_i64(int64_t _i64) {
+    return SetField<int64_t>(VT_I64, _i64, 0);
+  }
+  uint64_t u64() const {
+    return GetField<uint64_t>(VT_U64, 0);
+  }
+  bool mutate_u64(uint64_t _u64) {
+    return SetField<uint64_t>(VT_U64, _u64, 0);
+  }
+  float f32() const {
+    return GetField<float>(VT_F32, 0.0f);
+  }
+  bool mutate_f32(float _f32) {
+    return SetField<float>(VT_F32, _f32, 0.0f);
+  }
+  double f64() const {
+    return GetField<double>(VT_F64, 0.0);
+  }
+  bool mutate_f64(double _f64) {
+    return SetField<double>(VT_F64, _f64, 0.0);
+  }
+  const flatbuffers::Vector<int8_t> *v8() const {
+    return GetPointer<const flatbuffers::Vector<int8_t> *>(VT_V8);
+  }
+  flatbuffers::Vector<int8_t> *mutable_v8() {
+    return GetPointer<flatbuffers::Vector<int8_t> *>(VT_V8);
+  }
+  const flatbuffers::Vector<double> *vf64() const {
+    return GetPointer<const flatbuffers::Vector<double> *>(VT_VF64);
+  }
+  flatbuffers::Vector<double> *mutable_vf64() {
+    return GetPointer<flatbuffers::Vector<double> *>(VT_VF64);
+  }
+  bool Verify(flatbuffers::Verifier &verifier) const {
+    return VerifyTableStart(verifier) &&
+           VerifyField<int8_t>(verifier, VT_I8) &&
+           VerifyField<uint8_t>(verifier, VT_U8) &&
+           VerifyField<int16_t>(verifier, VT_I16) &&
+           VerifyField<uint16_t>(verifier, VT_U16) &&
+           VerifyField<int32_t>(verifier, VT_I32) &&
+           VerifyField<uint32_t>(verifier, VT_U32) &&
+           VerifyField<int64_t>(verifier, VT_I64) &&
+           VerifyField<uint64_t>(verifier, VT_U64) &&
+           VerifyField<float>(verifier, VT_F32) &&
+           VerifyField<double>(verifier, VT_F64) &&
+           VerifyOffset(verifier, VT_V8) &&
+           verifier.Verify(v8()) &&
+           VerifyOffset(verifier, VT_VF64) &&
+           verifier.Verify(vf64()) &&
+           verifier.EndTable();
+  }
+  TypeAliasesT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(TypeAliasesT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<TypeAliases> Pack(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct TypeAliasesBuilder {
+  flatbuffers::FlatBufferBuilder &fbb_;
+  flatbuffers::uoffset_t start_;
+  void add_i8(int8_t i8) {
+    fbb_.AddElement<int8_t>(TypeAliases::VT_I8, i8, 0);
+  }
+  void add_u8(uint8_t u8) {
+    fbb_.AddElement<uint8_t>(TypeAliases::VT_U8, u8, 0);
+  }
+  void add_i16(int16_t i16) {
+    fbb_.AddElement<int16_t>(TypeAliases::VT_I16, i16, 0);
+  }
+  void add_u16(uint16_t u16) {
+    fbb_.AddElement<uint16_t>(TypeAliases::VT_U16, u16, 0);
+  }
+  void add_i32(int32_t i32) {
+    fbb_.AddElement<int32_t>(TypeAliases::VT_I32, i32, 0);
+  }
+  void add_u32(uint32_t u32) {
+    fbb_.AddElement<uint32_t>(TypeAliases::VT_U32, u32, 0);
+  }
+  void add_i64(int64_t i64) {
+    fbb_.AddElement<int64_t>(TypeAliases::VT_I64, i64, 0);
+  }
+  void add_u64(uint64_t u64) {
+    fbb_.AddElement<uint64_t>(TypeAliases::VT_U64, u64, 0);
+  }
+  void add_f32(float f32) {
+    fbb_.AddElement<float>(TypeAliases::VT_F32, f32, 0.0f);
+  }
+  void add_f64(double f64) {
+    fbb_.AddElement<double>(TypeAliases::VT_F64, f64, 0.0);
+  }
+  void add_v8(flatbuffers::Offset<flatbuffers::Vector<int8_t>> v8) {
+    fbb_.AddOffset(TypeAliases::VT_V8, v8);
+  }
+  void add_vf64(flatbuffers::Offset<flatbuffers::Vector<double>> vf64) {
+    fbb_.AddOffset(TypeAliases::VT_VF64, vf64);
+  }
+  explicit TypeAliasesBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+        : fbb_(_fbb) {
+    start_ = fbb_.StartTable();
+  }
+  TypeAliasesBuilder &operator=(const TypeAliasesBuilder &);
+  flatbuffers::Offset<TypeAliases> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<TypeAliases>(end);
+    return o;
+  }
+};
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliases(
+    flatbuffers::FlatBufferBuilder &_fbb,
+    int8_t i8 = 0,
+    uint8_t u8 = 0,
+    int16_t i16 = 0,
+    uint16_t u16 = 0,
+    int32_t i32 = 0,
+    uint32_t u32 = 0,
+    int64_t i64 = 0,
+    uint64_t u64 = 0,
+    float f32 = 0.0f,
+    double f64 = 0.0,
+    flatbuffers::Offset<flatbuffers::Vector<int8_t>> v8 = 0,
+    flatbuffers::Offset<flatbuffers::Vector<double>> vf64 = 0) {
+  TypeAliasesBuilder builder_(_fbb);
+  builder_.add_f64(f64);
+  builder_.add_u64(u64);
+  builder_.add_i64(i64);
+  builder_.add_vf64(vf64);
+  builder_.add_v8(v8);
+  builder_.add_f32(f32);
+  builder_.add_u32(u32);
+  builder_.add_i32(i32);
+  builder_.add_u16(u16);
+  builder_.add_i16(i16);
+  builder_.add_u8(u8);
+  builder_.add_i8(i8);
+  return builder_.Finish();
+}
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliasesDirect(
+    flatbuffers::FlatBufferBuilder &_fbb,
+    int8_t i8 = 0,
+    uint8_t u8 = 0,
+    int16_t i16 = 0,
+    uint16_t u16 = 0,
+    int32_t i32 = 0,
+    uint32_t u32 = 0,
+    int64_t i64 = 0,
+    uint64_t u64 = 0,
+    float f32 = 0.0f,
+    double f64 = 0.0,
+    const std::vector<int8_t> *v8 = nullptr,
+    const std::vector<double> *vf64 = nullptr) {
+  return MyGame::Example::CreateTypeAliases(
+      _fbb,
+      i8,
+      u8,
+      i16,
+      u16,
+      i32,
+      u32,
+      i64,
+      u64,
+      f32,
+      f64,
+      v8 ? _fbb.CreateVector<int8_t>(*v8) : 0,
+      vf64 ? _fbb.CreateVector<double>(*vf64) : 0);
+}
+
+flatbuffers::Offset<TypeAliases> CreateTypeAliases(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
 }  // namespace Example
 
+inline InParentNamespaceT *InParentNamespace::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = new InParentNamespaceT();
+  UnPackTo(_o, _resolver);
+  return _o;
+}
+
+inline void InParentNamespace::UnPackTo(InParentNamespaceT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+}
+
+inline flatbuffers::Offset<InParentNamespace> InParentNamespace::Pack(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateInParentNamespace(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<InParentNamespace> CreateInParentNamespace(flatbuffers::FlatBufferBuilder &_fbb, const InParentNamespaceT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const InParentNamespaceT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  return MyGame::CreateInParentNamespace(
+      _fbb);
+}
+
 namespace Example2 {
 
 inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
@@ -1010,6 +1529,7 @@
 inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   return MyGame::Example2::CreateMonster(
       _fbb);
 }
@@ -1037,6 +1557,7 @@
 inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TestSimpleTableWithEnumT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   auto _color = _o->color;
   return MyGame::Example::CreateTestSimpleTableWithEnum(
       _fbb,
@@ -1064,7 +1585,8 @@
 inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
-  auto _id = _o->id.size() ? _fbb.CreateString(_o->id) : 0;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StatT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _id = _o->id.empty() ? 0 : _fbb.CreateString(_o->id);
   auto _val = _o->val;
   auto _count = _o->count;
   return MyGame::Example::CreateStat(
@@ -1083,20 +1605,20 @@
 inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
   (void)_o;
   (void)_resolver;
-  { auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
+  { auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<Vec3>(new Vec3(*_e)); };
   { auto _e = mana(); _o->mana = _e; };
   { auto _e = hp(); _o->hp = _e; };
   { auto _e = name(); if (_e) _o->name = _e->str(); };
-  { auto _e = inventory(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory.push_back(_e->Get(_i)); } };
+  { auto _e = inventory(); if (_e) { _o->inventory.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->inventory[_i] = _e->Get(_i); } } };
   { auto _e = color(); _o->color = _e; };
   { auto _e = test_type(); _o->test.type = _e; };
-  { auto _e = test(); if (_e) _o->test.table = AnyUnion::UnPack(_e, test_type(),_resolver); };
-  { auto _e = test4(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4.push_back(*_e->Get(_i)); } };
-  { auto _e = testarrayofstring(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring.push_back(_e->Get(_i)->str()); } };
-  { auto _e = testarrayoftables(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables.push_back(std::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver))); } };
-  { auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
-  { auto _e = testnestedflatbuffer(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer.push_back(_e->Get(_i)); } };
-  { auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(_resolver)); };
+  { auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
+  { auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
+  { auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
+  { auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = flatbuffers::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
+  { auto _e = enemy(); if (_e) _o->enemy = flatbuffers::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
+  { auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } };
+  { auto _e = testempty(); if (_e) _o->testempty = flatbuffers::unique_ptr<StatT>(_e->UnPack(_resolver)); };
   { auto _e = testbool(); _o->testbool = _e; };
   { auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
   { auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; };
@@ -1106,11 +1628,17 @@
   { auto _e = testhashu32_fnv1a(); if (_resolver) (*_resolver)(reinterpret_cast<void **>(&_o->testhashu32_fnv1a), static_cast<flatbuffers::hash_value_t>(_e)); else _o->testhashu32_fnv1a = nullptr; };
   { auto _e = testhashs64_fnv1a(); _o->testhashs64_fnv1a = _e; };
   { auto _e = testhashu64_fnv1a(); _o->testhashu64_fnv1a = _e; };
-  { auto _e = testarrayofbools(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools.push_back(_e->Get(_i) != 0); } };
+  { auto _e = testarrayofbools(); if (_e) { _o->testarrayofbools.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofbools[_i] = _e->Get(_i) != 0; } } };
   { auto _e = testf(); _o->testf = _e; };
   { auto _e = testf2(); _o->testf2 = _e; };
   { auto _e = testf3(); _o->testf3 = _e; };
-  { auto _e = testarrayofstring2(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2.push_back(_e->Get(_i)->str()); } };
+  { auto _e = testarrayofstring2(); if (_e) { _o->testarrayofstring2.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring2[_i] = _e->Get(_i)->str(); } } };
+  { auto _e = testarrayofsortedstruct(); if (_e) { _o->testarrayofsortedstruct.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofsortedstruct[_i] = *_e->Get(_i); } } };
+  { auto _e = flex(); if (_e) { _o->flex.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->flex[_i] = _e->Get(_i); } } };
+  { auto _e = test5(); if (_e) { _o->test5.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test5[_i] = *_e->Get(_i); } } };
+  { auto _e = vector_of_longs(); if (_e) { _o->vector_of_longs.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_longs[_i] = _e->Get(_i); } } };
+  { auto _e = vector_of_doubles(); if (_e) { _o->vector_of_doubles.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vector_of_doubles[_i] = _e->Get(_i); } } };
+  { auto _e = parent_namespace_test(); if (_e) _o->parent_namespace_test = flatbuffers::unique_ptr<MyGame::InParentNamespaceT>(_e->UnPack(_resolver)); };
 }
 
 inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -1120,6 +1648,7 @@
 inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   auto _pos = _o->pos ? _o->pos.get() : 0;
   auto _mana = _o->mana;
   auto _hp = _o->hp;
@@ -1130,7 +1659,7 @@
   auto _test = _o->test.Pack(_fbb);
   auto _test4 = _o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0;
   auto _testarrayofstring = _o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0;
-  auto _testarrayoftables = _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get(), _rehasher); }) : 0;
+  auto _testarrayoftables = _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>> (_o->testarrayoftables.size(), [](size_t i, _VectorArgs *__va) { return CreateMonster(*__va->__fbb, __va->__o->testarrayoftables[i].get(), __va->__rehasher); }, &_va ) : 0;
   auto _enemy = _o->enemy ? CreateMonster(_fbb, _o->enemy.get(), _rehasher) : 0;
   auto _testnestedflatbuffer = _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0;
   auto _testempty = _o->testempty ? CreateStat(_fbb, _o->testempty.get(), _rehasher) : 0;
@@ -1148,6 +1677,12 @@
   auto _testf2 = _o->testf2;
   auto _testf3 = _o->testf3;
   auto _testarrayofstring2 = _o->testarrayofstring2.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring2) : 0;
+  auto _testarrayofsortedstruct = _o->testarrayofsortedstruct.size() ? _fbb.CreateVectorOfStructs(_o->testarrayofsortedstruct) : 0;
+  auto _flex = _o->flex.size() ? _fbb.CreateVector(_o->flex) : 0;
+  auto _test5 = _o->test5.size() ? _fbb.CreateVectorOfStructs(_o->test5) : 0;
+  auto _vector_of_longs = _o->vector_of_longs.size() ? _fbb.CreateVector(_o->vector_of_longs) : 0;
+  auto _vector_of_doubles = _o->vector_of_doubles.size() ? _fbb.CreateVector(_o->vector_of_doubles) : 0;
+  auto _parent_namespace_test = _o->parent_namespace_test ? CreateInParentNamespace(_fbb, _o->parent_namespace_test.get(), _rehasher) : 0;
   return MyGame::Example::CreateMonster(
       _fbb,
       _pos,
@@ -1177,7 +1712,72 @@
       _testf,
       _testf2,
       _testf3,
-      _testarrayofstring2);
+      _testarrayofstring2,
+      _testarrayofsortedstruct,
+      _flex,
+      _test5,
+      _vector_of_longs,
+      _vector_of_doubles,
+      _parent_namespace_test);
+}
+
+inline TypeAliasesT *TypeAliases::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = new TypeAliasesT();
+  UnPackTo(_o, _resolver);
+  return _o;
+}
+
+inline void TypeAliases::UnPackTo(TypeAliasesT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+  { auto _e = i8(); _o->i8 = _e; };
+  { auto _e = u8(); _o->u8 = _e; };
+  { auto _e = i16(); _o->i16 = _e; };
+  { auto _e = u16(); _o->u16 = _e; };
+  { auto _e = i32(); _o->i32 = _e; };
+  { auto _e = u32(); _o->u32 = _e; };
+  { auto _e = i64(); _o->i64 = _e; };
+  { auto _e = u64(); _o->u64 = _e; };
+  { auto _e = f32(); _o->f32 = _e; };
+  { auto _e = f64(); _o->f64 = _e; };
+  { auto _e = v8(); if (_e) { _o->v8.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->v8[_i] = _e->Get(_i); } } };
+  { auto _e = vf64(); if (_e) { _o->vf64.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->vf64[_i] = _e->Get(_i); } } };
+}
+
+inline flatbuffers::Offset<TypeAliases> TypeAliases::Pack(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateTypeAliases(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<TypeAliases> CreateTypeAliases(flatbuffers::FlatBufferBuilder &_fbb, const TypeAliasesT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TypeAliasesT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _i8 = _o->i8;
+  auto _u8 = _o->u8;
+  auto _i16 = _o->i16;
+  auto _u16 = _o->u16;
+  auto _i32 = _o->i32;
+  auto _u32 = _o->u32;
+  auto _i64 = _o->i64;
+  auto _u64 = _o->u64;
+  auto _f32 = _o->f32;
+  auto _f64 = _o->f64;
+  auto _v8 = _o->v8.size() ? _fbb.CreateVector(_o->v8) : 0;
+  auto _vf64 = _o->vf64.size() ? _fbb.CreateVector(_o->vf64) : 0;
+  return MyGame::Example::CreateTypeAliases(
+      _fbb,
+      _i8,
+      _u8,
+      _i16,
+      _u16,
+      _i32,
+      _u32,
+      _i64,
+      _u64,
+      _f32,
+      _f64,
+      _v8,
+      _vf64);
 }
 
 inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *obj, Any type) {
@@ -1212,7 +1812,7 @@
   return true;
 }
 
-inline flatbuffers::NativeTable *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
+inline void *AnyUnion::UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver) {
   switch (type) {
     case Any_Monster: {
       auto ptr = reinterpret_cast<const Monster *>(obj);
@@ -1233,44 +1833,375 @@
 inline flatbuffers::Offset<void> AnyUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
   switch (type) {
     case Any_Monster: {
-      auto ptr = reinterpret_cast<const MonsterT *>(table);
+      auto ptr = reinterpret_cast<const MonsterT *>(value);
       return CreateMonster(_fbb, ptr, _rehasher).Union();
     }
     case Any_TestSimpleTableWithEnum: {
-      auto ptr = reinterpret_cast<const TestSimpleTableWithEnumT *>(table);
+      auto ptr = reinterpret_cast<const TestSimpleTableWithEnumT *>(value);
       return CreateTestSimpleTableWithEnum(_fbb, ptr, _rehasher).Union();
     }
     case Any_MyGame_Example2_Monster: {
-      auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(table);
+      auto ptr = reinterpret_cast<const MyGame::Example2::MonsterT *>(value);
       return CreateMonster(_fbb, ptr, _rehasher).Union();
     }
     default: return 0;
   }
 }
 
+inline AnyUnion::AnyUnion(const AnyUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+  switch (type) {
+    case Any_Monster: {
+      assert(false);  // MonsterT not copyable.
+      break;
+    }
+    case Any_TestSimpleTableWithEnum: {
+      value = new TestSimpleTableWithEnumT(*reinterpret_cast<TestSimpleTableWithEnumT *>(u.value));
+      break;
+    }
+    case Any_MyGame_Example2_Monster: {
+      value = new MyGame::Example2::MonsterT(*reinterpret_cast<MyGame::Example2::MonsterT *>(u.value));
+      break;
+    }
+    default:
+      break;
+  }
+}
+
 inline void AnyUnion::Reset() {
   switch (type) {
     case Any_Monster: {
-      auto ptr = reinterpret_cast<MonsterT *>(table);
+      auto ptr = reinterpret_cast<MonsterT *>(value);
       delete ptr;
       break;
     }
     case Any_TestSimpleTableWithEnum: {
-      auto ptr = reinterpret_cast<TestSimpleTableWithEnumT *>(table);
+      auto ptr = reinterpret_cast<TestSimpleTableWithEnumT *>(value);
       delete ptr;
       break;
     }
     case Any_MyGame_Example2_Monster: {
-      auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(table);
+      auto ptr = reinterpret_cast<MyGame::Example2::MonsterT *>(value);
       delete ptr;
       break;
     }
     default: break;
   }
-  table = nullptr;
+  value = nullptr;
   type = Any_NONE;
 }
 
+}  // namespace Example
+
+inline flatbuffers::TypeTable *InParentNamespaceTypeTable();
+
+namespace Example2 {
+
+inline flatbuffers::TypeTable *MonsterTypeTable();
+
+}  // namespace Example2
+
+namespace Example {
+
+inline flatbuffers::TypeTable *TestTypeTable();
+
+inline flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable();
+
+inline flatbuffers::TypeTable *Vec3TypeTable();
+
+inline flatbuffers::TypeTable *AbilityTypeTable();
+
+inline flatbuffers::TypeTable *StatTypeTable();
+
+inline flatbuffers::TypeTable *MonsterTypeTable();
+
+inline flatbuffers::TypeTable *TypeAliasesTypeTable();
+
+inline flatbuffers::TypeTable *ColorTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    ColorTypeTable
+  };
+  static const int32_t values[] = { 1, 2, 8 };
+  static const char *names[] = {
+    "Red",
+    "Green",
+    "Blue"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_ENUM, 3, type_codes, type_refs, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *AnyTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, -1 },
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_SEQUENCE, 0, 1 },
+    { flatbuffers::ET_SEQUENCE, 0, 2 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    MonsterTypeTable,
+    TestSimpleTableWithEnumTypeTable,
+    MyGame::Example2::MonsterTypeTable
+  };
+  static const char *names[] = {
+    "NONE",
+    "Monster",
+    "TestSimpleTableWithEnum",
+    "MyGame_Example2_Monster"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_UNION, 4, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+}  // namespace Example
+
+inline flatbuffers::TypeTable *InParentNamespaceTypeTable() {
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
+  };
+  return &tt;
+}
+
+namespace Example2 {
+
+inline flatbuffers::TypeTable *MonsterTypeTable() {
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 0, nullptr, nullptr, nullptr, nullptr
+  };
+  return &tt;
+}
+
+}  // namespace Example2
+
+namespace Example {
+
+inline flatbuffers::TypeTable *TestTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 2, 4 };
+  static const char *names[] = {
+    "a",
+    "b"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *TestSimpleTableWithEnumTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    ColorTypeTable
+  };
+  static const char *names[] = {
+    "color"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *Vec3TypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_SEQUENCE, 0, 1 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    ColorTypeTable,
+    TestTypeTable
+  };
+  static const int32_t values[] = { 0, 4, 8, 16, 24, 26, 32 };
+  static const char *names[] = {
+    "x",
+    "y",
+    "z",
+    "test1",
+    "test2",
+    "test3"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 6, type_codes, type_refs, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *AbilityTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 4, 8 };
+  static const char *names[] = {
+    "id",
+    "distance"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *StatTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_STRING, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 }
+  };
+  static const char *names[] = {
+    "id",
+    "val",
+    "count"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 3, type_codes, nullptr, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *MonsterTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_STRING, 0, -1 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_UCHAR, 1, -1 },
+    { flatbuffers::ET_CHAR, 0, 1 },
+    { flatbuffers::ET_UTYPE, 0, 2 },
+    { flatbuffers::ET_SEQUENCE, 0, 2 },
+    { flatbuffers::ET_SEQUENCE, 1, 3 },
+    { flatbuffers::ET_STRING, 1, -1 },
+    { flatbuffers::ET_SEQUENCE, 1, 4 },
+    { flatbuffers::ET_SEQUENCE, 0, 4 },
+    { flatbuffers::ET_UCHAR, 1, -1 },
+    { flatbuffers::ET_SEQUENCE, 0, 5 },
+    { flatbuffers::ET_BOOL, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_BOOL, 1, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_STRING, 1, -1 },
+    { flatbuffers::ET_SEQUENCE, 1, 6 },
+    { flatbuffers::ET_UCHAR, 1, -1 },
+    { flatbuffers::ET_SEQUENCE, 1, 3 },
+    { flatbuffers::ET_LONG, 1, -1 },
+    { flatbuffers::ET_DOUBLE, 1, -1 },
+    { flatbuffers::ET_SEQUENCE, 0, 7 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    Vec3TypeTable,
+    ColorTypeTable,
+    AnyTypeTable,
+    TestTypeTable,
+    MonsterTypeTable,
+    StatTypeTable,
+    AbilityTypeTable,
+    MyGame::InParentNamespaceTypeTable
+  };
+  static const char *names[] = {
+    "pos",
+    "mana",
+    "hp",
+    "name",
+    "friendly",
+    "inventory",
+    "color",
+    "test_type",
+    "test",
+    "test4",
+    "testarrayofstring",
+    "testarrayoftables",
+    "enemy",
+    "testnestedflatbuffer",
+    "testempty",
+    "testbool",
+    "testhashs32_fnv1",
+    "testhashu32_fnv1",
+    "testhashs64_fnv1",
+    "testhashu64_fnv1",
+    "testhashs32_fnv1a",
+    "testhashu32_fnv1a",
+    "testhashs64_fnv1a",
+    "testhashu64_fnv1a",
+    "testarrayofbools",
+    "testf",
+    "testf2",
+    "testf3",
+    "testarrayofstring2",
+    "testarrayofsortedstruct",
+    "flex",
+    "test5",
+    "vector_of_longs",
+    "vector_of_doubles",
+    "parent_namespace_test"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 35, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *TypeAliasesTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, -1 },
+    { flatbuffers::ET_UCHAR, 0, -1 },
+    { flatbuffers::ET_SHORT, 0, -1 },
+    { flatbuffers::ET_USHORT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_UINT, 0, -1 },
+    { flatbuffers::ET_LONG, 0, -1 },
+    { flatbuffers::ET_ULONG, 0, -1 },
+    { flatbuffers::ET_FLOAT, 0, -1 },
+    { flatbuffers::ET_DOUBLE, 0, -1 },
+    { flatbuffers::ET_CHAR, 1, -1 },
+    { flatbuffers::ET_DOUBLE, 1, -1 }
+  };
+  static const char *names[] = {
+    "i8",
+    "u8",
+    "i16",
+    "u16",
+    "i32",
+    "u32",
+    "i64",
+    "u64",
+    "f32",
+    "f64",
+    "v8",
+    "vf64"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 12, type_codes, nullptr, nullptr, names
+  };
+  return &tt;
+}
+
 inline const MyGame::Example::Monster *GetMonster(const void *buf) {
   return flatbuffers::GetRoot<MyGame::Example::Monster>(buf);
 }
@@ -1303,10 +2234,10 @@
   fbb.Finish(root, MonsterIdentifier());
 }
 
-inline std::unique_ptr<MonsterT> UnPackMonster(
+inline flatbuffers::unique_ptr<MonsterT> UnPackMonster(
     const void *buf,
     const flatbuffers::resolver_function_t *res = nullptr) {
-  return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
+  return flatbuffers::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
 }
 
 }  // namespace Example
diff --git a/tests/monster_test_generated.js b/tests/monster_test_generated.js
index dbb5ba6..e073b79 100644
--- a/tests/monster_test_generated.js
+++ b/tests/monster_test_generated.js
@@ -46,6 +46,57 @@
 /**
  * @constructor
  */
+MyGame.InParentNamespace = function() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.InParentNamespace}
+ */
+MyGame.InParentNamespace.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace}
+ */
+MyGame.InParentNamespace.getRootAsInParentNamespace = function(bb, obj) {
+  return (obj || new MyGame.InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.InParentNamespace.startInParentNamespace = function(builder) {
+  builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.InParentNamespace.endInParentNamespace = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
+/**
+ * @constructor
+ */
 MyGame.Example2.Monster = function() {
   /**
    * @type {flatbuffers.ByteBuffer}
@@ -398,7 +449,7 @@
 
 /**
  * @param {MyGame.Example.Test=} obj
- * @returns {MyGame.Example.Test}
+ * @returns {MyGame.Example.Test|null}
  */
 MyGame.Example.Vec3.prototype.test3 = function(obj) {
   return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb);
@@ -435,6 +486,89 @@
 /**
  * @constructor
  */
+MyGame.Example.Ability = function() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.Ability}
+ */
+MyGame.Example.Ability.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Ability.prototype.id = function() {
+  return this.bb.readUint32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Ability.prototype.mutate_id = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Ability.prototype.distance = function() {
+  return this.bb.readUint32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.Ability.prototype.mutate_distance = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} id
+ * @param {number} distance
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Ability.createAbility = function(builder, id, distance) {
+  builder.prep(4, 8);
+  builder.writeInt32(distance);
+  builder.writeInt32(id);
+  return builder.offset();
+};
+
+/**
+ * @constructor
+ */
 MyGame.Example.Stat = function() {
   /**
    * @type {flatbuffers.ByteBuffer}
@@ -469,7 +603,7 @@
 
 /**
  * @param {flatbuffers.Encoding=} optionalEncoding
- * @returns {string|Uint8Array}
+ * @returns {string|Uint8Array|null}
  */
 MyGame.Example.Stat.prototype.id = function(optionalEncoding) {
   var offset = this.bb.__offset(this.bb_pos, 4);
@@ -609,7 +743,7 @@
 
 /**
  * @param {MyGame.Example.Vec3=} obj
- * @returns {MyGame.Example.Vec3}
+ * @returns {MyGame.Example.Vec3|null}
  */
 MyGame.Example.Monster.prototype.pos = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 4);
@@ -664,7 +798,7 @@
 
 /**
  * @param {flatbuffers.Encoding=} optionalEncoding
- * @returns {string|Uint8Array}
+ * @returns {string|Uint8Array|null}
  */
 MyGame.Example.Monster.prototype.name = function(optionalEncoding) {
   var offset = this.bb.__offset(this.bb_pos, 10);
@@ -810,7 +944,7 @@
 
 /**
  * @param {MyGame.Example.Monster=} obj
- * @returns {MyGame.Example.Monster}
+ * @returns {MyGame.Example.Monster|null}
  */
 MyGame.Example.Monster.prototype.enemy = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 28);
@@ -844,7 +978,7 @@
 
 /**
  * @param {MyGame.Example.Stat=} obj
- * @returns {MyGame.Example.Stat}
+ * @returns {MyGame.Example.Stat|null}
  */
 MyGame.Example.Monster.prototype.testempty = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 32);
@@ -1171,10 +1305,122 @@
 };
 
 /**
+ * @param {number} index
+ * @param {MyGame.Example.Ability=} obj
+ * @returns {MyGame.Example.Ability}
+ */
+MyGame.Example.Monster.prototype.testarrayofsortedstruct = function(index, obj) {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.testarrayofsortedstructLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.flex = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.flexLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+MyGame.Example.Monster.prototype.flexArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+MyGame.Example.Monster.prototype.test5 = function(index, obj) {
+  var offset = this.bb.__offset(this.bb_pos, 66);
+  return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.test5Length = function() {
+  var offset = this.bb.__offset(this.bb_pos, 66);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongs = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.readInt64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfLongsLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoubles = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+MyGame.Example.Monster.prototype.vectorOfDoublesArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace|null}
+ */
+MyGame.Example.Monster.prototype.parentNamespaceTest = function(obj) {
+  var offset = this.bb.__offset(this.bb_pos, 72);
+  return offset ? (obj || new MyGame.InParentNamespace).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
  * @param {flatbuffers.Builder} builder
  */
 MyGame.Example.Monster.startMonster = function(builder) {
-  builder.startObject(29);
+  builder.startObject(35);
 };
 
 /**
@@ -1537,6 +1783,133 @@
 
 /**
  * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofsortedstructOffset
+ */
+MyGame.Example.Monster.addTestarrayofsortedstruct = function(builder, testarrayofsortedstructOffset) {
+  builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTestarrayofsortedstructVector = function(builder, numElems) {
+  builder.startVector(8, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} flexOffset
+ */
+MyGame.Example.Monster.addFlex = function(builder, flexOffset) {
+  builder.addFieldOffset(30, flexOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createFlexVector = function(builder, data) {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startFlexVector = function(builder, numElems) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test5Offset
+ */
+MyGame.Example.Monster.addTest5 = function(builder, test5Offset) {
+  builder.addFieldOffset(31, test5Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startTest5Vector = function(builder, numElems) {
+  builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfLongsOffset
+ */
+MyGame.Example.Monster.addVectorOfLongs = function(builder, vectorOfLongsOffset) {
+  builder.addFieldOffset(32, vectorOfLongsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfLongsVector = function(builder, data) {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfLongsVector = function(builder, numElems) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfDoublesOffset
+ */
+MyGame.Example.Monster.addVectorOfDoubles = function(builder, vectorOfDoublesOffset) {
+  builder.addFieldOffset(33, vectorOfDoublesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.Monster.createVectorOfDoublesVector = function(builder, data) {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addFloat64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.Monster.startVectorOfDoublesVector = function(builder, numElems) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} parentNamespaceTestOffset
+ */
+MyGame.Example.Monster.addParentNamespaceTest = function(builder, parentNamespaceTestOffset) {
+  builder.addFieldOffset(34, parentNamespaceTestOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
  * @returns {flatbuffers.Offset}
  */
 MyGame.Example.Monster.endMonster = function(builder) {
@@ -1553,5 +1926,474 @@
   builder.finish(offset, 'MONS');
 };
 
+/**
+ * @constructor
+ */
+MyGame.Example.TypeAliases = function() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+};
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {MyGame.Example.TypeAliases}
+ */
+MyGame.Example.TypeAliases.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {MyGame.Example.TypeAliases=} obj
+ * @returns {MyGame.Example.TypeAliases}
+ */
+MyGame.Example.TypeAliases.getRootAsTypeAliases = function(bb, obj) {
+  return (obj || new MyGame.Example.TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i8 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i8 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u8 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readUint8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u8 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i16 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i16 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u16 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u16 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.i32 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 12);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i32 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 12);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.u32 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u32 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.TypeAliases.prototype.i64 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_i64 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+MyGame.Example.TypeAliases.prototype.u64 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_u64 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.f32 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_f32 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.f64 = function() {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+MyGame.Example.TypeAliases.prototype.mutate_f64 = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.v8 = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.v8Length = function() {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+MyGame.Example.TypeAliases.prototype.v8Array = function() {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.vf64 = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+MyGame.Example.TypeAliases.prototype.vf64Length = function() {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+MyGame.Example.TypeAliases.prototype.vf64Array = function() {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+MyGame.Example.TypeAliases.startTypeAliases = function(builder) {
+  builder.startObject(12);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i8
+ */
+MyGame.Example.TypeAliases.addI8 = function(builder, i8) {
+  builder.addFieldInt8(0, i8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u8
+ */
+MyGame.Example.TypeAliases.addU8 = function(builder, u8) {
+  builder.addFieldInt8(1, u8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i16
+ */
+MyGame.Example.TypeAliases.addI16 = function(builder, i16) {
+  builder.addFieldInt16(2, i16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u16
+ */
+MyGame.Example.TypeAliases.addU16 = function(builder, u16) {
+  builder.addFieldInt16(3, u16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i32
+ */
+MyGame.Example.TypeAliases.addI32 = function(builder, i32) {
+  builder.addFieldInt32(4, i32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u32
+ */
+MyGame.Example.TypeAliases.addU32 = function(builder, u32) {
+  builder.addFieldInt32(5, u32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} i64
+ */
+MyGame.Example.TypeAliases.addI64 = function(builder, i64) {
+  builder.addFieldInt64(6, i64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} u64
+ */
+MyGame.Example.TypeAliases.addU64 = function(builder, u64) {
+  builder.addFieldInt64(7, u64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f32
+ */
+MyGame.Example.TypeAliases.addF32 = function(builder, f32) {
+  builder.addFieldFloat32(8, f32, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f64
+ */
+MyGame.Example.TypeAliases.addF64 = function(builder, f64) {
+  builder.addFieldFloat64(9, f64, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} v8Offset
+ */
+MyGame.Example.TypeAliases.addV8 = function(builder, v8Offset) {
+  builder.addFieldOffset(10, v8Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.createV8Vector = function(builder, data) {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.TypeAliases.startV8Vector = function(builder, numElems) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vf64Offset
+ */
+MyGame.Example.TypeAliases.addVf64 = function(builder, vf64Offset) {
+  builder.addFieldOffset(11, vf64Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.createVf64Vector = function(builder, data) {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addFloat64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+MyGame.Example.TypeAliases.startVf64Vector = function(builder, numElems) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+MyGame.Example.TypeAliases.endTypeAliases = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
 // Exports for Node.js and RequireJS
 this.MyGame = MyGame;
diff --git a/tests/monster_test_generated.ts b/tests/monster_test_generated.ts
new file mode 100644
index 0000000..fa4e963
--- /dev/null
+++ b/tests/monster_test_generated.ts
@@ -0,0 +1,2392 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum
+ */
+export namespace MyGame.Example{
+export enum Color{
+  Red= 1,
+  Green= 2,
+  Blue= 8
+}};
+
+/**
+ * @enum
+ */
+export namespace MyGame.Example{
+export enum Any{
+  NONE= 0,
+  Monster= 1,
+  TestSimpleTableWithEnum= 2,
+  MyGame_Example2_Monster= 3
+}};
+
+/**
+ * @constructor
+ */
+export namespace MyGame{
+export class InParentNamespace {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {InParentNamespace}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):InParentNamespace {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {InParentNamespace=} obj
+ * @returns {InParentNamespace}
+ */
+static getRootAsInParentNamespace(bb:flatbuffers.ByteBuffer, obj?:InParentNamespace):InParentNamespace {
+  return (obj || new InParentNamespace).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startInParentNamespace(builder:flatbuffers.Builder) {
+  builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endInParentNamespace(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example2{
+export class Monster {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Monster}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Monster=} obj
+ * @returns {Monster}
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+  return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+  builder.startObject(0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Test {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Test}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Test {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+a():number {
+  return this.bb.readInt16(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+b():number {
+  return this.bb.readInt8(this.bb_pos + 2);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_b(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 2);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+static createTest(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+  builder.prep(2, 4);
+  builder.pad(1);
+  builder.writeInt8(b);
+  builder.writeInt16(a);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class TestSimpleTableWithEnum {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TestSimpleTableWithEnum}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TestSimpleTableWithEnum {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TestSimpleTableWithEnum=} obj
+ * @returns {TestSimpleTableWithEnum}
+ */
+static getRootAsTestSimpleTableWithEnum(bb:flatbuffers.ByteBuffer, obj?:TestSimpleTableWithEnum):TestSimpleTableWithEnum {
+  return (obj || new TestSimpleTableWithEnum).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+color():MyGame.Example.Color {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + offset)) : MyGame.Example.Color.Green;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTestSimpleTableWithEnum(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+  builder.addFieldInt8(0, color, MyGame.Example.Color.Green);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTestSimpleTableWithEnum(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Vec3 {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Vec3}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Vec3 {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+x():number {
+  return this.bb.readFloat32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_x(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+y():number {
+  return this.bb.readFloat32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_y(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+z():number {
+  return this.bb.readFloat32(this.bb_pos + 8);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_z(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+test1():number {
+  return this.bb.readFloat64(this.bb_pos + 16);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_test1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+test2():MyGame.Example.Color {
+  return /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + 24));
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_test2(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test|null}
+ */
+test3(obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+  return (obj || new MyGame.Example.Test).__init(this.bb_pos + 26, this.bb);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} test1
+ * @param {MyGame.Example.Color} test2
+ * @param {number} test3_a
+ * @param {number} test3_b
+ * @returns {flatbuffers.Offset}
+ */
+static createVec3(builder:flatbuffers.Builder, x: number, y: number, z: number, test1: number, test2: MyGame.Example.Color, test3_a: number, test3_b: number):flatbuffers.Offset {
+  builder.prep(16, 32);
+  builder.pad(2);
+  builder.prep(2, 4);
+  builder.pad(1);
+  builder.writeInt8(test3_b);
+  builder.writeInt16(test3_a);
+  builder.pad(1);
+  builder.writeInt8(test2);
+  builder.writeFloat64(test1);
+  builder.pad(4);
+  builder.writeFloat32(z);
+  builder.writeFloat32(y);
+  builder.writeFloat32(x);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Ability {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Ability}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Ability {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+id():number {
+  return this.bb.readUint32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_id(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+distance():number {
+  return this.bb.readUint32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_distance(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} id
+ * @param {number} distance
+ * @returns {flatbuffers.Offset}
+ */
+static createAbility(builder:flatbuffers.Builder, id: number, distance: number):flatbuffers.Offset {
+  builder.prep(4, 8);
+  builder.writeInt32(distance);
+  builder.writeInt32(id);
+  return builder.offset();
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Stat {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Stat}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Stat {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Stat=} obj
+ * @returns {Stat}
+ */
+static getRootAsStat(bb:flatbuffers.ByteBuffer, obj?:Stat):Stat {
+  return (obj || new Stat).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array|null}
+ */
+id():string|null
+id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+id(optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+val():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_val(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+count():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_count(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startStat(builder:flatbuffers.Builder) {
+  builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} idOffset
+ */
+static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, idOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} val
+ */
+static addVal(builder:flatbuffers.Builder, val:flatbuffers.Long) {
+  builder.addFieldInt64(1, val, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} count
+ */
+static addCount(builder:flatbuffers.Builder, count:number) {
+  builder.addFieldInt16(2, count, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endStat(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * an example documentation comment: monster object
+ *
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class Monster {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Monster}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Monster {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Monster=} obj
+ * @returns {Monster}
+ */
+static getRootAsMonster(bb:flatbuffers.ByteBuffer, obj?:Monster):Monster {
+  return (obj || new Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
+  return bb.__has_identifier('MONS');
+};
+
+/**
+ * @param {MyGame.Example.Vec3=} obj
+ * @returns {MyGame.Example.Vec3|null}
+ */
+pos(obj?:MyGame.Example.Vec3):MyGame.Example.Vec3|null {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new MyGame.Example.Vec3).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+mana():number {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 150;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_mana(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+hp():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 100;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_hp(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array|null}
+ */
+name():string|null
+name(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null
+name(optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__string(this.bb_pos + offset, optionalEncoding) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+inventory(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+inventoryLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+inventoryArray():Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {MyGame.Example.Color}
+ */
+color():MyGame.Example.Color {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+  return offset ? /** @type {MyGame.Example.Color} */ (this.bb.readInt8(this.bb_pos + offset)) : MyGame.Example.Color.Blue;
+};
+
+/**
+ * @param {MyGame.Example.Color} value
+ * @returns {boolean}
+ */
+mutate_color(value:MyGame.Example.Color):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {MyGame.Example.Any}
+ */
+testType():MyGame.Example.Any {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+  return offset ? /** @type {MyGame.Example.Any} */ (this.bb.readUint8(this.bb_pos + offset)) : MyGame.Example.Any.NONE;
+};
+
+/**
+ * @param {MyGame.Example.Any} value
+ * @returns {boolean}
+ */
+mutate_test_type(value:MyGame.Example.Any):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+test<T extends flatbuffers.Table>(obj:T):T|null {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+  return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+test4(index: number, obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+test4Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+testarrayofstring(index: number):string
+testarrayofstring(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring(index: number,optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofstringLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * an example documentation comment: this will end up in the generated code
+ * multiline too
+ *
+ * @param {number} index
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster}
+ */
+testarrayoftables(index: number, obj?:MyGame.Example.Monster):MyGame.Example.Monster|null {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb.__vector(this.bb_pos + offset) + index * 4), this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayoftablesLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {MyGame.Example.Monster=} obj
+ * @returns {MyGame.Example.Monster|null}
+ */
+enemy(obj?:MyGame.Example.Monster):MyGame.Example.Monster|null {
+  var offset = this.bb.__offset(this.bb_pos, 28);
+  return offset ? (obj || new MyGame.Example.Monster).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+testnestedflatbuffer(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+testnestedflatbufferLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+testnestedflatbufferArray():Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 30);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.Example.Stat=} obj
+ * @returns {MyGame.Example.Stat|null}
+ */
+testempty(obj?:MyGame.Example.Stat):MyGame.Example.Stat|null {
+  var offset = this.bb.__offset(this.bb_pos, 32);
+  return offset ? (obj || new MyGame.Example.Stat).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {boolean}
+ */
+testbool():boolean {
+  var offset = this.bb.__offset(this.bb_pos, 34);
+  return offset ? !!this.bb.readInt8(this.bb_pos + offset) : false;
+};
+
+/**
+ * @param {boolean} value
+ * @returns {boolean}
+ */
+mutate_testbool(value:boolean):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 34);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, +value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashs32Fnv1():number {
+  var offset = this.bb.__offset(this.bb_pos, 36);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashs32_fnv1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 36);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashu32Fnv1():number {
+  var offset = this.bb.__offset(this.bb_pos, 38);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashu32_fnv1(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 38);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashs64Fnv1():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 40);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashs64_fnv1(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 40);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashu64Fnv1():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 42);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashu64_fnv1(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 42);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashs32Fnv1a():number {
+  var offset = this.bb.__offset(this.bb_pos, 44);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashs32_fnv1a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 44);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testhashu32Fnv1a():number {
+  var offset = this.bb.__offset(this.bb_pos, 46);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testhashu32_fnv1a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 46);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashs64Fnv1a():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 48);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashs64_fnv1a(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 48);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+testhashu64Fnv1a():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 50);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_testhashu64_fnv1a(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 50);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {boolean}
+ */
+testarrayofbools(index: number):boolean|null {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? !!this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : false;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofboolsLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+testarrayofboolsArray():Int8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 52);
+  return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testf():number {
+  var offset = this.bb.__offset(this.bb_pos, 54);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.14159;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 54);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testf2():number {
+  var offset = this.bb.__offset(this.bb_pos, 56);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 3.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf2(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 56);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+testf3():number {
+  var offset = this.bb.__offset(this.bb_pos, 58);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_testf3(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 58);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Encoding=} optionalEncoding
+ * @returns {string|Uint8Array}
+ */
+testarrayofstring2(index: number):string
+testarrayofstring2(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array
+testarrayofstring2(index: number,optionalEncoding?:any):string|Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 60);
+  return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofstring2Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 60);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Ability=} obj
+ * @returns {MyGame.Example.Ability}
+ */
+testarrayofsortedstruct(index: number, obj?:MyGame.Example.Ability):MyGame.Example.Ability|null {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? (obj || new MyGame.Example.Ability).__init(this.bb.__vector(this.bb_pos + offset) + index * 8, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+testarrayofsortedstructLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 62);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+flex(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+flexLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+flexArray():Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 64);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {MyGame.Example.Test=} obj
+ * @returns {MyGame.Example.Test}
+ */
+test5(index: number, obj?:MyGame.Example.Test):MyGame.Example.Test|null {
+  var offset = this.bb.__offset(this.bb_pos, 66);
+  return offset ? (obj || new MyGame.Example.Test).__init(this.bb.__vector(this.bb_pos + offset) + index * 4, this.bb) : null;
+};
+
+/**
+ * @returns {number}
+ */
+test5Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 66);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {flatbuffers.Long}
+ */
+vectorOfLongs(index: number):flatbuffers.Long|null {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.readInt64(this.bb.__vector(this.bb_pos + offset) + index * 8) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @returns {number}
+ */
+vectorOfLongsLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 68);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+vectorOfDoubles(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+vectorOfDoublesLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+vectorOfDoublesArray():Float64Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 70);
+  return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {MyGame.InParentNamespace=} obj
+ * @returns {MyGame.InParentNamespace|null}
+ */
+parentNamespaceTest(obj?:MyGame.InParentNamespace):MyGame.InParentNamespace|null {
+  var offset = this.bb.__offset(this.bb_pos, 72);
+  return offset ? (obj || new MyGame.InParentNamespace).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startMonster(builder:flatbuffers.Builder) {
+  builder.startObject(35);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} posOffset
+ */
+static addPos(builder:flatbuffers.Builder, posOffset:flatbuffers.Offset) {
+  builder.addFieldStruct(0, posOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} mana
+ */
+static addMana(builder:flatbuffers.Builder, mana:number) {
+  builder.addFieldInt16(1, mana, 150);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hp
+ */
+static addHp(builder:flatbuffers.Builder, hp:number) {
+  builder.addFieldInt16(2, hp, 100);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} nameOffset
+ */
+static addName(builder:flatbuffers.Builder, nameOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(3, nameOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} inventoryOffset
+ */
+static addInventory(builder:flatbuffers.Builder, inventoryOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(5, inventoryOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createInventoryVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startInventoryVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Color} color
+ */
+static addColor(builder:flatbuffers.Builder, color:MyGame.Example.Color) {
+  builder.addFieldInt8(6, color, MyGame.Example.Color.Blue);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {MyGame.Example.Any} testType
+ */
+static addTestType(builder:flatbuffers.Builder, testType:MyGame.Example.Any) {
+  builder.addFieldInt8(7, testType, MyGame.Example.Any.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testOffset
+ */
+static addTest(builder:flatbuffers.Builder, testOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(8, testOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test4Offset
+ */
+static addTest4(builder:flatbuffers.Builder, test4Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(9, test4Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTest4Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstringOffset
+ */
+static addTestarrayofstring(builder:flatbuffers.Builder, testarrayofstringOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(10, testarrayofstringOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofstringVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofstringVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayoftablesOffset
+ */
+static addTestarrayoftables(builder:flatbuffers.Builder, testarrayoftablesOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(11, testarrayoftablesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayoftablesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayoftablesVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} enemyOffset
+ */
+static addEnemy(builder:flatbuffers.Builder, enemyOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(12, enemyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testnestedflatbufferOffset
+ */
+static addTestnestedflatbuffer(builder:flatbuffers.Builder, testnestedflatbufferOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(13, testnestedflatbufferOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestnestedflatbufferVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestnestedflatbufferVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testemptyOffset
+ */
+static addTestempty(builder:flatbuffers.Builder, testemptyOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(14, testemptyOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {boolean} testbool
+ */
+static addTestbool(builder:flatbuffers.Builder, testbool:boolean) {
+  builder.addFieldInt8(15, +testbool, +false);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1
+ */
+static addTesthashs32Fnv1(builder:flatbuffers.Builder, testhashs32Fnv1:number) {
+  builder.addFieldInt32(16, testhashs32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1
+ */
+static addTesthashu32Fnv1(builder:flatbuffers.Builder, testhashu32Fnv1:number) {
+  builder.addFieldInt32(17, testhashu32Fnv1, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1
+ */
+static addTesthashs64Fnv1(builder:flatbuffers.Builder, testhashs64Fnv1:flatbuffers.Long) {
+  builder.addFieldInt64(18, testhashs64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1
+ */
+static addTesthashu64Fnv1(builder:flatbuffers.Builder, testhashu64Fnv1:flatbuffers.Long) {
+  builder.addFieldInt64(19, testhashu64Fnv1, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashs32Fnv1a
+ */
+static addTesthashs32Fnv1a(builder:flatbuffers.Builder, testhashs32Fnv1a:number) {
+  builder.addFieldInt32(20, testhashs32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testhashu32Fnv1a
+ */
+static addTesthashu32Fnv1a(builder:flatbuffers.Builder, testhashu32Fnv1a:number) {
+  builder.addFieldInt32(21, testhashu32Fnv1a, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashs64Fnv1a
+ */
+static addTesthashs64Fnv1a(builder:flatbuffers.Builder, testhashs64Fnv1a:flatbuffers.Long) {
+  builder.addFieldInt64(22, testhashs64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} testhashu64Fnv1a
+ */
+static addTesthashu64Fnv1a(builder:flatbuffers.Builder, testhashu64Fnv1a:flatbuffers.Long) {
+  builder.addFieldInt64(23, testhashu64Fnv1a, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofboolsOffset
+ */
+static addTestarrayofbools(builder:flatbuffers.Builder, testarrayofboolsOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(24, testarrayofboolsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<boolean>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofboolsVector(builder:flatbuffers.Builder, data:boolean[]):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(+data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofboolsVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf
+ */
+static addTestf(builder:flatbuffers.Builder, testf:number) {
+  builder.addFieldFloat32(25, testf, 3.14159);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf2
+ */
+static addTestf2(builder:flatbuffers.Builder, testf2:number) {
+  builder.addFieldFloat32(26, testf2, 3.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} testf3
+ */
+static addTestf3(builder:flatbuffers.Builder, testf3:number) {
+  builder.addFieldFloat32(27, testf3, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofstring2Offset
+ */
+static addTestarrayofstring2(builder:flatbuffers.Builder, testarrayofstring2Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(28, testarrayofstring2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createTestarrayofstring2Vector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofstring2Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} testarrayofsortedstructOffset
+ */
+static addTestarrayofsortedstruct(builder:flatbuffers.Builder, testarrayofsortedstructOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(29, testarrayofsortedstructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTestarrayofsortedstructVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(8, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} flexOffset
+ */
+static addFlex(builder:flatbuffers.Builder, flexOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(30, flexOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createFlexVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startFlexVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} test5Offset
+ */
+static addTest5(builder:flatbuffers.Builder, test5Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(31, test5Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startTest5Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfLongsOffset
+ */
+static addVectorOfLongs(builder:flatbuffers.Builder, vectorOfLongsOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(32, vectorOfLongsOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Long>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createVectorOfLongsVector(builder:flatbuffers.Builder, data:flatbuffers.Long[]):flatbuffers.Offset {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startVectorOfLongsVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vectorOfDoublesOffset
+ */
+static addVectorOfDoubles(builder:flatbuffers.Builder, vectorOfDoublesOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(33, vectorOfDoublesOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createVectorOfDoublesVector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addFloat64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startVectorOfDoublesVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} parentNamespaceTestOffset
+ */
+static addParentNamespaceTest(builder:flatbuffers.Builder, parentNamespaceTestOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(34, parentNamespaceTestOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endMonster(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  builder.requiredField(offset, 10); // name
+  return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+static finishMonsterBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+  builder.finish(offset, 'MONS');
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace MyGame.Example{
+export class TypeAliases {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TypeAliases}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TypeAliases {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TypeAliases=} obj
+ * @returns {TypeAliases}
+ */
+static getRootAsTypeAliases(bb:flatbuffers.ByteBuffer, obj?:TypeAliases):TypeAliases {
+  return (obj || new TypeAliases).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+i8():number {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_i8(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+u8():number {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.readUint8(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_u8(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+i16():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.readInt16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_i16(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+u16():number {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.readUint16(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_u16(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint16(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+i32():number {
+  var offset = this.bb.__offset(this.bb_pos, 12);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_i32(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 12);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+u32():number {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+  return offset ? this.bb.readUint32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_u32(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 14);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+i64():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+  return offset ? this.bb.readInt64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_i64(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 16);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {flatbuffers.Long}
+ */
+u64():flatbuffers.Long {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+  return offset ? this.bb.readUint64(this.bb_pos + offset) : this.bb.createLong(0, 0);
+};
+
+/**
+ * @param {flatbuffers.Long} value
+ * @returns {boolean}
+ */
+mutate_u64(value:flatbuffers.Long):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 18);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+f32():number {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+  return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_f32(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 20);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+f64():number {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+  return offset ? this.bb.readFloat64(this.bb_pos + offset) : 0.0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_f64(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 22);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeFloat64(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+v8(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.readInt8(this.bb.__vector(this.bb_pos + offset) + index) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+v8Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Int8Array}
+ */
+v8Array():Int8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 24);
+  return offset ? new Int8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {number}
+ */
+vf64(index: number):number|null {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.readFloat64(this.bb.__vector(this.bb_pos + offset) + index * 8) : 0;
+};
+
+/**
+ * @returns {number}
+ */
+vf64Length():number {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Float64Array}
+ */
+vf64Array():Float64Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 26);
+  return offset ? new Float64Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTypeAliases(builder:flatbuffers.Builder) {
+  builder.startObject(12);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i8
+ */
+static addI8(builder:flatbuffers.Builder, i8:number) {
+  builder.addFieldInt8(0, i8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u8
+ */
+static addU8(builder:flatbuffers.Builder, u8:number) {
+  builder.addFieldInt8(1, u8, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i16
+ */
+static addI16(builder:flatbuffers.Builder, i16:number) {
+  builder.addFieldInt16(2, i16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u16
+ */
+static addU16(builder:flatbuffers.Builder, u16:number) {
+  builder.addFieldInt16(3, u16, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} i32
+ */
+static addI32(builder:flatbuffers.Builder, i32:number) {
+  builder.addFieldInt32(4, i32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} u32
+ */
+static addU32(builder:flatbuffers.Builder, u32:number) {
+  builder.addFieldInt32(5, u32, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} i64
+ */
+static addI64(builder:flatbuffers.Builder, i64:flatbuffers.Long) {
+  builder.addFieldInt64(6, i64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Long} u64
+ */
+static addU64(builder:flatbuffers.Builder, u64:flatbuffers.Long) {
+  builder.addFieldInt64(7, u64, builder.createLong(0, 0));
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f32
+ */
+static addF32(builder:flatbuffers.Builder, f32:number) {
+  builder.addFieldFloat32(8, f32, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} f64
+ */
+static addF64(builder:flatbuffers.Builder, f64:number) {
+  builder.addFieldFloat64(9, f64, 0.0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} v8Offset
+ */
+static addV8(builder:flatbuffers.Builder, v8Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(10, v8Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createV8Vector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startV8Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} vf64Offset
+ */
+static addVf64(builder:flatbuffers.Builder, vf64Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(11, vf64Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<number>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createVf64Vector(builder:flatbuffers.Builder, data:number[] | Uint8Array):flatbuffers.Offset {
+  builder.startVector(8, data.length, 8);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addFloat64(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startVf64Vector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(8, numElems, 8);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTypeAliases(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
diff --git a/tests/monsterdata_python_wire.mon b/tests/monsterdata_python_wire.mon
index 190f43a..55e37bf 100644
--- a/tests/monsterdata_python_wire.mon
+++ b/tests/monsterdata_python_wire.mon
Binary files differ
diff --git a/tests/monsterdata_test.golden b/tests/monsterdata_test.golden
index 73afc42..e6304b5 100644
--- a/tests/monsterdata_test.golden
+++ b/tests/monsterdata_test.golden
@@ -1,13 +1,13 @@
 {
   pos: {
-    x: 1,
-    y: 2,
-    z: 3,
-    test1: 3,
+    x: 1.0,
+    y: 2.0,
+    z: 3.0,
+    test1: 3.0,
     test2: Green,
     test3: {
-      a: 5,
-      b: 6
+      a: 10,
+      b: 20
     }
   },
   hp: 80,
@@ -17,7 +17,12 @@
     1,
     2,
     3,
-    4
+    4,
+    5,
+    6,
+    7,
+    8,
+    9
   ],
   test_type: Monster,
   test: {
@@ -34,8 +39,22 @@
     }
   ],
   testarrayofstring: [
-    "test1",
-    "test2"
+    "bob",
+    "fred",
+    "bob",
+    "fred"
+  ],
+  testarrayoftables: [
+    {
+      hp: 1000,
+      name: "Barney"
+    },
+    {
+      name: "Fred"
+    },
+    {
+      name: "Wilma"
+    }
   ],
   testhashs32_fnv1: -579221183,
   testhashu32_fnv1: 3715746113,
@@ -44,5 +63,16 @@
   testhashs32_fnv1a: -1904106383,
   testhashu32_fnv1a: 2390860913,
   testhashs64_fnv1a: 4898026182817603057,
-  testhashu64_fnv1a: 4898026182817603057
+  testhashu64_fnv1a: 4898026182817603057,
+  flex: 1234,
+  test5: [
+    {
+      a: 10,
+      b: 20
+    },
+    {
+      a: 30,
+      b: 40
+    }
+  ]
 }
diff --git a/tests/monsterdata_test.json b/tests/monsterdata_test.json
old mode 100755
new mode 100644
index e8e3e1d..fb2d244
--- a/tests/monsterdata_test.json
+++ b/tests/monsterdata_test.json
@@ -19,6 +19,18 @@
     3,
     4
   ],
+  vector_of_longs: [
+      1,
+      100,
+      10000,
+      1000000,
+      100000000
+  ],
+  vector_of_doubles: [
+      -1.7976931348623157e+308,
+      0,
+      1.7976931348623157e+308
+  ],
   test_type: Monster,
   test: {
     name: "Fred",
@@ -34,6 +46,16 @@
       a: 30
     }
   ],
+  test5: [
+    {
+      a: 10,
+      b: 20
+    },
+    {
+      b: "40",
+      a: 30
+    }
+  ],
   testarrayofstring: [
     "test1",
     "test2"
diff --git a/tests/monsterdata_test.mon b/tests/monsterdata_test.mon
index 01bd527..8cb9caf 100644
--- a/tests/monsterdata_test.mon
+++ b/tests/monsterdata_test.mon
Binary files differ
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs
index 5f979fe..1a75ed4 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs
+++ b/tests/namespace_test/NamespaceA/NamespaceB/EnumInNestedNS.cs
@@ -1,4 +1,6 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceA.NamespaceB
 {
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
index 508895f..397fb89 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
+++ b/tests/namespace_test/NamespaceA/NamespaceB/StructInNestedNS.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceA.NamespaceB
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct StructInNestedNS : IFlatbufferObject
 {
diff --git a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
index a2a1c0b..8921744 100644
--- a/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
+++ b/tests/namespace_test/NamespaceA/NamespaceB/TableInNestedNS.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceA.NamespaceB
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct TableInNestedNS : IFlatbufferObject
 {
diff --git a/tests/namespace_test/NamespaceA/SecondTableInA.cs b/tests/namespace_test/NamespaceA/SecondTableInA.cs
index 2048828..99c82cc 100644
--- a/tests/namespace_test/NamespaceA/SecondTableInA.cs
+++ b/tests/namespace_test/NamespaceA/SecondTableInA.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceA
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct SecondTableInA : IFlatbufferObject
 {
diff --git a/tests/namespace_test/NamespaceA/TableInFirstNS.cs b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
index 3b5659a..48b5b20 100644
--- a/tests/namespace_test/NamespaceA/TableInFirstNS.cs
+++ b/tests/namespace_test/NamespaceA/TableInFirstNS.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceA
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct TableInFirstNS : IFlatbufferObject
 {
diff --git a/tests/namespace_test/NamespaceC/TableInC.cs b/tests/namespace_test/NamespaceC/TableInC.cs
index fa53ec5..0c454ac 100644
--- a/tests/namespace_test/NamespaceC/TableInC.cs
+++ b/tests/namespace_test/NamespaceC/TableInC.cs
@@ -1,10 +1,12 @@
-// automatically generated by the FlatBuffers compiler, do not modify
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
 
 namespace NamespaceC
 {
 
-using System;
-using FlatBuffers;
+using global::System;
+using global::FlatBuffers;
 
 public struct TableInC : IFlatbufferObject
 {
diff --git a/tests/namespace_test/NamespaceC/__init__.py b/tests/namespace_test/NamespaceC/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/namespace_test/NamespaceC/__init__.py
diff --git a/tests/namespace_test/namespace_test1_generated.h b/tests/namespace_test/namespace_test1_generated.h
index 9c8c28a..47e6a26 100644
--- a/tests/namespace_test/namespace_test1_generated.h
+++ b/tests/namespace_test/namespace_test1_generated.h
@@ -21,6 +21,15 @@
   EnumInNestedNS_MAX = EnumInNestedNS_C
 };
 
+inline EnumInNestedNS (&EnumValuesEnumInNestedNS())[3] {
+  static EnumInNestedNS values[] = {
+    EnumInNestedNS_A,
+    EnumInNestedNS_B,
+    EnumInNestedNS_C
+  };
+  return values;
+}
+
 inline const char **EnumNamesEnumInNestedNS() {
   static const char *names[] = {
     "A",
@@ -45,9 +54,6 @@
   StructInNestedNS() {
     memset(this, 0, sizeof(StructInNestedNS));
   }
-  StructInNestedNS(const StructInNestedNS &_o) {
-    memcpy(this, &_o, sizeof(StructInNestedNS));
-  }
   StructInNestedNS(int32_t _a, int32_t _b)
       : a_(flatbuffers::EndianScalar(_a)),
         b_(flatbuffers::EndianScalar(_b)) {
@@ -75,7 +81,7 @@
     return GetField<int32_t>(VT_FOO, 0);
   }
   bool mutate_foo(int32_t _foo) {
-    return SetField(VT_FOO, _foo);
+    return SetField<int32_t>(VT_FOO, _foo, 0);
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
@@ -90,13 +96,13 @@
   void add_foo(int32_t foo) {
     fbb_.AddElement<int32_t>(TableInNestedNS::VT_FOO, foo, 0);
   }
-  TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   TableInNestedNSBuilder &operator=(const TableInNestedNSBuilder &);
   flatbuffers::Offset<TableInNestedNS> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<TableInNestedNS>(end);
     return o;
   }
@@ -110,6 +116,59 @@
   return builder_.Finish();
 }
 
+inline flatbuffers::TypeTable *TableInNestedNSTypeTable();
+
+inline flatbuffers::TypeTable *StructInNestedNSTypeTable();
+
+inline flatbuffers::TypeTable *EnumInNestedNSTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    EnumInNestedNSTypeTable
+  };
+  static const char *names[] = {
+    "A",
+    "B",
+    "C"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_ENUM, 3, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *TableInNestedNSTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_INT, 0, -1 }
+  };
+  static const char *names[] = {
+    "foo"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *StructInNestedNSTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_INT, 0, -1 },
+    { flatbuffers::ET_INT, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 4, 8 };
+  static const char *names[] = {
+    "a",
+    "b"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 2, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
 }  // namespace NamespaceB
 }  // namespace NamespaceA
 
diff --git a/tests/namespace_test/namespace_test1_generated.ts b/tests/namespace_test/namespace_test1_generated.ts
new file mode 100644
index 0000000..54d935a
--- /dev/null
+++ b/tests/namespace_test/namespace_test1_generated.ts
@@ -0,0 +1,179 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum
+ */
+export namespace NamespaceA.NamespaceB{
+export enum EnumInNestedNS{
+  A= 0,
+  B= 1,
+  C= 2
+}};
+
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class TableInNestedNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInNestedNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInNestedNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInNestedNS=} obj
+ * @returns {TableInNestedNS}
+ */
+static getRootAsTableInNestedNS(bb:flatbuffers.ByteBuffer, obj?:TableInNestedNS):TableInNestedNS {
+  return (obj || new TableInNestedNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+foo():number {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_foo(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInNestedNS(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} foo
+ */
+static addFoo(builder:flatbuffers.Builder, foo:number) {
+  builder.addFieldInt32(0, foo, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInNestedNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA.NamespaceB{
+export class StructInNestedNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {StructInNestedNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):StructInNestedNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+a():number {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_a(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @returns {number}
+ */
+b():number {
+  return this.bb.readInt32(this.bb_pos + 4);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_b(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} a
+ * @param {number} b
+ * @returns {flatbuffers.Offset}
+ */
+static createStructInNestedNS(builder:flatbuffers.Builder, a: number, b: number):flatbuffers.Offset {
+  builder.prep(4, 8);
+  builder.writeInt32(b);
+  builder.writeInt32(a);
+  return builder.offset();
+};
+
+}
+}
diff --git a/tests/namespace_test/namespace_test2_generated.h b/tests/namespace_test/namespace_test2_generated.h
index 15971ba..a881814 100644
--- a/tests/namespace_test/namespace_test2_generated.h
+++ b/tests/namespace_test/namespace_test2_generated.h
@@ -40,7 +40,7 @@
     return static_cast<NamespaceA::NamespaceB::EnumInNestedNS>(GetField<int8_t>(VT_FOO_ENUM, 0));
   }
   bool mutate_foo_enum(NamespaceA::NamespaceB::EnumInNestedNS _foo_enum) {
-    return SetField(VT_FOO_ENUM, static_cast<int8_t>(_foo_enum));
+    return SetField<int8_t>(VT_FOO_ENUM, static_cast<int8_t>(_foo_enum), 0);
   }
   const NamespaceA::NamespaceB::StructInNestedNS *foo_struct() const {
     return GetStruct<const NamespaceA::NamespaceB::StructInNestedNS *>(VT_FOO_STRUCT);
@@ -50,7 +50,7 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_FOO_TABLE) &&
+           VerifyOffset(verifier, VT_FOO_TABLE) &&
            verifier.VerifyTable(foo_table()) &&
            VerifyField<int8_t>(verifier, VT_FOO_ENUM) &&
            VerifyField<NamespaceA::NamespaceB::StructInNestedNS>(verifier, VT_FOO_STRUCT) &&
@@ -70,13 +70,13 @@
   void add_foo_struct(const NamespaceA::NamespaceB::StructInNestedNS *foo_struct) {
     fbb_.AddStruct(TableInFirstNS::VT_FOO_STRUCT, foo_struct);
   }
-  TableInFirstNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit TableInFirstNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   TableInFirstNSBuilder &operator=(const TableInFirstNSBuilder &);
   flatbuffers::Offset<TableInFirstNS> Finish() {
-    const auto end = fbb_.EndTable(start_, 3);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<TableInFirstNS>(end);
     return o;
   }
@@ -117,9 +117,9 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_REFER_TO_A1) &&
+           VerifyOffset(verifier, VT_REFER_TO_A1) &&
            verifier.VerifyTable(refer_to_a1()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_REFER_TO_A2) &&
+           VerifyOffset(verifier, VT_REFER_TO_A2) &&
            verifier.VerifyTable(refer_to_a2()) &&
            verifier.EndTable();
   }
@@ -134,13 +134,13 @@
   void add_refer_to_a2(flatbuffers::Offset<NamespaceA::SecondTableInA> refer_to_a2) {
     fbb_.AddOffset(TableInC::VT_REFER_TO_A2, refer_to_a2);
   }
-  TableInCBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit TableInCBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   TableInCBuilder &operator=(const TableInCBuilder &);
   flatbuffers::Offset<TableInC> Finish() {
-    const auto end = fbb_.EndTable(start_, 2);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<TableInC>(end);
     return o;
   }
@@ -172,7 +172,7 @@
   }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_REFER_TO_C) &&
+           VerifyOffset(verifier, VT_REFER_TO_C) &&
            verifier.VerifyTable(refer_to_c()) &&
            verifier.EndTable();
   }
@@ -184,13 +184,13 @@
   void add_refer_to_c(flatbuffers::Offset<NamespaceC::TableInC> refer_to_c) {
     fbb_.AddOffset(SecondTableInA::VT_REFER_TO_C, refer_to_c);
   }
-  SecondTableInABuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit SecondTableInABuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   SecondTableInABuilder &operator=(const SecondTableInABuilder &);
   flatbuffers::Offset<SecondTableInA> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<SecondTableInA>(end);
     return o;
   }
@@ -212,6 +212,85 @@
 
 namespace NamespaceA {
 
+inline flatbuffers::TypeTable *TableInFirstNSTypeTable();
+
+}  // namespace NamespaceA
+
+namespace NamespaceC {
+
+inline flatbuffers::TypeTable *TableInCTypeTable();
+
+}  // namespace NamespaceC
+
+namespace NamespaceA {
+
+inline flatbuffers::TypeTable *SecondTableInATypeTable();
+
+inline flatbuffers::TypeTable *TableInFirstNSTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_CHAR, 0, 1 },
+    { flatbuffers::ET_SEQUENCE, 0, 2 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    NamespaceA::NamespaceB::TableInNestedNSTypeTable,
+    NamespaceA::NamespaceB::EnumInNestedNSTypeTable,
+    NamespaceA::NamespaceB::StructInNestedNSTypeTable
+  };
+  static const char *names[] = {
+    "foo_table",
+    "foo_enum",
+    "foo_struct"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 3, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+}  // namespace NamespaceA
+
+namespace NamespaceC {
+
+inline flatbuffers::TypeTable *TableInCTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_SEQUENCE, 0, 1 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    NamespaceA::TableInFirstNSTypeTable,
+    NamespaceA::SecondTableInATypeTable
+  };
+  static const char *names[] = {
+    "refer_to_a1",
+    "refer_to_a2"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 2, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+}  // namespace NamespaceC
+
+namespace NamespaceA {
+
+inline flatbuffers::TypeTable *SecondTableInATypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    NamespaceC::TableInCTypeTable
+  };
+  static const char *names[] = {
+    "refer_to_c"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 1, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
 }  // namespace NamespaceA
 
 #endif  // FLATBUFFERS_GENERATED_NAMESPACETEST2_NAMESPACEA_H_
diff --git a/tests/namespace_test/namespace_test2_generated.js b/tests/namespace_test/namespace_test2_generated.js
index c1c25ef..25db73f 100644
--- a/tests/namespace_test/namespace_test2_generated.js
+++ b/tests/namespace_test/namespace_test2_generated.js
@@ -55,7 +55,7 @@
 
 /**
  * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
- * @returns {NamespaceA.NamespaceB.TableInNestedNS}
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS|null}
  */
 NamespaceA.TableInFirstNS.prototype.fooTable = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 4);
@@ -87,7 +87,7 @@
 
 /**
  * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
- * @returns {NamespaceA.NamespaceB.StructInNestedNS}
+ * @returns {NamespaceA.NamespaceB.StructInNestedNS|null}
  */
 NamespaceA.TableInFirstNS.prototype.fooStruct = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 8);
@@ -171,7 +171,7 @@
 
 /**
  * @param {NamespaceA.TableInFirstNS=} obj
- * @returns {NamespaceA.TableInFirstNS}
+ * @returns {NamespaceA.TableInFirstNS|null}
  */
 NamespaceC.TableInC.prototype.referToA1 = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 4);
@@ -180,7 +180,7 @@
 
 /**
  * @param {NamespaceA.SecondTableInA=} obj
- * @returns {NamespaceA.SecondTableInA}
+ * @returns {NamespaceA.SecondTableInA|null}
  */
 NamespaceC.TableInC.prototype.referToA2 = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 6);
@@ -256,7 +256,7 @@
 
 /**
  * @param {NamespaceC.TableInC=} obj
- * @returns {NamespaceC.TableInC}
+ * @returns {NamespaceC.TableInC|null}
  */
 NamespaceA.SecondTableInA.prototype.referToC = function(obj) {
   var offset = this.bb.__offset(this.bb_pos, 4);
diff --git a/tests/namespace_test/namespace_test2_generated.ts b/tests/namespace_test/namespace_test2_generated.ts
new file mode 100644
index 0000000..8a4aebd
--- /dev/null
+++ b/tests/namespace_test/namespace_test2_generated.ts
@@ -0,0 +1,275 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+import * as NS11563891686210618450 from "./namespace_test1_generated";
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class TableInFirstNS {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInFirstNS}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInFirstNS {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInFirstNS=} obj
+ * @returns {TableInFirstNS}
+ */
+static getRootAsTableInFirstNS(bb:flatbuffers.ByteBuffer, obj?:TableInFirstNS):TableInFirstNS {
+  return (obj || new TableInFirstNS).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.TableInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.TableInNestedNS|null}
+ */
+fooTable(obj?:NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS):NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS|null {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NS11563891686210618450.NamespaceA.NamespaceB.TableInNestedNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @returns {NamespaceA.NamespaceB.EnumInNestedNS}
+ */
+fooEnum():NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? /** @type {NamespaceA.NamespaceB.EnumInNestedNS} */ (this.bb.readInt8(this.bb_pos + offset)) : NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS.A;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} value
+ * @returns {boolean}
+ */
+mutate_foo_enum(value:NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {NamespaceA.NamespaceB.StructInNestedNS=} obj
+ * @returns {NamespaceA.NamespaceB.StructInNestedNS|null}
+ */
+fooStruct(obj?:NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS):NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS|null {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? (obj || new NS11563891686210618450.NamespaceA.NamespaceB.StructInNestedNS).__init(this.bb_pos + offset, this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInFirstNS(builder:flatbuffers.Builder) {
+  builder.startObject(3);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooTableOffset
+ */
+static addFooTable(builder:flatbuffers.Builder, fooTableOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, fooTableOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {NamespaceA.NamespaceB.EnumInNestedNS} fooEnum
+ */
+static addFooEnum(builder:flatbuffers.Builder, fooEnum:NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS) {
+  builder.addFieldInt8(1, fooEnum, NS11563891686210618450.NamespaceA.NamespaceB.EnumInNestedNS.A);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} fooStructOffset
+ */
+static addFooStruct(builder:flatbuffers.Builder, fooStructOffset:flatbuffers.Offset) {
+  builder.addFieldStruct(2, fooStructOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInFirstNS(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceC{
+export class TableInC {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {TableInC}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):TableInC {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {TableInC=} obj
+ * @returns {TableInC}
+ */
+static getRootAsTableInC(bb:flatbuffers.ByteBuffer, obj?:TableInC):TableInC {
+  return (obj || new TableInC).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceA.TableInFirstNS=} obj
+ * @returns {NamespaceA.TableInFirstNS|null}
+ */
+referToA1(obj?:NamespaceA.TableInFirstNS):NamespaceA.TableInFirstNS|null {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NamespaceA.TableInFirstNS).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {NamespaceA.SecondTableInA=} obj
+ * @returns {NamespaceA.SecondTableInA|null}
+ */
+referToA2(obj?:NamespaceA.SecondTableInA):NamespaceA.SecondTableInA|null {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? (obj || new NamespaceA.SecondTableInA).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startTableInC(builder:flatbuffers.Builder) {
+  builder.startObject(2);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA1Offset
+ */
+static addReferToA1(builder:flatbuffers.Builder, referToA1Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, referToA1Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToA2Offset
+ */
+static addReferToA2(builder:flatbuffers.Builder, referToA2Offset:flatbuffers.Offset) {
+  builder.addFieldOffset(1, referToA2Offset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endTableInC(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
+/**
+ * @constructor
+ */
+export namespace NamespaceA{
+export class SecondTableInA {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {SecondTableInA}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):SecondTableInA {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {SecondTableInA=} obj
+ * @returns {SecondTableInA}
+ */
+static getRootAsSecondTableInA(bb:flatbuffers.ByteBuffer, obj?:SecondTableInA):SecondTableInA {
+  return (obj || new SecondTableInA).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {NamespaceC.TableInC=} obj
+ * @returns {NamespaceC.TableInC|null}
+ */
+referToC(obj?:NamespaceC.TableInC):NamespaceC.TableInC|null {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? (obj || new NamespaceC.TableInC).__init(this.bb.__indirect(this.bb_pos + offset), this.bb) : null;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startSecondTableInA(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} referToCOffset
+ */
+static addReferToC(builder:flatbuffers.Builder, referToCOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(0, referToCOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endSecondTableInA(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+}
diff --git a/tests/phpUnionVectorTest.php b/tests/phpUnionVectorTest.php
new file mode 100644
index 0000000..4b5e258
--- /dev/null
+++ b/tests/phpUnionVectorTest.php
@@ -0,0 +1,109 @@
+<?php
+
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Constants.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "ByteBuffer.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "FlatbufferBuilder.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Table.php"));
+require join(DIRECTORY_SEPARATOR, array(dirname(dirname(__FILE__)), "php", "Struct.php"));
+
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Attacker.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'BookReader.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Character.php'));
+require join(DIRECTORY_SEPARATOR, array(dirname(__FILE__), "php", 'Movie.php'));
+
+class Assert {
+    public function ok($result, $message = "") {
+        if (!$result){
+            throw new Exception(!empty($message) ? $message : "{$result} is not true.");
+        }
+    }
+
+    public function Equal($result, $expected, $message = "") {
+        if ($result != $expected) {
+            throw new Exception(!empty($message) ? $message : "given the result {$result} is not equals as {$expected}");
+        }
+    }
+
+
+    public function strictEqual($result, $expected, $message = "") {
+        if ($result !== $expected) {
+            throw new Exception(!empty($message) ? $message : "given the result {$result} is not strict equals as {$expected}");
+        }
+    }
+
+    public function Throws($class, Callable $callback) {
+        try {
+            $callback();
+
+            throw new \Exception("passed statement don't throw an exception.");
+        } catch (\Exception $e) {
+            if (get_class($e) != get_class($class)) {
+                throw new Exception("passed statement doesn't throw " . get_class($class) . ". throwws " . get_class($e));
+            }
+        }
+    }
+}
+
+function main()
+{
+    $assert = new Assert();
+
+    $fbb = new Google\FlatBuffers\FlatBufferBuilder(1);
+
+    $charTypes = [
+        Character::Belle,
+        Character::MuLan,
+        Character::BookFan,
+    ];
+
+    Attacker::startAttacker($fbb);
+    Attacker::addSwordAttackDamage($fbb, 5);
+    $attackerOffset = Attacker::endAttacker($fbb);
+
+    $charTypesOffset = Movie::createCharactersTypeVector($fbb, $charTypes);
+    $charsOffset = Movie::createCharactersVector(
+        $fbb,
+        [
+            BookReader::createBookReader($fbb, 7),
+            $attackerOffset,
+            BookReader::createBookReader($fbb, 2),
+        ]
+    );
+
+    Movie::startMovie($fbb);
+    Movie::addCharactersType($fbb, $charTypesOffset);
+    Movie::addCharacters($fbb, $charsOffset);
+    Movie::finishMovieBuffer($fbb, Movie::endMovie($fbb));
+
+    $buf = Google\FlatBuffers\ByteBuffer::wrap($fbb->dataBuffer()->data());
+
+    $movie = Movie::getRootAsMovie($buf);
+
+    $assert->strictEqual($movie->getCharactersTypeLength(), count($charTypes));
+    $assert->strictEqual($movie->getCharactersLength(), $movie->getCharactersTypeLength());
+
+    for ($i = 0; $i < count($charTypes); ++$i) {
+        $assert->strictEqual($movie->getCharactersType($i), $charTypes[$i]);
+    }
+
+    $bookReader7 = $movie->getCharacters(0, new BookReader());
+    $assert->strictEqual($bookReader7->getBooksRead(), 7);
+
+    $attacker = $movie->getCharacters(1, new Attacker());
+    $assert->strictEqual($attacker->getSwordAttackDamage(), 5);
+
+    $bookReader2 = $movie->getCharacters(2, new BookReader());
+    $assert->strictEqual($bookReader2->getBooksRead(), 2);
+}
+
+try {
+    main();
+    exit(0);
+} catch(Exception $e) {
+    printf("Fatal error: Uncaught exception '%s' with message '%s. in %s:%d\n", get_class($e), $e->getMessage(), $e->getFile(), $e->getLine());
+    printf("Stack trace:\n");
+    echo $e->getTraceAsString() . PHP_EOL;
+    printf("  thrown in in %s:%d\n", $e->getFile(), $e->getLine());
+
+    die(-1);
+}
diff --git a/tests/phpUnionVectorTest.sh b/tests/phpUnionVectorTest.sh
new file mode 100755
index 0000000..a6c3f26
--- /dev/null
+++ b/tests/phpUnionVectorTest.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+set -e
+
+../flatc --php -o php union_vector/union_vector.fbs
+php phpUnionVectorTest.php
+
+echo 'PHP union vector test passed'
diff --git a/tests/prototest/test.golden b/tests/prototest/test.golden
index 2c74413..389133d 100644
--- a/tests/prototest/test.golden
+++ b/tests/prototest/test.golden
@@ -1,6 +1,6 @@
 // Generated from test.proto
 
-namespace _proto._test;
+namespace proto.test;
 
 /// Enum doc comment.
 enum ProtoEnum : int {
@@ -9,14 +9,10 @@
   BAR = 5,
 }
 
-namespace _proto._test;
-
 table ImportedMessage {
   a:int;
 }
 
-namespace _proto._test;
-
 /// 2nd table doc comment with
 /// many lines.
 table ProtoMessage {
@@ -36,13 +32,13 @@
   /// doc comment for l on 2
   /// lines
   l:string (required);
-  m:string;
-  n:_proto._test._ProtoMessage.OtherMessage;
+  m:[ubyte];
+  n:proto.test.ProtoMessage_.OtherMessage;
   o:[string];
-  z:_proto._test.ImportedMessage;
+  z:proto.test.ImportedMessage;
 }
 
-namespace _proto._test._ProtoMessage;
+namespace proto.test.ProtoMessage_;
 
 table OtherMessage {
   a:double;
diff --git a/tests/py_test.py b/tests/py_test.py
index e660944..aeef729 100644
--- a/tests/py_test.py
+++ b/tests/py_test.py
@@ -15,6 +15,7 @@
 
 import os.path
 import sys
+import imp
 PY_VERSION = sys.version_info[:2]
 
 import ctypes
@@ -25,6 +26,7 @@
 
 from flatbuffers import compat
 from flatbuffers.compat import range_func as compat_range
+from flatbuffers.compat import NumpyRequiredForThisFeature
 
 import flatbuffers
 from flatbuffers import number_types as N
@@ -130,6 +132,40 @@
         invsum += int(v)
     asserter(invsum == 10)
 
+    for i in range(5):
+        asserter(monster.VectorOfLongs(i) == 10 ** (i * 2))
+
+    asserter(([-1.7976931348623157e+308, 0, 1.7976931348623157e+308]
+              == [monster.VectorOfDoubles(i)
+                  for i in range(monster.VectorOfDoublesLength())]))
+
+    try:
+        imp.find_module('numpy')
+        # if numpy exists, then we should be able to get the
+        # vector as a numpy array
+        import numpy as np
+
+        asserter(monster.InventoryAsNumpy().sum() == 10)
+        asserter(monster.InventoryAsNumpy().dtype == np.dtype('uint8'))
+
+        VectorOfLongs = monster.VectorOfLongsAsNumpy()
+        asserter(VectorOfLongs.dtype == np.dtype('int64'))
+        for i in range(5):
+            asserter(VectorOfLongs[i] == 10 ** (i * 2))
+
+        VectorOfDoubles = monster.VectorOfDoublesAsNumpy()
+        asserter(VectorOfDoubles.dtype == np.dtype('float64'))
+        asserter(VectorOfDoubles[0] == np.finfo('float64').min)
+        asserter(VectorOfDoubles[1] == 0.0)
+        asserter(VectorOfDoubles[2] == np.finfo('float64').max)
+
+    except ImportError:
+        # If numpy does not exist, trying to get vector as numpy
+        # array should raise NumpyRequiredForThisFeature. The way
+        # assertRaises has been implemented prevents us from
+        # asserting this error is raised outside of a test case.
+        pass
+
     asserter(monster.Test4Length() == 2)
 
     # create a 'Test' object and populate it:
@@ -423,6 +459,17 @@
         self.assertBuilderEquals(b, [4, 0, 0, 0, 4, 5, 6, 7, 0, 0, 0, 0,
                                      3, 0, 0, 0, 1, 2, 3, 0])
 
+    def test_create_byte_vector(self):
+        b = flatbuffers.Builder(0)
+        b.CreateByteVector(b"")
+        # 0-byte pad:
+        self.assertBuilderEquals(b, [0, 0, 0, 0])
+
+        b = flatbuffers.Builder(0)
+        b.CreateByteVector(b"\x01\x02\x03")
+        # 1-byte pad:
+        self.assertBuilderEquals(b, [3, 0, 0, 0, 1, 2, 3, 0])
+
     def test_empty_vtable(self):
         b = flatbuffers.Builder(0)
         b.StartObject(0)
@@ -454,10 +501,10 @@
         b.PrependBoolSlot(0, False, False)
         b.EndObject()
         self.assertBuilderEquals(b, [
-            6, 0,  # vtable bytes
+            4, 0,  # vtable bytes
             4, 0,  # end of object from here
-            0, 0,  # entry 1 is zero
-            6, 0, 0, 0,  # offset for start of vtable (int32)
+            # entry 1 is zero and not stored
+            4, 0, 0, 0,  # offset for start of vtable (int32)
         ])
 
     def test_vtable_with_one_int16(self):
@@ -794,6 +841,20 @@
     b.PrependUOffsetTRelative(test1)
     testArrayOfString = b.EndVector(2)
 
+    MyGame.Example.Monster.MonsterStartVectorOfLongsVector(b, 5)
+    b.PrependInt64(100000000)
+    b.PrependInt64(1000000)
+    b.PrependInt64(10000)
+    b.PrependInt64(100)
+    b.PrependInt64(1)
+    VectorOfLongs = b.EndVector(5)
+
+    MyGame.Example.Monster.MonsterStartVectorOfDoublesVector(b, 3)
+    b.PrependFloat64(1.7976931348623157e+308)
+    b.PrependFloat64(0)
+    b.PrependFloat64(-1.7976931348623157e+308)
+    VectorOfDoubles = b.EndVector(3)
+
     MyGame.Example.Monster.MonsterStart(b)
 
     pos = MyGame.Example.Vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
@@ -806,6 +867,8 @@
     MyGame.Example.Monster.MonsterAddTest(b, mon2)
     MyGame.Example.Monster.MonsterAddTest4(b, test4)
     MyGame.Example.Monster.MonsterAddTestarrayofstring(b, testArrayOfString)
+    MyGame.Example.Monster.MonsterAddVectorOfLongs(b, VectorOfLongs)
+    MyGame.Example.Monster.MonsterAddVectorOfDoubles(b, VectorOfDoubles)
     mon = MyGame.Example.Monster.MonsterEnd(b)
 
     b.Finish(mon)
@@ -843,7 +906,7 @@
         self.assertEqual(100, self.mon.Hp())
 
     def test_default_monster_name(self):
-        self.assertEqual('', self.mon.Name())
+        self.assertEqual(b'', self.mon.Name())
 
     def test_default_monster_inventory_item(self):
         self.assertEqual(0, self.mon.Inventory(0))
@@ -962,6 +1025,15 @@
         self.assertEqual(0, mon2.Testnestedflatbuffer(0))
         self.assertEqual(2, mon2.Testnestedflatbuffer(1))
         self.assertEqual(4, mon2.Testnestedflatbuffer(2))
+        try:
+            imp.find_module('numpy')
+            # if numpy exists, then we should be able to get the
+            # vector as a numpy array
+            self.assertEqual([0, 2, 4], mon2.TestnestedflatbufferAsNumpy().tolist())
+        except ImportError:
+            assertRaises(self,
+                         lambda: mon2.TestnestedflatbufferAsNumpy(),
+                         NumpyRequiredForThisFeature)
 
     def test_nondefault_monster_testempty(self):
         b = flatbuffers.Builder(0)
@@ -1165,6 +1237,13 @@
         assertRaises(self, lambda: b.CreateString(s),
                      flatbuffers.builder.IsNestedError)
 
+    def test_create_byte_vector_is_nested_error(self):
+        b = flatbuffers.Builder(0)
+        b.StartObject(0)
+        s = b'test1'
+        assertRaises(self, lambda: b.CreateByteVector(s),
+                     flatbuffers.builder.IsNestedError)
+
     def test_finished_bytes_error(self):
         b = flatbuffers.Builder(0)
         assertRaises(self, lambda: b.Output(),
diff --git a/tests/test.cpp b/tests/test.cpp
index f74e9a8..dd76c0d 100644
--- a/tests/test.cpp
+++ b/tests/test.cpp
@@ -17,6 +17,8 @@
 #include "flatbuffers/flatbuffers.h"
 #include "flatbuffers/idl.h"
 #include "flatbuffers/util.h"
+#include "flatbuffers/registry.h"
+#include "flatbuffers/minireflect.h"
 
 #include "monster_test_generated.h"
 #include "namespace_test/namespace_test1_generated.h"
@@ -45,8 +47,9 @@
 
 void TestFail(const char *expval, const char *val, const char *exp,
               const char *file, int line) {
-  TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s (%s) != %s", file, line,
-                   exp, expval, val);
+  TEST_OUTPUT_LINE("VALUE: \"%s\"", expval);
+  TEST_OUTPUT_LINE("EXPECTED: \"%s\"", val);
+  TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s", file, line, exp);
   assert(0);
   testing_fails++;
 }
@@ -80,8 +83,10 @@
 }
 void lcg_reset() { lcg_seed = 48271; }
 
+std::string test_data_path = "tests/";
+
 // example of how to build up a serialized buffer algorithmically:
-flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
+flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
   flatbuffers::FlatBufferBuilder builder;
 
   auto vec = Vec3(1, 2, 3, 0, Color_Red, Test(10, 20));
@@ -100,6 +105,21 @@
   Test tests[] = { Test(10, 20), Test(30, 40) };
   auto testv = builder.CreateVectorOfStructs(tests, 2);
 
+
+  #ifndef FLATBUFFERS_CPP98_STL
+    // Create a vector of structures from a lambda.
+    auto testv2 = builder.CreateVectorOfStructs<Test>(
+          2, [&](size_t i, Test* s) -> void {
+            *s = tests[i];
+          });
+  #else
+    // Create a vector of structures using a plain old C++ function.
+    auto testv2 = builder.CreateVectorOfStructs<Test>(
+          2, [](size_t i, Test* s, void *state) -> void {
+            *s = (reinterpret_cast<Test*>(state))[i];
+          }, tests);
+  #endif  // FLATBUFFERS_CPP98_STL
+
   // create monster with very few fields set:
   // (same functionality as CreateMonster below, but sets fields manually)
   flatbuffers::Offset<Monster> mlocs[3];
@@ -118,12 +138,13 @@
   mlocs[2] = mb3.Finish();
 
   // Create an array of strings. Also test string pooling, and lambdas.
-  const char *names[] = { "bob", "fred", "bob", "fred" };
   auto vecofstrings =
       builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(4,
-        [&](size_t i) {
-    return builder.CreateSharedString(names[i]);
-  });
+        [](size_t i, flatbuffers::FlatBufferBuilder *b)
+          -> flatbuffers::Offset<flatbuffers::String> {
+    static const char *names[] = { "bob", "fred", "bob", "fred" };
+    return b->CreateSharedString(names[i]);
+  }, &builder);
 
   // Creating vectors of strings in one convenient call.
   std::vector<std::string> names2;
@@ -134,12 +155,50 @@
   // Create an array of sorted tables, can be used with binary search when read:
   auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
 
+  // Create an array of sorted structs,
+  // can be used with binary search when read:
+  std::vector<Ability> abilities;
+  abilities.push_back(Ability(4, 40));
+  abilities.push_back(Ability(3, 30));
+  abilities.push_back(Ability(2, 20));
+  abilities.push_back(Ability(1, 10));
+  auto vecofstructs = builder.CreateVectorOfSortedStructs(&abilities);
+
+  // Create a nested FlatBuffer.
+  // Nested FlatBuffers are stored in a ubyte vector, which can be convenient
+  // since they can be memcpy'd around much easier than other FlatBuffer
+  // values. They have little overhead compared to storing the table directly.
+  // As a test, create a mostly empty Monster buffer:
+  flatbuffers::FlatBufferBuilder nested_builder;
+  auto nmloc = CreateMonster(nested_builder, nullptr, 0, 0,
+                             nested_builder.CreateString("NestedMonster"));
+  FinishMonsterBuffer(nested_builder, nmloc);
+  // Now we can store the buffer in the parent. Note that by default, vectors
+  // are only aligned to their elements or size field, so in this case if the
+  // buffer contains 64-bit elements, they may not be correctly aligned. We fix
+  // that with:
+  builder.ForceVectorAlignment(nested_builder.GetSize(), sizeof(uint8_t),
+                               nested_builder.GetBufferMinAlignment());
+  // If for whatever reason you don't have the nested_builder available, you
+  // can substitute flatbuffers::largest_scalar_t (64-bit) for the alignment, or
+  // the largest force_align value in your schema if you're using it.
+  auto nested_flatbuffer_vector =
+      builder.CreateVector(nested_builder.GetBufferPointer(),
+                           nested_builder.GetSize());
+
+  // Test a nested FlexBuffer:
+  flexbuffers::Builder flexbuild;
+  flexbuild.Int(1234);
+  flexbuild.Finish();
+  auto flex = builder.CreateVector(flexbuild.GetBuffer());
+
   // shortcut for creating monster with all fields set:
   auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue,
                             Any_Monster, mlocs[1].Union(), // Store a union.
-                            testv, vecofstrings, vecoftables, 0, 0, 0, false,
+                            testv, vecofstrings, vecoftables, 0,
+                            nested_flatbuffer_vector, 0, false,
                             0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f,
-                            vecofstrings2);
+                            vecofstrings2, vecofstructs, flex, testv2);
 
   FinishMonsterBuffer(builder, mloc);
 
@@ -171,10 +230,6 @@
   std::memcpy(&test_buff[0], flatbuf , length);
   std::memcpy(&test_buff[length], flatbuf , length);
 
-  flatbuffers::Verifier verifierl(&test_buff[0], length - 1);
-  TEST_EQ(VerifyMonsterBuffer(verifierl), false);
-  TEST_EQ(verifierl.GetComputedSize(), 0);
-
   flatbuffers::Verifier verifier1(&test_buff[0], length);
   TEST_EQ(VerifyMonsterBuffer(verifier1), true);
   TEST_EQ(verifier1.GetComputedSize(), length);
@@ -249,22 +304,58 @@
   TEST_NOTNULL(vecoftables->LookupByKey("Fred"));
   TEST_NOTNULL(vecoftables->LookupByKey("Wilma"));
 
+  // Test accessing a vector of sorted structs
+  auto vecofstructs = monster->testarrayofsortedstruct();
+  if (vecofstructs) {  // not filled in monster_test.bfbs
+    for (flatbuffers::uoffset_t i = 0; i < vecofstructs->size()-1; i++) {
+      auto left = vecofstructs->Get(i);
+      auto right = vecofstructs->Get(i+1);
+      TEST_EQ(true, (left->KeyCompareLessThan(right)));
+    }
+    TEST_NOTNULL(vecofstructs->LookupByKey(3));
+    TEST_EQ(static_cast<const Ability*>(nullptr), vecofstructs->LookupByKey(5));
+  }
+
+  // Test nested FlatBuffers if available:
+  auto nested_buffer = monster->testnestedflatbuffer();
+  if (nested_buffer) {
+    // nested_buffer is a vector of bytes you can memcpy. However, if you
+    // actually want to access the nested data, this is a convenient
+    // accessor that directly gives you the root table:
+    auto nested_monster = monster->testnestedflatbuffer_nested_root();
+    TEST_EQ_STR(nested_monster->name()->c_str(), "NestedMonster");
+  }
+
+  // Test flexbuffer if available:
+  auto flex = monster->flex();
+  // flex is a vector of bytes you can memcpy etc.
+  TEST_EQ(flex->size(), 4);  // Encoded FlexBuffer bytes.
+  // However, if you actually want to access the nested data, this is a
+  // convenient accessor that directly gives you the root value:
+  TEST_EQ(monster->flex_flexbuffer_root().AsInt16(), 1234);
+
   // Since Flatbuffers uses explicit mechanisms to override the default
   // compiler alignment, double check that the compiler indeed obeys them:
   // (Test consists of a short and byte):
   TEST_EQ(flatbuffers::AlignOf<Test>(), 2UL);
   TEST_EQ(sizeof(Test), 4UL);
 
-  auto tests = monster->test4();
-  TEST_NOTNULL(tests);
-  auto test_0 = tests->Get(0);
-  auto test_1 = tests->Get(1);
-  TEST_EQ(test_0->a(), 10);
-  TEST_EQ(test_0->b(), 20);
-  TEST_EQ(test_1->a(), 30);
-  TEST_EQ(test_1->b(), 40);
-  for (auto it = tests->begin(); it != tests->end(); ++it) {
-    TEST_EQ(it->a() == 10 || it->a() == 30, true);  // Just testing iterators.
+  const flatbuffers::Vector<const Test *>* tests_array[] = {
+    monster->test4(),
+    monster->test5(),
+  };
+  for (size_t i = 0; i < sizeof(tests_array) / sizeof(tests_array[0]); ++i) {
+    auto tests = tests_array[i];
+    TEST_NOTNULL(tests);
+    auto test_0 = tests->Get(0);
+    auto test_1 = tests->Get(1);
+    TEST_EQ(test_0->a(), 10);
+    TEST_EQ(test_0->b(), 20);
+    TEST_EQ(test_1->a(), 30);
+    TEST_EQ(test_1->b(), 40);
+    for (auto it = tests->begin(); it != tests->end(); ++it) {
+      TEST_EQ(it->a() == 10 || it->a() == 30, true);  // Just testing iterators.
+    }
   }
 
   // Checking for presence of fields:
@@ -285,10 +376,23 @@
   auto hp_ok = monster->mutate_hp(10);
   TEST_EQ(hp_ok, true);  // Field was present.
   TEST_EQ(monster->hp(), 10);
+  // Mutate to default value
+  auto hp_ok_default = monster->mutate_hp(100);
+  TEST_EQ(hp_ok_default, true);  // Field was present.
+  TEST_EQ(monster->hp(), 100);
+  // Test that mutate to default above keeps field valid for further mutations
+  auto hp_ok_2 = monster->mutate_hp(20);
+  TEST_EQ(hp_ok_2, true);
+  TEST_EQ(monster->hp(), 20);
   monster->mutate_hp(80);
 
+  // Monster originally at 150 mana (default value)
+  auto mana_default_ok = monster->mutate_mana(150);  // Mutate to default value.
+  TEST_EQ(mana_default_ok, true);  // Mutation should succeed, because default value.
+  TEST_EQ(monster->mana(), 150);
   auto mana_ok = monster->mutate_mana(10);
   TEST_EQ(mana_ok, false);  // Field was NOT present, because default value.
+  TEST_EQ(monster->mana(), 150);
 
   // Mutate structs.
   auto pos = monster->mutable_pos();
@@ -422,6 +526,18 @@
   TEST_EQ_STR(m->name()->c_str(), "bob");
 }
 
+
+void TriviallyCopyableTest() {
+  #if __GNUG__ && __GNUC__ < 5
+    TEST_EQ(__has_trivial_copy(Vec3), true);
+  #else
+    #if __cplusplus >= 201103L
+      TEST_EQ(std::is_trivially_copyable<Vec3>::value, true);
+    #endif
+  #endif
+}
+
+
 // example of parsing text straight into a buffer, and generating
 // text back from it:
 void ParseAndGenerateTextTest() {
@@ -429,13 +545,18 @@
   std::string schemafile;
   std::string jsonfile;
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/monster_test.fbs", false, &schemafile), true);
+    (test_data_path + "monster_test.fbs").c_str(), false, &schemafile), true);
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/monsterdata_test.golden", false, &jsonfile), true);
+    (test_data_path + "monsterdata_test.golden").c_str(), false, &jsonfile),
+    true);
 
   // parse schema first, so we can use it to parse the data after
   flatbuffers::Parser parser;
-  const char *include_directories[] = { "tests", nullptr };
+  auto include_test_path =
+      flatbuffers::ConCatPathFileName(test_data_path, "include_test");
+  const char *include_directories[] = {
+    test_data_path.c_str(), include_test_path.c_str(), nullptr
+  };
   TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
   TEST_EQ(parser.Parse(jsonfile.c_str(), include_directories), true);
 
@@ -446,23 +567,48 @@
                                  parser.builder_.GetSize());
   TEST_EQ(VerifyMonsterBuffer(verifier), true);
 
+  AccessFlatBufferTest(parser.builder_.GetBufferPointer(),
+                       parser.builder_.GetSize(), false);
+
   // to ensure it is correct, we now generate text back from the binary,
   // and compare the two:
   std::string jsongen;
   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   TEST_EQ(result, true);
+  TEST_EQ_STR(jsongen.c_str(), jsonfile.c_str());
 
-  if (jsongen != jsonfile) {
-    printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
-    TEST_NOTNULL(NULL);
-  }
+  // We can also do the above using the convenient Registry that knows about
+  // a set of file_identifiers mapped to schemas.
+  flatbuffers::Registry registry;
+  // Make sure schemas can find their includes.
+  registry.AddIncludeDirectory(test_data_path.c_str());
+  registry.AddIncludeDirectory(include_test_path.c_str());
+  // Call this with many schemas if possible.
+  registry.Register(MonsterIdentifier(),
+                    (test_data_path + "monster_test.fbs").c_str());
+  // Now we got this set up, we can parse by just specifying the identifier,
+  // the correct schema will be loaded on the fly:
+  auto buf = registry.TextToFlatBuffer(jsonfile.c_str(),
+                                       MonsterIdentifier());
+  // If this fails, check registry.lasterror_.
+  TEST_NOTNULL(buf.data());
+  // Test the buffer, to be sure:
+  AccessFlatBufferTest(buf.data(), buf.size(), false);
+  // We can use the registry to turn this back into text, in this case it
+  // will get the file_identifier from the binary:
+  std::string text;
+  auto ok = registry.FlatBufferToText(buf.data(), buf.size(), &text);
+  // If this fails, check registry.lasterror_.
+  TEST_EQ(ok, true);
+  TEST_EQ_STR(text.c_str(), jsonfile.c_str());
 }
 
 void ReflectionTest(uint8_t *flatbuf, size_t length) {
   // Load a binary schema.
   std::string bfbsfile;
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/monster_test.bfbs", true, &bfbsfile), true);
+    (test_data_path + "monster_test.bfbs").c_str(), true, &bfbsfile),
+    true);
 
   // Verify it, just in case:
   flatbuffers::Verifier verifier(
@@ -557,8 +703,8 @@
   // Get the root.
   // This time we wrap the result from GetAnyRoot in a smartpointer that
   // will keep rroot valid as resizingbuf resizes.
-  auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(resizingbuf.data()),
-                                resizingbuf);
+  auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(
+      flatbuffers::vector_data(resizingbuf)), resizingbuf);
   SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
             &resizingbuf);
   // Here resizingbuf has changed, but rroot is still valid.
@@ -604,12 +750,14 @@
   TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
   // Test integrity of all resize operations above.
   flatbuffers::Verifier resize_verifier(
-        reinterpret_cast<const uint8_t *>(resizingbuf.data()),
+        reinterpret_cast<const uint8_t *>(
+            flatbuffers::vector_data(resizingbuf)),
         resizingbuf.size());
   TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
 
   // Test buffer is valid using reflection as well
-  TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), resizingbuf.data(),
+  TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
+                              flatbuffers::vector_data(resizingbuf),
                               resizingbuf.size()), true);
 
   // As an additional test, also set it on the name field.
@@ -634,15 +782,45 @@
                               fbb.GetBufferPointer(), fbb.GetSize()), true);
 }
 
+void MiniReflectFlatBuffersTest(uint8_t *flatbuf) {
+  auto s = flatbuffers::FlatBufferToString(flatbuf, MonsterTypeTable());
+  TEST_EQ_STR(s.c_str(),
+    "{ "
+    "pos: { x: 1.0, y: 2.0, z: 3.0, test1: 0.0, test2: Red, test3: "
+      "{ a: 10, b: 20 } }, "
+    "hp: 80, "
+    "name: \"MyMonster\", "
+    "inventory: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], "
+    "test_type: Monster, "
+    "test: { name: \"Fred\" }, "
+    "test4: [ { a: 10, b: 20 }, { a: 30, b: 40 } ], "
+    "testarrayofstring: [ \"bob\", \"fred\", \"bob\", \"fred\" ], "
+    "testarrayoftables: [ { hp: 1000, name: \"Barney\" }, { name: \"Fred\" }, "
+      "{ name: \"Wilma\" } ], "
+    // TODO(wvo): should really print this nested buffer correctly.
+    "testnestedflatbuffer: [ 20, 0, 0, 0, 77, 79, 78, 83, 12, 0, 12, 0, 0, 0, "
+      "4, 0, 6, 0, 8, 0, 12, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 13, 0, 0, 0, 78, "
+      "101, 115, 116, 101, 100, 77, 111, 110, 115, 116, 101, 114, 0, 0, 0 ], "
+    "testarrayofstring2: [ \"jane\", \"mary\" ], "
+    "testarrayofsortedstruct: [ { id: 1, distance: 10 }, "
+      "{ id: 2, distance: 20 }, { id: 3, distance: 30 }, "
+      "{ id: 4, distance: 40 } ], "
+    "flex: [ 210, 4, 5, 2 ], "
+    "test5: [ { a: 10, b: 20 }, { a: 30, b: 40 } ] "
+    "}");
+}
+
 // Parse a .proto schema, output as .fbs
 void ParseProtoTest() {
   // load the .proto and the golden file from disk
   std::string protofile;
   std::string goldenfile;
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/prototest/test.proto", false, &protofile), true);
+    (test_data_path + "prototest/test.proto").c_str(), false, &protofile),
+    true);
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/prototest/test.golden", false, &goldenfile), true);
+    (test_data_path + "prototest/test.golden").c_str(), false, &goldenfile),
+    true);
 
   flatbuffers::IDLOptions opts;
   opts.include_dependence_headers = false;
@@ -650,7 +828,8 @@
 
   // Parse proto.
   flatbuffers::Parser parser(opts);
-  const char *include_directories[] = { "tests/prototest", nullptr };
+  auto protopath = test_data_path + "prototest/";
+  const char *include_directories[] = { protopath.c_str(), nullptr };
   TEST_EQ(parser.Parse(protofile.c_str(), include_directories), true);
 
   // Generate fbs.
@@ -659,11 +838,7 @@
   // Ensure generated file is parsable.
   flatbuffers::Parser parser2;
   TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
-
-  if (fbs != goldenfile) {
-    printf("%s----------------\n%s", fbs.c_str(), goldenfile.c_str());
-    TEST_NOTNULL(NULL);
-  }
+  TEST_EQ_STR(fbs.c_str(), goldenfile.c_str());
 }
 
 template<typename T> void CompareTableFieldValue(flatbuffers::Table *table,
@@ -722,7 +897,7 @@
         case 10: builder.AddElement<double  >(off, double_val, 0); break;
       }
     }
-    objects[i] = builder.EndTable(start, fields_per_object);
+    objects[i] = builder.EndTable(start);
   }
   builder.PreAlign<flatbuffers::largest_scalar_t>(0);  // Align whole buffer.
 
@@ -827,7 +1002,8 @@
       AddToSchemaAndInstances(("  " + field_name + ":").c_str(),
                               deprecated ? "" : (field_name + ": ").c_str());
       // Pick random type:
-      int base_type = lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1);
+      auto base_type = static_cast<flatbuffers::BaseType>(
+                         lcg_rand() % (flatbuffers::BASE_TYPE_UNION + 1));
       switch (base_type) {
         case flatbuffers::BASE_TYPE_STRING:
           if (is_struct) {
@@ -878,7 +1054,9 @@
             // We want each instance to use its own random value.
             for (int inst = 0; inst < instances_per_definition; inst++)
               definitions[definition].instances[inst] +=
-              flatbuffers::NumToString(lcg_rand() % 128).c_str();
+              flatbuffers::IsFloat(base_type)
+                  ? flatbuffers::NumToString<double>(lcg_rand() % 128).c_str()
+                  : flatbuffers::NumToString<int>(lcg_rand() % 128).c_str();
           }
       }
       AddToSchemaAndInstances(
@@ -919,17 +1097,19 @@
         i -= std::min(static_cast<size_t>(10), i); // show some context;
         size_t end = std::min(len, i + 20);
         for (; i < end; i++)
-          printf("at %d: found \"%c\", expected \"%c\"\n",
-               static_cast<int>(i), jsongen[i], json[i]);
+          TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
+                           static_cast<int>(i), jsongen[i], json[i]);
         break;
       }
     }
     TEST_NOTNULL(NULL);
   }
 
-  printf("%dk schema tested with %dk of json\n",
-         static_cast<int>(schema.length() / 1024),
-         static_cast<int>(json.length() / 1024));
+  #ifdef FLATBUFFERS_TEST_VERBOSE
+    TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
+                     static_cast<int>(schema.length() / 1024),
+                     static_cast<int>(json.length() / 1024));
+  #endif
 }
 
 // Test that parser errors are actually generated.
@@ -947,7 +1127,7 @@
 // Also useful for coverage, making sure these paths are run.
 void ErrorTest() {
   // In order they appear in idl_parser.cpp
-  TestError("table X { Y:byte; } root_type X; { Y: 999 }", "bit field");
+  TestError("table X { Y:byte; } root_type X; { Y: 999 }", "does not fit");
   TestError(".0", "floating point");
   TestError("\"\0", "illegal");
   TestError("\"\\q", "escape code");
@@ -957,6 +1137,7 @@
   TestError("table X { Y:[[int]]; }", "nested vector");
   TestError("table X { Y:1; }", "illegal type");
   TestError("table X { Y:int; Y:int; }", "field already");
+  TestError("table Y {} table X { Y:int; }", "same as table");
   TestError("struct X { Y:string; }", "only scalar");
   TestError("struct X { Y:int (deprecated); }", "deprecate");
   TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
@@ -976,6 +1157,7 @@
   TestError("enum X:float {}", "underlying");
   TestError("enum X:byte { Y, Y }", "value already");
   TestError("enum X:byte { Y=2, Z=1 }", "ascending");
+  TestError("union X { Y = 256 }", "must fit");
   TestError("enum X:byte (bit_flags) { Y=8 }", "bit flag out");
   TestError("table X { Y:int; } table X {", "datatype already");
   TestError("struct X (force_align: 7) { Y:int; }", "force_align");
@@ -1023,6 +1205,13 @@
                               12335089644688340133ULL);
 }
 
+void NestedListTest() {
+  flatbuffers::Parser parser1;
+  TEST_EQ(parser1.Parse("struct Test { a:short; b:byte; } table T { F:[Test]; }"
+                        "root_type T;"
+                        "{ F:[ [10,20], [30,40]] }"), true);
+}
+
 void EnumStringsTest() {
   flatbuffers::Parser parser1;
   TEST_EQ(parser1.Parse("enum E:byte { A, B, C } table T { F:[E]; }"
@@ -1035,32 +1224,51 @@
 }
 
 void IntegerOutOfRangeTest() {
-  TestError("table T { F:byte; } root_type T; { F:256 }",
+  TestError("table T { F:byte; } root_type T; { F:128 }",
             "constant does not fit");
-  TestError("table T { F:byte; } root_type T; { F:-257 }",
+  TestError("table T { F:byte; } root_type T; { F:-129 }",
             "constant does not fit");
   TestError("table T { F:ubyte; } root_type T; { F:256 }",
             "constant does not fit");
-  TestError("table T { F:ubyte; } root_type T; { F:-257 }",
+  TestError("table T { F:ubyte; } root_type T; { F:-1 }",
             "constant does not fit");
-  TestError("table T { F:short; } root_type T; { F:65536 }",
+  TestError("table T { F:short; } root_type T; { F:32768 }",
             "constant does not fit");
-  TestError("table T { F:short; } root_type T; { F:-65537 }",
+  TestError("table T { F:short; } root_type T; { F:-32769 }",
             "constant does not fit");
   TestError("table T { F:ushort; } root_type T; { F:65536 }",
             "constant does not fit");
-  TestError("table T { F:ushort; } root_type T; { F:-65537 }",
+  TestError("table T { F:ushort; } root_type T; { F:-1 }",
             "constant does not fit");
-  TestError("table T { F:int; } root_type T; { F:4294967296 }",
+  TestError("table T { F:int; } root_type T; { F:2147483648 }",
             "constant does not fit");
-  TestError("table T { F:int; } root_type T; { F:-4294967297 }",
+  TestError("table T { F:int; } root_type T; { F:-2147483649 }",
             "constant does not fit");
   TestError("table T { F:uint; } root_type T; { F:4294967296 }",
             "constant does not fit");
-  TestError("table T { F:uint; } root_type T; { F:-4294967297 }",
+  TestError("table T { F:uint; } root_type T; { F:-1 }",
             "constant does not fit");
 }
 
+void IntegerBoundaryTest() {
+  TEST_EQ(TestValue<int8_t>("{ Y:127 }","byte"), 127);
+  TEST_EQ(TestValue<int8_t>("{ Y:-128 }","byte"), -128);
+  TEST_EQ(TestValue<uint8_t>("{ Y:255 }","ubyte"), 255);
+  TEST_EQ(TestValue<uint8_t>("{ Y:0 }","ubyte"), 0);
+  TEST_EQ(TestValue<int16_t>("{ Y:32767 }","short"), 32767);
+  TEST_EQ(TestValue<int16_t>("{ Y:-32768 }","short"), -32768);
+  TEST_EQ(TestValue<uint16_t>("{ Y:65535 }","ushort"), 65535);
+  TEST_EQ(TestValue<uint16_t>("{ Y:0 }","ushort"), 0);
+  TEST_EQ(TestValue<int32_t>("{ Y:2147483647 }","int"), 2147483647);
+  TEST_EQ(TestValue<int32_t>("{ Y:-2147483648 }","int"), (-2147483647 - 1));
+  TEST_EQ(TestValue<uint32_t>("{ Y:4294967295 }","uint"), 4294967295);
+  TEST_EQ(TestValue<uint32_t>("{ Y:0 }","uint"), 0);
+  TEST_EQ(TestValue<int64_t>("{ Y:9223372036854775807 }","long"), 9223372036854775807);
+  TEST_EQ(TestValue<int64_t>("{ Y:-9223372036854775808 }","long"), (-9223372036854775807 - 1));
+  TEST_EQ(TestValue<uint64_t>("{ Y:18446744073709551615 }","ulong"), 18446744073709551615U);
+  TEST_EQ(TestValue<uint64_t>("{ Y:0 }","ulong"), 0);
+}
+
 void UnicodeTest() {
   flatbuffers::Parser parser;
   // Without setting allow_non_utf8 = true, we treat \x sequences as byte sequences
@@ -1074,10 +1282,9 @@
   parser.opts.indent_step = -1;
   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   TEST_EQ(result, true);
-  TEST_EQ(jsongen,
-          std::string(
+  TEST_EQ_STR(jsongen.c_str(),
             "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
-            "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}"));
+            "\\u5225\\u30B5\\u30A4\\u30C8\\u20AC\\u0080\\uD83D\\uDE0E\"}");
 }
 
 void UnicodeTestAllowNonUTF8() {
@@ -1091,10 +1298,9 @@
   parser.opts.indent_step = -1;
   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   TEST_EQ(result, true);
-  TEST_EQ(jsongen,
-          std::string(
+  TEST_EQ_STR(jsongen.c_str(),
             "{F: \"\\u20AC\\u00A2\\u30E6\\u30FC\\u30B6\\u30FC"
-            "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}"));
+            "\\u5225\\u30B5\\u30A4\\u30C8\\u0001\\x80\\u0080\\uD83D\\uDE0E\"}");
 }
 
 void UnicodeTestGenerateTextFailsOnNonUTF8() {
@@ -1126,7 +1332,7 @@
     parser.builder_.GetBufferPointer());
   auto string = root->GetPointer<flatbuffers::String *>(
     flatbuffers::FieldIndexToOffset(0));
-  TEST_EQ(strcmp(string->c_str(), "\xF0\x9F\x92\xA9"), 0);
+  TEST_EQ_STR(string->c_str(), "\xF0\x9F\x92\xA9");
 }
 
 void UnicodeInvalidSurrogatesTest() {
@@ -1263,7 +1469,7 @@
   parser.opts.indent_step = -1;
   auto result = GenerateText(parser, parser.builder_.GetBufferPointer(), &jsongen);
   TEST_EQ(result, true);
-  TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
+  TEST_EQ_STR(jsongen.c_str(), "{str: \"test\",i: 10}");
 }
 
 void ParseUnionTest() {
@@ -1286,78 +1492,142 @@
   // TODO: load a JSON file with such a vector when JSON support is ready.
   std::string schemafile;
   TEST_EQ(flatbuffers::LoadFile(
-    "tests/union_vector/union_vector.fbs", false, &schemafile), true);
+    (test_data_path + "union_vector/union_vector.fbs").c_str(), false,
+    &schemafile), true);
 
   // parse schema.
   flatbuffers::IDLOptions idl_opts;
   idl_opts.lang_to_generate |= flatbuffers::IDLOptions::kCpp;
   flatbuffers::Parser parser(idl_opts);
-  const char *include_directories[] = { "tests/union_vector", nullptr };
-  TEST_EQ(parser.Parse(schemafile.c_str(), include_directories), true);
+  TEST_EQ(parser.Parse(schemafile.c_str()), true);
 
   flatbuffers::FlatBufferBuilder fbb;
 
   // union types.
   std::vector<uint8_t> types;
   types.push_back(static_cast<uint8_t>(Character_Belle));
-  types.push_back(static_cast<uint8_t>(Character_Rapunzel));
   types.push_back(static_cast<uint8_t>(Character_MuLan));
+  types.push_back(static_cast<uint8_t>(Character_BookFan));
+  types.push_back(static_cast<uint8_t>(Character_Other));
+  types.push_back(static_cast<uint8_t>(Character_Unused));
 
   // union values.
   std::vector<flatbuffers::Offset<void>> characters;
-  characters.push_back(CreateBelle(fbb, /*books_read=*/7).Union());
-  characters.push_back(CreateRapunzel(fbb, /*hair_length=*/6).Union());
-  characters.push_back(CreateMuLan(fbb, /*sword_attack_damage=*/5).Union());
+  characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/7)).Union());
+  characters.push_back(CreateAttacker(fbb, /*sword_attack_damage=*/5).Union());
+  characters.push_back(fbb.CreateStruct(BookReader(/*books_read=*/2)).Union());
+  characters.push_back(fbb.CreateString("Other").Union());
+  characters.push_back(fbb.CreateString("Unused").Union());
 
   // create Movie.
   const auto movie_offset =
-      CreateMovie(fbb, fbb.CreateVector(types), fbb.CreateVector(characters));
+      CreateMovie(fbb,
+                  Character_Rapunzel,
+                  fbb.CreateStruct(Rapunzel(/*hair_length=*/6)).Union(),
+                  fbb.CreateVector(types),
+                  fbb.CreateVector(characters));
   FinishMovieBuffer(fbb, movie_offset);
-  uint8_t *buf = fbb.GetBufferPointer();
+  auto buf = fbb.GetBufferPointer();
 
   flatbuffers::Verifier verifier(buf, fbb.GetSize());
   TEST_EQ(VerifyMovieBuffer(verifier), true);
 
-  const Movie *movie = GetMovie(buf);
-  TEST_EQ(movie->characters_type()->size(), 3);
-  TEST_EQ(
-      movie->characters_type()->GetEnum<Character>(0) == Character_Belle,
-      true);
-  TEST_EQ(
-      movie->characters_type()->GetEnum<Character>(1) == Character_Rapunzel,
-      true);
-  TEST_EQ(
-      movie->characters_type()->GetEnum<Character>(2) == Character_MuLan,
-      true);
+  auto flat_movie = GetMovie(buf);
 
-  TEST_EQ(movie->characters()->size(), 3);
-  const Belle *belle =
-      reinterpret_cast<const Belle*>(movie->characters()->Get(0));
-  TEST_EQ(belle->books_read(), 7);
-  const Rapunzel *rapunzel =
-      reinterpret_cast<const Rapunzel*>(movie->characters()->Get(1));
-  TEST_EQ(rapunzel->hair_length(), 6);
-  const MuLan *mu_lan =
-      reinterpret_cast<const MuLan*>(movie->characters()->Get(2));
-  TEST_EQ(mu_lan->sword_attack_damage(), 5);
+  auto TestMovie = [](const Movie *movie) {
+    TEST_EQ(movie->main_character_type() == Character_Rapunzel, true);
+
+    auto cts = movie->characters_type();
+    TEST_EQ(movie->characters_type()->size(), 5);
+    TEST_EQ(cts->GetEnum<Character>(0) == Character_Belle, true);
+    TEST_EQ(cts->GetEnum<Character>(1) == Character_MuLan, true);
+    TEST_EQ(cts->GetEnum<Character>(2) == Character_BookFan, true);
+    TEST_EQ(cts->GetEnum<Character>(3) == Character_Other, true);
+    TEST_EQ(cts->GetEnum<Character>(4) == Character_Unused, true);
+
+    auto rapunzel = movie->main_character_as_Rapunzel();
+    TEST_EQ(rapunzel->hair_length(), 6);
+
+    auto cs = movie->characters();
+    TEST_EQ(cs->size(), 5);
+    auto belle = cs->GetAs<BookReader>(0);
+    TEST_EQ(belle->books_read(), 7);
+    auto mu_lan = cs->GetAs<Attacker>(1);
+    TEST_EQ(mu_lan->sword_attack_damage(), 5);
+    auto book_fan = cs->GetAs<BookReader>(2);
+    TEST_EQ(book_fan->books_read(), 2);
+    auto other = cs->GetAsString(3);
+    TEST_EQ_STR(other->c_str(), "Other");
+    auto unused = cs->GetAsString(4);
+    TEST_EQ_STR(unused->c_str(), "Unused");
+  };
+
+  TestMovie(flat_movie);
+
+  auto movie_object = flat_movie->UnPack();
+  TEST_EQ(movie_object->main_character.AsRapunzel()->hair_length(), 6);
+  TEST_EQ(movie_object->characters[0].AsBelle()->books_read(), 7);
+  TEST_EQ(movie_object->characters[1].AsMuLan()->sword_attack_damage, 5);
+  TEST_EQ(movie_object->characters[2].AsBookFan()->books_read(), 2);
+  TEST_EQ_STR(movie_object->characters[3].AsOther()->c_str(), "Other");
+  TEST_EQ_STR(movie_object->characters[4].AsUnused()->c_str(), "Unused");
+
+  fbb.Clear();
+  fbb.Finish(Movie::Pack(fbb, movie_object));
+
+  delete movie_object;
+
+  auto repacked_movie = GetMovie(fbb.GetBufferPointer());
+
+  TestMovie(repacked_movie);
+
+  auto s = flatbuffers::FlatBufferToString(fbb.GetBufferPointer(),
+                                           MovieTypeTable());
+  TEST_EQ_STR(s.c_str(),
+    "{ main_character_type: Rapunzel, main_character: { hair_length: 6 }, "
+    "characters_type: [ Belle, MuLan, BookFan, Other, Unused ], "
+    "characters: [ { books_read: 7 }, { sword_attack_damage: 5 }, "
+    "{ books_read: 2 }, \"Other\", \"Unused\" ] }");
 }
 
 void ConformTest() {
   flatbuffers::Parser parser;
   TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
 
-  auto test_conform = [&](const char *test, const char *expected_err) {
+  auto test_conform = [](flatbuffers::Parser &parser1,
+                         const char *test, const char *expected_err) {
     flatbuffers::Parser parser2;
     TEST_EQ(parser2.Parse(test), true);
-    auto err = parser2.ConformTo(parser);
+    auto err = parser2.ConformTo(parser1);
     TEST_NOTNULL(strstr(err.c_str(), expected_err));
   };
 
-  test_conform("table T { A:byte; }", "types differ for field");
-  test_conform("table T { B:int; A:int; }", "offsets differ for field");
-  test_conform("table T { A:int = 1; }", "defaults differ for field");
-  test_conform("table T { B:float; }", "field renamed to different type");
-  test_conform("enum E:byte { B, A }", "values differ for enum");
+  test_conform(parser, "table T { A:byte; }", "types differ for field");
+  test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
+  test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
+  test_conform(parser, "table T { B:float; }",
+               "field renamed to different type");
+  test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
+}
+
+void ParseProtoBufAsciiTest() {
+  // We can put the parser in a mode where it will accept JSON that looks more
+  // like Protobuf ASCII, for users that have data in that format.
+  // This uses no "" for field names (which we already support by default,
+  // omits `,`, `:` before `{` and a couple of other features.
+  flatbuffers::Parser parser;
+  parser.opts.protobuf_ascii_alike = true;
+  TEST_EQ(parser.Parse(
+            "table S { B:int; } table T { A:[int]; C:S; } root_type T;"), true);
+  TEST_EQ(parser.Parse("{ A [1 2] C { B:2 }}"), true);
+  // Similarly, in text output, it should omit these.
+  std::string text;
+  auto ok = flatbuffers::GenerateText(parser,
+                                      parser.builder_.GetBufferPointer(),
+                                      &text);
+  TEST_EQ(ok, true);
+  TEST_EQ_STR(text.c_str(),
+              "{\n  A [\n    1\n    2\n  ]\n  C {\n    B: 2\n  }\n}\n");
 }
 
 void FlexBuffersTest() {
@@ -1365,49 +1635,98 @@
                            flexbuffers::BUILDER_FLAG_SHARE_KEYS_AND_STRINGS);
 
   // Write the equivalent of:
-  // { vec: [ -100, "Fred", 4.0 ], bar: [ 1, 2, 3 ], foo: 100 }
-  slb.Map([&]() {
-     slb.Vector("vec", [&]() {
-      slb += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
-      slb += "Fred";
-      slb.IndirectFloat(4.0f);
+  // { vec: [ -100, "Fred", 4.0, false ], bar: [ 1, 2, 3 ], bar3: [ 1, 2, 3 ], foo: 100, bool: true, mymap: { foo: "Fred" } }
+  #ifndef FLATBUFFERS_CPP98_STL
+    // It's possible to do this without std::function support as well.
+    slb.Map([&]() {
+       slb.Vector("vec", [&]() {
+        slb += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
+        slb += "Fred";
+        slb.IndirectFloat(4.0f);
+        uint8_t blob[] = { 77 };
+        slb.Blob(blob, 1);
+        slb += false;
+      });
+      int ints[] = { 1, 2, 3 };
+      slb.Vector("bar", ints, 3);
+      slb.FixedTypedVector("bar3", ints, 3);
+      bool bools[] = {true, false, true, false};
+      slb.Vector("bools", bools, 4);
+      slb.Bool("bool", true);
+      slb.Double("foo", 100);
+      slb.Map("mymap", [&]() {
+        slb.String("foo", "Fred");  // Testing key and string reuse.
+      });
     });
-    int ints[] = { 1, 2, 3 };
-    slb.Vector("bar", ints, 3);
-    slb.FixedTypedVector("bar3", ints, 3);
-    slb.Double("foo", 100);
-    slb.Map("mymap", [&]() {
-      slb.String("foo", "Fred");  // Testing key and string reuse.
-    });
-  });
-  slb.Finish();
+    slb.Finish();
+  #else
+    // It's possible to do this without std::function support as well.
+    slb.Map([](flexbuffers::Builder& slb2) {
+       slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
+        slb3 += -100;  // Equivalent to slb.Add(-100) or slb.Int(-100);
+        slb3 += "Fred";
+        slb3.IndirectFloat(4.0f);
+        uint8_t blob[] = { 77 };
+        slb3.Blob(blob, 1);
+        slb3 += false;
+      }, slb2);
+      int ints[] = { 1, 2, 3 };
+      slb2.Vector("bar", ints, 3);
+      slb2.FixedTypedVector("bar3", ints, 3);
+      slb2.Bool("bool", true);
+      slb2.Double("foo", 100);
+      slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
+        slb3.String("foo", "Fred");  // Testing key and string reuse.
+      }, slb2);
+    }, slb);
+    slb.Finish();
+  #endif  // FLATBUFFERS_CPP98_STL
 
-  for (size_t i = 0; i < slb.GetBuffer().size(); i++)
-    printf("%d ", slb.GetBuffer().data()[i]);
-  printf("\n");
+  #ifdef FLATBUFFERS_TEST_VERBOSE
+    for (size_t i = 0; i < slb.GetBuffer().size(); i++)
+      printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
+    printf("\n");
+  #endif
 
   auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
-  TEST_EQ(map.size(), 5);
+  TEST_EQ(map.size(), 7);
   auto vec = map["vec"].AsVector();
-  TEST_EQ(vec.size(), 3);
+  TEST_EQ(vec.size(), 5);
   TEST_EQ(vec[0].AsInt64(), -100);
   TEST_EQ_STR(vec[1].AsString().c_str(), "Fred");
   TEST_EQ(vec[1].AsInt64(), 0);  // Number parsing failed.
   TEST_EQ(vec[2].AsDouble(), 4.0);
   TEST_EQ(vec[2].AsString().IsTheEmptyString(), true);  // Wrong Type.
   TEST_EQ_STR(vec[2].AsString().c_str(), "");  // This still works though.
-  TEST_EQ_STR(vec[2].ToString().c_str(), "4");  // Or have it converted.
+  TEST_EQ_STR(vec[2].ToString().c_str(), "4.0");  // Or have it converted.
+
+  // Few tests for templated version of As.
+  TEST_EQ(vec[0].As<int64_t>(), -100);
+  TEST_EQ_STR(vec[1].As<std::string>().c_str(), "Fred");
+  TEST_EQ(vec[1].As<int64_t>(), 0);  // Number parsing failed.
+  TEST_EQ(vec[2].As<double>(), 4.0);
+
+  // Test that the blob can be accessed.
+  TEST_EQ(vec[3].IsBlob(), true);
+  auto blob = vec[3].AsBlob();
+  TEST_EQ(blob.size(), 1);
+  TEST_EQ(blob.data()[0], 77);
+  TEST_EQ(vec[4].IsBool(), true);  // Check if type is a bool
+  TEST_EQ(vec[4].AsBool(), false);  // Check if value is false
   auto tvec = map["bar"].AsTypedVector();
   TEST_EQ(tvec.size(), 3);
   TEST_EQ(tvec[2].AsInt8(), 3);
   auto tvec3 = map["bar3"].AsFixedTypedVector();
   TEST_EQ(tvec3.size(), 3);
   TEST_EQ(tvec3[2].AsInt8(), 3);
+  TEST_EQ(map["bool"].AsBool(), true);
+  auto tvecb = map["bools"].AsTypedVector();
+  TEST_EQ(tvecb.ElementType(), flexbuffers::TYPE_BOOL);
   TEST_EQ(map["foo"].AsUInt8(), 100);
   TEST_EQ(map["unknown"].IsNull(), true);
   auto mymap = map["mymap"].AsMap();
   // These should be equal by pointer equality, since key and value are shared.
-  TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[2].AsKey());
+  TEST_EQ(mymap.Keys()[0].AsKey(), map.Keys()[4].AsKey());
   TEST_EQ(mymap.Values()[0].AsString().c_str(), vec[1].AsString().c_str());
   // We can mutate values in the buffer.
   TEST_EQ(vec[0].MutateInt(-99), true);
@@ -1418,28 +1737,124 @@
   TEST_EQ(vec[2].MutateFloat(2.0f), true);
   TEST_EQ(vec[2].AsFloat(), 2.0f);
   TEST_EQ(vec[2].MutateFloat(3.14159), false);  // Double does not fit in float.
+  TEST_EQ(vec[4].AsBool(), false); // Is false before change
+  TEST_EQ(vec[4].MutateBool(true), true); // Can change a bool
+  TEST_EQ(vec[4].AsBool(), true); // Changed bool is now true
+
+  // Parse from JSON:
+  flatbuffers::Parser parser;
+  slb.Clear();
+  auto jsontest = "{ a: [ 123, 456.0 ], b: \"hello\", c: true, d: false }";
+  TEST_EQ(parser.ParseFlexBuffer(jsontest, nullptr, &slb),
+          true);
+  auto jroot = flexbuffers::GetRoot(slb.GetBuffer());
+  auto jmap = jroot.AsMap();
+  auto jvec = jmap["a"].AsVector();
+  TEST_EQ(jvec[0].AsInt64(), 123);
+  TEST_EQ(jvec[1].AsDouble(), 456.0);
+  TEST_EQ_STR(jmap["b"].AsString().c_str(), "hello");
+  TEST_EQ(jmap["c"].IsBool(), true); // Parsed correctly to a bool
+  TEST_EQ(jmap["c"].AsBool(), true); // Parsed correctly to true
+  TEST_EQ(jmap["d"].IsBool(), true); // Parsed correctly to a bool
+  TEST_EQ(jmap["d"].AsBool(), false); // Parsed correctly to false
+  // And from FlexBuffer back to JSON:
+  auto jsonback = jroot.ToString();
+  TEST_EQ_STR(jsontest, jsonback.c_str());
+}
+
+void TypeAliasesTest()
+{
+  flatbuffers::FlatBufferBuilder builder;
+
+  builder.Finish(CreateTypeAliases(
+      builder,
+      flatbuffers::numeric_limits<int8_t>::min(),
+      flatbuffers::numeric_limits<uint8_t>::max(),
+      flatbuffers::numeric_limits<int16_t>::min(),
+      flatbuffers::numeric_limits<uint16_t>::max(),
+      flatbuffers::numeric_limits<int32_t>::min(),
+      flatbuffers::numeric_limits<uint32_t>::max(),
+      flatbuffers::numeric_limits<int64_t>::min(),
+      flatbuffers::numeric_limits<uint64_t>::max(),
+      2.3f, 2.3));
+
+  auto p = builder.GetBufferPointer();
+  auto ta = flatbuffers::GetRoot<TypeAliases>(p);
+
+  TEST_EQ(ta->i8(), flatbuffers::numeric_limits<int8_t>::min());
+  TEST_EQ(ta->u8(), flatbuffers::numeric_limits<uint8_t>::max());
+  TEST_EQ(ta->i16(), flatbuffers::numeric_limits<int16_t>::min());
+  TEST_EQ(ta->u16(), flatbuffers::numeric_limits<uint16_t>::max());
+  TEST_EQ(ta->i32(), flatbuffers::numeric_limits<int32_t>::min());
+  TEST_EQ(ta->u32(), flatbuffers::numeric_limits<uint32_t>::max());
+  TEST_EQ(ta->i64(), flatbuffers::numeric_limits<int64_t>::min());
+  TEST_EQ(ta->u64(), flatbuffers::numeric_limits<uint64_t>::max());
+  TEST_EQ(ta->f32(), 2.3f);
+  TEST_EQ(ta->f64(), 2.3);
+  TEST_EQ(sizeof(ta->i8()), 1);
+  TEST_EQ(sizeof(ta->i16()), 2);
+  TEST_EQ(sizeof(ta->i32()), 4);
+  TEST_EQ(sizeof(ta->i64()), 8);
+  TEST_EQ(sizeof(ta->u8()), 1);
+  TEST_EQ(sizeof(ta->u16()), 2);
+  TEST_EQ(sizeof(ta->u32()), 4);
+  TEST_EQ(sizeof(ta->u64()), 8);
+  TEST_EQ(sizeof(ta->f32()), 4);
+  TEST_EQ(sizeof(ta->f64()), 8);
+}
+
+void EndianSwapTest() {
+  TEST_EQ(flatbuffers::EndianSwap(static_cast<int16_t>(0x1234)),
+          0x3412);
+  TEST_EQ(flatbuffers::EndianSwap(static_cast<int32_t>(0x12345678)),
+          0x78563412);
+  TEST_EQ(flatbuffers::EndianSwap(static_cast<int64_t>(0x1234567890ABCDEF)),
+          0xEFCDAB9078563412);
+  TEST_EQ(flatbuffers::EndianSwap(flatbuffers::EndianSwap(3.14f)), 3.14f);
 }
 
 int main(int /*argc*/, const char * /*argv*/[]) {
+  #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && \
+      defined(_MSC_VER) && defined(_DEBUG)
+    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF
+      // For more thorough checking:
+      //| _CRTDBG_CHECK_ALWAYS_DF | _CRTDBG_DELAY_FREE_MEM_DF
+    );
+  #endif
+
   // Run our various test suites:
 
   std::string rawbuf;
-  auto flatbuf = CreateFlatBufferTest(rawbuf);
+  auto flatbuf1 = CreateFlatBufferTest(rawbuf);
+  #if !defined(FLATBUFFERS_CPP98_STL)
+    auto flatbuf = std::move(flatbuf1);  // Test move assignment.
+  #else
+    auto &flatbuf = flatbuf1;
+  #endif // !defined(FLATBUFFERS_CPP98_STL)
+
+  TriviallyCopyableTest();
+
   AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
                        rawbuf.length());
-  AccessFlatBufferTest(flatbuf.get(), rawbuf.length());
+  AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
 
-  MutateFlatBuffersTest(flatbuf.get(), rawbuf.length());
+  MutateFlatBuffersTest(flatbuf.data(), flatbuf.size());
 
-  ObjectFlatBuffersTest(flatbuf.get());
+  ObjectFlatBuffersTest(flatbuf.data());
+
+  MiniReflectFlatBuffersTest(flatbuf.data());
 
   SizePrefixedTest();
 
   #ifndef FLATBUFFERS_NO_FILE_TESTS
-  ParseAndGenerateTextTest();
-  ReflectionTest(flatbuf.get(), rawbuf.length());
-  ParseProtoTest();
-  UnionVectorTest();
+    #ifdef FLATBUFFERS_TEST_PATH_PREFIX
+      test_data_path = FLATBUFFERS_STRING(FLATBUFFERS_TEST_PATH_PREFIX) +
+                       test_data_path;
+    #endif
+    ParseAndGenerateTextTest();
+    ReflectionTest(flatbuf.data(), flatbuf.size());
+    ParseProtoTest();
+    UnionVectorTest();
   #endif
 
   FuzzTest1();
@@ -1449,6 +1864,7 @@
   ValueTest();
   EnumStringsTest();
   IntegerOutOfRangeTest();
+  IntegerBoundaryTest();
   UnicodeTest();
   UnicodeTestAllowNonUTF8();
   UnicodeTestGenerateTextFailsOnNonUTF8();
@@ -1458,6 +1874,9 @@
   UnknownFieldsTest();
   ParseUnionTest();
   ConformTest();
+  ParseProtoBufAsciiTest();
+  TypeAliasesTest();
+  EndianSwapTest();
 
   FlexBuffersTest();
 
@@ -1469,4 +1888,3 @@
     return 1;
   }
 }
-
diff --git a/tests/union_vector/Attacker.php b/tests/union_vector/Attacker.php
new file mode 100644
index 0000000..e3ebfe6
--- /dev/null
+++ b/tests/union_vector/Attacker.php
@@ -0,0 +1,92 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Attacker extends Table
+{
+    /**
+     * @param ByteBuffer $bb
+     * @return Attacker
+     */
+    public static function getRootAsAttacker(ByteBuffer $bb)
+    {
+        $obj = new Attacker();
+        return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+    }
+
+    public static function AttackerIdentifier()
+    {
+        return "MOVI";
+    }
+
+    public static function AttackerBufferHasIdentifier(ByteBuffer $buf)
+    {
+        return self::__has_identifier($buf, self::AttackerIdentifier());
+    }
+
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return Attacker
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function getSwordAttackDamage()
+    {
+        $o = $this->__offset(4);
+        return $o != 0 ? $this->bb->getInt($o + $this->bb_pos) : 0;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return void
+     */
+    public static function startAttacker(FlatBufferBuilder $builder)
+    {
+        $builder->StartObject(1);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return Attacker
+     */
+    public static function createAttacker(FlatBufferBuilder $builder, $sword_attack_damage)
+    {
+        $builder->startObject(1);
+        self::addSwordAttackDamage($builder, $sword_attack_damage);
+        $o = $builder->endObject();
+        return $o;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int
+     * @return void
+     */
+    public static function addSwordAttackDamage(FlatBufferBuilder $builder, $swordAttackDamage)
+    {
+        $builder->addIntX(0, $swordAttackDamage, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return int table offset
+     */
+    public static function endAttacker(FlatBufferBuilder $builder)
+    {
+        $o = $builder->endObject();
+        return $o;
+    }
+}
diff --git a/tests/union_vector/BookReader.php b/tests/union_vector/BookReader.php
new file mode 100644
index 0000000..1f8f8d8
--- /dev/null
+++ b/tests/union_vector/BookReader.php
@@ -0,0 +1,41 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class BookReader extends Struct
+{
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return BookReader
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function GetBooksRead()
+    {
+        return $this->bb->getInt($this->bb_pos + 0);
+    }
+
+
+    /**
+     * @return int offset
+     */
+    public static function createBookReader(FlatBufferBuilder $builder, $booksRead)
+    {
+        $builder->prep(4, 4);
+        $builder->putInt($booksRead);
+        return $builder->offset();
+    }
+}
diff --git a/tests/union_vector/Character.php b/tests/union_vector/Character.php
new file mode 100644
index 0000000..bf73c36
--- /dev/null
+++ b/tests/union_vector/Character.php
@@ -0,0 +1,31 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+class Character
+{
+    const NONE = 0;
+    const MuLan = 1;
+    const Rapunzel = 2;
+    const Belle = 3;
+    const BookFan = 4;
+    const Other = 5;
+    const Unused = 6;
+
+    private static $names = array(
+        "NONE",
+        "MuLan",
+        "Rapunzel",
+        "Belle",
+        "BookFan",
+        "Other",
+        "Unused",
+    );
+
+    public static function Name($e)
+    {
+        if (!isset(self::$names[$e])) {
+            throw new \Exception();
+        }
+        return self::$names[$e];
+    }
+}
diff --git a/tests/union_vector/Movie.php b/tests/union_vector/Movie.php
new file mode 100644
index 0000000..9baad5a
--- /dev/null
+++ b/tests/union_vector/Movie.php
@@ -0,0 +1,220 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Movie extends Table
+{
+    /**
+     * @param ByteBuffer $bb
+     * @return Movie
+     */
+    public static function getRootAsMovie(ByteBuffer $bb)
+    {
+        $obj = new Movie();
+        return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
+    }
+
+    public static function MovieIdentifier()
+    {
+        return "MOVI";
+    }
+
+    public static function MovieBufferHasIdentifier(ByteBuffer $buf)
+    {
+        return self::__has_identifier($buf, self::MovieIdentifier());
+    }
+
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return Movie
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return byte
+     */
+    public function getMainCharacterType()
+    {
+        $o = $this->__offset(4);
+        return $o != 0 ? $this->bb->getByte($o + $this->bb_pos) : \Character::NONE;
+    }
+
+    /**
+     * @returnint
+     */
+    public function getMainCharacter($obj)
+    {
+        $o = $this->__offset(6);
+        return $o != 0 ? $this->__union($obj, $o) : null;
+    }
+
+    /**
+     * @param int offset
+     * @return byte
+     */
+    public function getCharactersType($j)
+    {
+        $o = $this->__offset(8);
+        return $o != 0 ? $this->bb->getByte($this->__vector($o) + $j * 1) : \Character::NONE;
+    }
+
+    /**
+     * @return int
+     */
+    public function getCharactersTypeLength()
+    {
+        $o = $this->__offset(8);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param int offset
+     * @return Table
+     */
+    public function getCharacters($j, $obj)
+    {
+        $o = $this->__offset(10);
+        return $o != 0 ? $this->__union($obj, $this->__vector($o) + $j * 4 - $this->bb_pos) : null;
+    }
+
+    /**
+     * @return int
+     */
+    public function getCharactersLength()
+    {
+        $o = $this->__offset(10);
+        return $o != 0 ? $this->__vector_len($o) : 0;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return void
+     */
+    public static function startMovie(FlatBufferBuilder $builder)
+    {
+        $builder->StartObject(4);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return Movie
+     */
+    public static function createMovie(FlatBufferBuilder $builder, $main_character_type, $main_character, $characters_type, $characters)
+    {
+        $builder->startObject(4);
+        self::addMainCharacterType($builder, $main_character_type);
+        self::addMainCharacter($builder, $main_character);
+        self::addCharactersType($builder, $characters_type);
+        self::addCharacters($builder, $characters);
+        $o = $builder->endObject();
+        return $o;
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param byte
+     * @return void
+     */
+    public static function addMainCharacterType(FlatBufferBuilder $builder, $mainCharacterType)
+    {
+        $builder->addByteX(0, $mainCharacterType, 0);
+    }
+
+    public static function addMainCharacter(FlatBufferBuilder $builder, $offset)
+    {
+        $builder->addOffsetX(1, $offset, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addCharactersType(FlatBufferBuilder $builder, $charactersType)
+    {
+        $builder->addOffsetX(2, $charactersType, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createCharactersTypeVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(1, count($data), 1);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addByte($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startCharactersTypeVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(1, $numElems, 1);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param VectorOffset
+     * @return void
+     */
+    public static function addCharacters(FlatBufferBuilder $builder, $characters)
+    {
+        $builder->addOffsetX(3, $characters, 0);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param array offset array
+     * @return int vector offset
+     */
+    public static function createCharactersVector(FlatBufferBuilder $builder, array $data)
+    {
+        $builder->startVector(4, count($data), 4);
+        for ($i = count($data) - 1; $i >= 0; $i--) {
+            $builder->addOffset($data[$i]);
+        }
+        return $builder->endVector();
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @param int $numElems
+     * @return void
+     */
+    public static function startCharactersVector(FlatBufferBuilder $builder, $numElems)
+    {
+        $builder->startVector(4, $numElems, 4);
+    }
+
+    /**
+     * @param FlatBufferBuilder $builder
+     * @return int table offset
+     */
+    public static function endMovie(FlatBufferBuilder $builder)
+    {
+        $o = $builder->endObject();
+        return $o;
+    }
+
+    public static function finishMovieBuffer(FlatBufferBuilder $builder, $offset)
+    {
+        $builder->finish($offset, "MOVI");
+    }
+}
diff --git a/tests/union_vector/Rapunzel.php b/tests/union_vector/Rapunzel.php
new file mode 100644
index 0000000..9842d95
--- /dev/null
+++ b/tests/union_vector/Rapunzel.php
@@ -0,0 +1,41 @@
+<?php
+// automatically generated by the FlatBuffers compiler, do not modify
+
+use \Google\FlatBuffers\Struct;
+use \Google\FlatBuffers\Table;
+use \Google\FlatBuffers\ByteBuffer;
+use \Google\FlatBuffers\FlatBufferBuilder;
+
+class Rapunzel extends Struct
+{
+    /**
+     * @param int $_i offset
+     * @param ByteBuffer $_bb
+     * @return Rapunzel
+     **/
+    public function init($_i, ByteBuffer $_bb)
+    {
+        $this->bb_pos = $_i;
+        $this->bb = $_bb;
+        return $this;
+    }
+
+    /**
+     * @return int
+     */
+    public function GetHairLength()
+    {
+        return $this->bb->getInt($this->bb_pos + 0);
+    }
+
+
+    /**
+     * @return int offset
+     */
+    public static function createRapunzel(FlatBufferBuilder $builder, $hairLength)
+    {
+        $builder->prep(4, 4);
+        $builder->putInt($hairLength);
+        return $builder->offset();
+    }
+}
diff --git a/tests/union_vector/union_vector.fbs b/tests/union_vector/union_vector.fbs
index 4957cd8..495076f 100644
--- a/tests/union_vector/union_vector.fbs
+++ b/tests/union_vector/union_vector.fbs
@@ -1,22 +1,29 @@
-table MuLan {
+// Demonstrates the ability to have vectors of unions, and also to
+// store structs and strings in unions.
+
+table Attacker {
   sword_attack_damage: int;
 }
 
-table Rapunzel {
+struct Rapunzel {
   hair_length: int;
 }
 
-table Belle {
+struct BookReader {
   books_read: int;
 }
 
 union Character {
-  MuLan,
-  Rapunzel,
-  Belle,
+  MuLan: Attacker,  // Can have name be different from type.
+  Rapunzel,         // Or just both the same, as before.
+  Belle: BookReader,
+  BookFan: BookReader,
+  Other: string,
+  Unused: string
 }
 
 table Movie {
+  main_character: Character;
   characters: [Character];
 }
 
diff --git a/tests/union_vector/union_vector_generated.h b/tests/union_vector/union_vector_generated.h
index 560860c..3222fb0 100644
--- a/tests/union_vector/union_vector_generated.h
+++ b/tests/union_vector/union_vector_generated.h
@@ -6,29 +6,50 @@
 
 #include "flatbuffers/flatbuffers.h"
 
-struct MuLan;
+struct Attacker;
+struct AttackerT;
 
 struct Rapunzel;
 
-struct Belle;
+struct BookReader;
 
 struct Movie;
+struct MovieT;
 
 enum Character {
   Character_NONE = 0,
   Character_MuLan = 1,
   Character_Rapunzel = 2,
   Character_Belle = 3,
+  Character_BookFan = 4,
+  Character_Other = 5,
+  Character_Unused = 6,
   Character_MIN = Character_NONE,
-  Character_MAX = Character_Belle
+  Character_MAX = Character_Unused
 };
 
+inline Character (&EnumValuesCharacter())[7] {
+  static Character values[] = {
+    Character_NONE,
+    Character_MuLan,
+    Character_Rapunzel,
+    Character_Belle,
+    Character_BookFan,
+    Character_Other,
+    Character_Unused
+  };
+  return values;
+}
+
 inline const char **EnumNamesCharacter() {
   static const char *names[] = {
     "NONE",
     "MuLan",
     "Rapunzel",
     "Belle",
+    "BookFan",
+    "Other",
+    "Unused",
     nullptr
   };
   return names;
@@ -39,183 +60,274 @@
   return EnumNamesCharacter()[index];
 }
 
-template<typename T> struct CharacterTraits {
-  static const Character enum_value = Character_NONE;
-};
+struct CharacterUnion {
+  Character type;
+  void *value;
 
-template<> struct CharacterTraits<MuLan> {
-  static const Character enum_value = Character_MuLan;
-};
+  CharacterUnion() : type(Character_NONE), value(nullptr) {}
+  CharacterUnion(CharacterUnion&& u) FLATBUFFERS_NOEXCEPT :
+    type(Character_NONE), value(nullptr)
+    { std::swap(type, u.type); std::swap(value, u.value); }
+  CharacterUnion(const CharacterUnion &) FLATBUFFERS_NOEXCEPT;
+  CharacterUnion &operator=(const CharacterUnion &u) FLATBUFFERS_NOEXCEPT
+    { CharacterUnion t(u); std::swap(type, t.type); std::swap(value, t.value); return *this; }
+  CharacterUnion &operator=(CharacterUnion &&u) FLATBUFFERS_NOEXCEPT
+    { std::swap(type, u.type); std::swap(value, u.value); return *this; }
+  ~CharacterUnion() { Reset(); }
 
-template<> struct CharacterTraits<Rapunzel> {
-  static const Character enum_value = Character_Rapunzel;
-};
+  void Reset();
 
-template<> struct CharacterTraits<Belle> {
-  static const Character enum_value = Character_Belle;
+  static void *UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver);
+  flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
+
+  AttackerT *AsMuLan() {
+    return type == Character_MuLan ?
+      reinterpret_cast<AttackerT *>(value) : nullptr;
+  }
+  const AttackerT *AsMuLan() const {
+    return type == Character_MuLan ?
+      reinterpret_cast<const AttackerT *>(value) : nullptr;
+  }
+  Rapunzel *AsRapunzel() {
+    return type == Character_Rapunzel ?
+      reinterpret_cast<Rapunzel *>(value) : nullptr;
+  }
+  const Rapunzel *AsRapunzel() const {
+    return type == Character_Rapunzel ?
+      reinterpret_cast<const Rapunzel *>(value) : nullptr;
+  }
+  BookReader *AsBelle() {
+    return type == Character_Belle ?
+      reinterpret_cast<BookReader *>(value) : nullptr;
+  }
+  const BookReader *AsBelle() const {
+    return type == Character_Belle ?
+      reinterpret_cast<const BookReader *>(value) : nullptr;
+  }
+  BookReader *AsBookFan() {
+    return type == Character_BookFan ?
+      reinterpret_cast<BookReader *>(value) : nullptr;
+  }
+  const BookReader *AsBookFan() const {
+    return type == Character_BookFan ?
+      reinterpret_cast<const BookReader *>(value) : nullptr;
+  }
+  std::string *AsOther() {
+    return type == Character_Other ?
+      reinterpret_cast<std::string *>(value) : nullptr;
+  }
+  const std::string *AsOther() const {
+    return type == Character_Other ?
+      reinterpret_cast<const std::string *>(value) : nullptr;
+  }
+  std::string *AsUnused() {
+    return type == Character_Unused ?
+      reinterpret_cast<std::string *>(value) : nullptr;
+  }
+  const std::string *AsUnused() const {
+    return type == Character_Unused ?
+      reinterpret_cast<const std::string *>(value) : nullptr;
+  }
 };
 
 bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type);
 bool VerifyCharacterVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
 
-struct MuLan FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+MANUALLY_ALIGNED_STRUCT(4) Rapunzel FLATBUFFERS_FINAL_CLASS {
+ private:
+  int32_t hair_length_;
+
+ public:
+  Rapunzel() {
+    memset(this, 0, sizeof(Rapunzel));
+  }
+  Rapunzel(int32_t _hair_length)
+      : hair_length_(flatbuffers::EndianScalar(_hair_length)) {
+  }
+  int32_t hair_length() const {
+    return flatbuffers::EndianScalar(hair_length_);
+  }
+  void mutate_hair_length(int32_t _hair_length) {
+    flatbuffers::WriteScalar(&hair_length_, _hair_length);
+  }
+};
+STRUCT_END(Rapunzel, 4);
+
+MANUALLY_ALIGNED_STRUCT(4) BookReader FLATBUFFERS_FINAL_CLASS {
+ private:
+  int32_t books_read_;
+
+ public:
+  BookReader() {
+    memset(this, 0, sizeof(BookReader));
+  }
+  BookReader(int32_t _books_read)
+      : books_read_(flatbuffers::EndianScalar(_books_read)) {
+  }
+  int32_t books_read() const {
+    return flatbuffers::EndianScalar(books_read_);
+  }
+  void mutate_books_read(int32_t _books_read) {
+    flatbuffers::WriteScalar(&books_read_, _books_read);
+  }
+};
+STRUCT_END(BookReader, 4);
+
+struct AttackerT : public flatbuffers::NativeTable {
+  typedef Attacker TableType;
+  int32_t sword_attack_damage;
+  AttackerT()
+      : sword_attack_damage(0) {
+  }
+};
+
+struct Attacker FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef AttackerT NativeTableType;
   enum {
     VT_SWORD_ATTACK_DAMAGE = 4
   };
   int32_t sword_attack_damage() const {
     return GetField<int32_t>(VT_SWORD_ATTACK_DAMAGE, 0);
   }
+  bool mutate_sword_attack_damage(int32_t _sword_attack_damage) {
+    return SetField<int32_t>(VT_SWORD_ATTACK_DAMAGE, _sword_attack_damage, 0);
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<int32_t>(verifier, VT_SWORD_ATTACK_DAMAGE) &&
            verifier.EndTable();
   }
+  AttackerT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<Attacker> Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 };
 
-struct MuLanBuilder {
+struct AttackerBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
   void add_sword_attack_damage(int32_t sword_attack_damage) {
-    fbb_.AddElement<int32_t>(MuLan::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0);
+    fbb_.AddElement<int32_t>(Attacker::VT_SWORD_ATTACK_DAMAGE, sword_attack_damage, 0);
   }
-  MuLanBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit AttackerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
-  MuLanBuilder &operator=(const MuLanBuilder &);
-  flatbuffers::Offset<MuLan> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
-    auto o = flatbuffers::Offset<MuLan>(end);
+  AttackerBuilder &operator=(const AttackerBuilder &);
+  flatbuffers::Offset<Attacker> Finish() {
+    const auto end = fbb_.EndTable(start_);
+    auto o = flatbuffers::Offset<Attacker>(end);
     return o;
   }
 };
 
-inline flatbuffers::Offset<MuLan> CreateMuLan(
+inline flatbuffers::Offset<Attacker> CreateAttacker(
     flatbuffers::FlatBufferBuilder &_fbb,
     int32_t sword_attack_damage = 0) {
-  MuLanBuilder builder_(_fbb);
+  AttackerBuilder builder_(_fbb);
   builder_.add_sword_attack_damage(sword_attack_damage);
   return builder_.Finish();
 }
 
-struct Rapunzel FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_HAIR_LENGTH = 4
-  };
-  int32_t hair_length() const {
-    return GetField<int32_t>(VT_HAIR_LENGTH, 0);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int32_t>(verifier, VT_HAIR_LENGTH) &&
-           verifier.EndTable();
+flatbuffers::Offset<Attacker> CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct MovieT : public flatbuffers::NativeTable {
+  typedef Movie TableType;
+  CharacterUnion main_character;
+  std::vector<CharacterUnion> characters;
+  MovieT() {
   }
 };
 
-struct RapunzelBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_hair_length(int32_t hair_length) {
-    fbb_.AddElement<int32_t>(Rapunzel::VT_HAIR_LENGTH, hair_length, 0);
-  }
-  RapunzelBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
-  }
-  RapunzelBuilder &operator=(const RapunzelBuilder &);
-  flatbuffers::Offset<Rapunzel> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
-    auto o = flatbuffers::Offset<Rapunzel>(end);
-    return o;
-  }
-};
-
-inline flatbuffers::Offset<Rapunzel> CreateRapunzel(
-    flatbuffers::FlatBufferBuilder &_fbb,
-    int32_t hair_length = 0) {
-  RapunzelBuilder builder_(_fbb);
-  builder_.add_hair_length(hair_length);
-  return builder_.Finish();
-}
-
-struct Belle FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  enum {
-    VT_BOOKS_READ = 4
-  };
-  int32_t books_read() const {
-    return GetField<int32_t>(VT_BOOKS_READ, 0);
-  }
-  bool Verify(flatbuffers::Verifier &verifier) const {
-    return VerifyTableStart(verifier) &&
-           VerifyField<int32_t>(verifier, VT_BOOKS_READ) &&
-           verifier.EndTable();
-  }
-};
-
-struct BelleBuilder {
-  flatbuffers::FlatBufferBuilder &fbb_;
-  flatbuffers::uoffset_t start_;
-  void add_books_read(int32_t books_read) {
-    fbb_.AddElement<int32_t>(Belle::VT_BOOKS_READ, books_read, 0);
-  }
-  BelleBuilder(flatbuffers::FlatBufferBuilder &_fbb)
-        : fbb_(_fbb) {
-    start_ = fbb_.StartTable();
-  }
-  BelleBuilder &operator=(const BelleBuilder &);
-  flatbuffers::Offset<Belle> Finish() {
-    const auto end = fbb_.EndTable(start_, 1);
-    auto o = flatbuffers::Offset<Belle>(end);
-    return o;
-  }
-};
-
-inline flatbuffers::Offset<Belle> CreateBelle(
-    flatbuffers::FlatBufferBuilder &_fbb,
-    int32_t books_read = 0) {
-  BelleBuilder builder_(_fbb);
-  builder_.add_books_read(books_read);
-  return builder_.Finish();
-}
-
 struct Movie FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef MovieT NativeTableType;
   enum {
-    VT_CHARACTERS_TYPE = 4,
-    VT_CHARACTERS = 6
+    VT_MAIN_CHARACTER_TYPE = 4,
+    VT_MAIN_CHARACTER = 6,
+    VT_CHARACTERS_TYPE = 8,
+    VT_CHARACTERS = 10
   };
+  Character main_character_type() const {
+    return static_cast<Character>(GetField<uint8_t>(VT_MAIN_CHARACTER_TYPE, 0));
+  }
+  bool mutate_main_character_type(Character _main_character_type) {
+    return SetField<uint8_t>(VT_MAIN_CHARACTER_TYPE, static_cast<uint8_t>(_main_character_type), 0);
+  }
+  const void *main_character() const {
+    return GetPointer<const void *>(VT_MAIN_CHARACTER);
+  }
+  template<typename T> const T *main_character_as() const;
+  const Attacker *main_character_as_MuLan() const {
+    return main_character_type() == Character_MuLan ? static_cast<const Attacker *>(main_character()) : nullptr;
+  }
+  const Rapunzel *main_character_as_Rapunzel() const {
+    return main_character_type() == Character_Rapunzel ? static_cast<const Rapunzel *>(main_character()) : nullptr;
+  }
+  const BookReader *main_character_as_Belle() const {
+    return main_character_type() == Character_Belle ? static_cast<const BookReader *>(main_character()) : nullptr;
+  }
+  const BookReader *main_character_as_BookFan() const {
+    return main_character_type() == Character_BookFan ? static_cast<const BookReader *>(main_character()) : nullptr;
+  }
+  const flatbuffers::String *main_character_as_Other() const {
+    return main_character_type() == Character_Other ? static_cast<const flatbuffers::String *>(main_character()) : nullptr;
+  }
+  const flatbuffers::String *main_character_as_Unused() const {
+    return main_character_type() == Character_Unused ? static_cast<const flatbuffers::String *>(main_character()) : nullptr;
+  }
+  void *mutable_main_character() {
+    return GetPointer<void *>(VT_MAIN_CHARACTER);
+  }
   const flatbuffers::Vector<uint8_t> *characters_type() const {
     return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_CHARACTERS_TYPE);
   }
+  flatbuffers::Vector<uint8_t> *mutable_characters_type() {
+    return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_CHARACTERS_TYPE);
+  }
   const flatbuffers::Vector<flatbuffers::Offset<void>> *characters() const {
     return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<void>> *>(VT_CHARACTERS);
   }
+  flatbuffers::Vector<flatbuffers::Offset<void>> *mutable_characters() {
+    return GetPointer<flatbuffers::Vector<flatbuffers::Offset<void>> *>(VT_CHARACTERS);
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_CHARACTERS_TYPE) &&
+           VerifyField<uint8_t>(verifier, VT_MAIN_CHARACTER_TYPE) &&
+           VerifyOffset(verifier, VT_MAIN_CHARACTER) &&
+           VerifyCharacter(verifier, main_character(), main_character_type()) &&
+           VerifyOffset(verifier, VT_CHARACTERS_TYPE) &&
            verifier.Verify(characters_type()) &&
-           VerifyField<flatbuffers::uoffset_t>(verifier, VT_CHARACTERS) &&
+           VerifyOffset(verifier, VT_CHARACTERS) &&
            verifier.Verify(characters()) &&
            VerifyCharacterVector(verifier, characters(), characters_type()) &&
            verifier.EndTable();
   }
+  MovieT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<Movie> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 };
 
 struct MovieBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
+  void add_main_character_type(Character main_character_type) {
+    fbb_.AddElement<uint8_t>(Movie::VT_MAIN_CHARACTER_TYPE, static_cast<uint8_t>(main_character_type), 0);
+  }
+  void add_main_character(flatbuffers::Offset<void> main_character) {
+    fbb_.AddOffset(Movie::VT_MAIN_CHARACTER, main_character);
+  }
   void add_characters_type(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type) {
     fbb_.AddOffset(Movie::VT_CHARACTERS_TYPE, characters_type);
   }
   void add_characters(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters) {
     fbb_.AddOffset(Movie::VT_CHARACTERS, characters);
   }
-  MovieBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit MovieBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
   MovieBuilder &operator=(const MovieBuilder &);
   flatbuffers::Offset<Movie> Finish() {
-    const auto end = fbb_.EndTable(start_, 2);
+    const auto end = fbb_.EndTable(start_);
     auto o = flatbuffers::Offset<Movie>(end);
     return o;
   }
@@ -223,40 +335,120 @@
 
 inline flatbuffers::Offset<Movie> CreateMovie(
     flatbuffers::FlatBufferBuilder &_fbb,
+    Character main_character_type = Character_NONE,
+    flatbuffers::Offset<void> main_character = 0,
     flatbuffers::Offset<flatbuffers::Vector<uint8_t>> characters_type = 0,
     flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<void>>> characters = 0) {
   MovieBuilder builder_(_fbb);
   builder_.add_characters(characters);
   builder_.add_characters_type(characters_type);
+  builder_.add_main_character(main_character);
+  builder_.add_main_character_type(main_character_type);
   return builder_.Finish();
 }
 
 inline flatbuffers::Offset<Movie> CreateMovieDirect(
     flatbuffers::FlatBufferBuilder &_fbb,
+    Character main_character_type = Character_NONE,
+    flatbuffers::Offset<void> main_character = 0,
     const std::vector<uint8_t> *characters_type = nullptr,
     const std::vector<flatbuffers::Offset<void>> *characters = nullptr) {
   return CreateMovie(
       _fbb,
+      main_character_type,
+      main_character,
       characters_type ? _fbb.CreateVector<uint8_t>(*characters_type) : 0,
       characters ? _fbb.CreateVector<flatbuffers::Offset<void>>(*characters) : 0);
 }
 
+flatbuffers::Offset<Movie> CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+inline AttackerT *Attacker::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = new AttackerT();
+  UnPackTo(_o, _resolver);
+  return _o;
+}
+
+inline void Attacker::UnPackTo(AttackerT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+  { auto _e = sword_attack_damage(); _o->sword_attack_damage = _e; };
+}
+
+inline flatbuffers::Offset<Attacker> Attacker::Pack(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateAttacker(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Attacker> CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AttackerT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _sword_attack_damage = _o->sword_attack_damage;
+  return CreateAttacker(
+      _fbb,
+      _sword_attack_damage);
+}
+
+inline MovieT *Movie::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = new MovieT();
+  UnPackTo(_o, _resolver);
+  return _o;
+}
+
+inline void Movie::UnPackTo(MovieT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+  (void)_o;
+  (void)_resolver;
+  { auto _e = main_character_type(); _o->main_character.type = _e; };
+  { auto _e = main_character(); if (_e) _o->main_character.value = CharacterUnion::UnPack(_e, main_character_type(), _resolver); };
+  { auto _e = characters_type(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].type = (Character)_e->Get(_i); } } };
+  { auto _e = characters(); if (_e) { _o->characters.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->characters[_i].value = CharacterUnion::UnPack(_e->Get(_i), characters_type()->GetEnum<Character>(_i), _resolver); } } };
+}
+
+inline flatbuffers::Offset<Movie> Movie::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MovieT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateMovie(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<Movie> CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+  (void)_rehasher;
+  (void)_o;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MovieT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  auto _main_character_type = _o->main_character.type;
+  auto _main_character = _o->main_character.Pack(_fbb);
+  auto _characters_type = _o->characters.size() ? _fbb.CreateVector<uint8_t>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return static_cast<uint8_t>(__va->__o->characters[i].type); }, &_va) : 0;
+  auto _characters = _o->characters.size() ? _fbb.CreateVector<flatbuffers::Offset<void>>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return __va->__o->characters[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va) : 0;
+  return CreateMovie(
+      _fbb,
+      _main_character_type,
+      _main_character,
+      _characters_type,
+      _characters);
+}
+
 inline bool VerifyCharacter(flatbuffers::Verifier &verifier, const void *obj, Character type) {
   switch (type) {
     case Character_NONE: {
       return true;
     }
     case Character_MuLan: {
-      auto ptr = reinterpret_cast<const MuLan *>(obj);
+      auto ptr = reinterpret_cast<const Attacker *>(obj);
       return verifier.VerifyTable(ptr);
     }
     case Character_Rapunzel: {
-      auto ptr = reinterpret_cast<const Rapunzel *>(obj);
-      return verifier.VerifyTable(ptr);
+      return true;
     }
     case Character_Belle: {
-      auto ptr = reinterpret_cast<const Belle *>(obj);
-      return verifier.VerifyTable(ptr);
+      return true;
+    }
+    case Character_BookFan: {
+      return true;
+    }
+    case Character_Other: {
+      auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+      return verifier.Verify(ptr);
+    }
+    case Character_Unused: {
+      auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+      return verifier.Verify(ptr);
     }
     default: return false;
   }
@@ -273,10 +465,244 @@
   return true;
 }
 
+inline void *CharacterUnion::UnPack(const void *obj, Character type, const flatbuffers::resolver_function_t *resolver) {
+  switch (type) {
+    case Character_MuLan: {
+      auto ptr = reinterpret_cast<const Attacker *>(obj);
+      return ptr->UnPack(resolver);
+    }
+    case Character_Rapunzel: {
+      auto ptr = reinterpret_cast<const Rapunzel *>(obj);
+      return new Rapunzel(*ptr);
+    }
+    case Character_Belle: {
+      auto ptr = reinterpret_cast<const BookReader *>(obj);
+      return new BookReader(*ptr);
+    }
+    case Character_BookFan: {
+      auto ptr = reinterpret_cast<const BookReader *>(obj);
+      return new BookReader(*ptr);
+    }
+    case Character_Other: {
+      auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+      return new std::string(ptr->c_str(), ptr->size());
+    }
+    case Character_Unused: {
+      auto ptr = reinterpret_cast<const flatbuffers::String *>(obj);
+      return new std::string(ptr->c_str(), ptr->size());
+    }
+    default: return nullptr;
+  }
+}
+
+inline flatbuffers::Offset<void> CharacterUnion::Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher) const {
+  switch (type) {
+    case Character_MuLan: {
+      auto ptr = reinterpret_cast<const AttackerT *>(value);
+      return CreateAttacker(_fbb, ptr, _rehasher).Union();
+    }
+    case Character_Rapunzel: {
+      auto ptr = reinterpret_cast<const Rapunzel *>(value);
+      return _fbb.CreateStruct(*ptr).Union();
+    }
+    case Character_Belle: {
+      auto ptr = reinterpret_cast<const BookReader *>(value);
+      return _fbb.CreateStruct(*ptr).Union();
+    }
+    case Character_BookFan: {
+      auto ptr = reinterpret_cast<const BookReader *>(value);
+      return _fbb.CreateStruct(*ptr).Union();
+    }
+    case Character_Other: {
+      auto ptr = reinterpret_cast<const std::string *>(value);
+      return _fbb.CreateString(*ptr).Union();
+    }
+    case Character_Unused: {
+      auto ptr = reinterpret_cast<const std::string *>(value);
+      return _fbb.CreateString(*ptr).Union();
+    }
+    default: return 0;
+  }
+}
+
+inline CharacterUnion::CharacterUnion(const CharacterUnion &u) FLATBUFFERS_NOEXCEPT : type(u.type), value(nullptr) {
+  switch (type) {
+    case Character_MuLan: {
+      value = new AttackerT(*reinterpret_cast<AttackerT *>(u.value));
+      break;
+    }
+    case Character_Rapunzel: {
+      value = new Rapunzel(*reinterpret_cast<Rapunzel *>(u.value));
+      break;
+    }
+    case Character_Belle: {
+      value = new BookReader(*reinterpret_cast<BookReader *>(u.value));
+      break;
+    }
+    case Character_BookFan: {
+      value = new BookReader(*reinterpret_cast<BookReader *>(u.value));
+      break;
+    }
+    case Character_Other: {
+      value = new std::string(*reinterpret_cast<std::string *>(u.value));
+      break;
+    }
+    case Character_Unused: {
+      value = new std::string(*reinterpret_cast<std::string *>(u.value));
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+inline void CharacterUnion::Reset() {
+  switch (type) {
+    case Character_MuLan: {
+      auto ptr = reinterpret_cast<AttackerT *>(value);
+      delete ptr;
+      break;
+    }
+    case Character_Rapunzel: {
+      auto ptr = reinterpret_cast<Rapunzel *>(value);
+      delete ptr;
+      break;
+    }
+    case Character_Belle: {
+      auto ptr = reinterpret_cast<BookReader *>(value);
+      delete ptr;
+      break;
+    }
+    case Character_BookFan: {
+      auto ptr = reinterpret_cast<BookReader *>(value);
+      delete ptr;
+      break;
+    }
+    case Character_Other: {
+      auto ptr = reinterpret_cast<std::string *>(value);
+      delete ptr;
+      break;
+    }
+    case Character_Unused: {
+      auto ptr = reinterpret_cast<std::string *>(value);
+      delete ptr;
+      break;
+    }
+    default: break;
+  }
+  value = nullptr;
+  type = Character_NONE;
+}
+
+inline flatbuffers::TypeTable *AttackerTypeTable();
+
+inline flatbuffers::TypeTable *RapunzelTypeTable();
+
+inline flatbuffers::TypeTable *BookReaderTypeTable();
+
+inline flatbuffers::TypeTable *MovieTypeTable();
+
+inline flatbuffers::TypeTable *CharacterTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_SEQUENCE, 0, -1 },
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_SEQUENCE, 0, 1 },
+    { flatbuffers::ET_SEQUENCE, 0, 2 },
+    { flatbuffers::ET_SEQUENCE, 0, 2 },
+    { flatbuffers::ET_STRING, 0, -1 },
+    { flatbuffers::ET_STRING, 0, -1 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    AttackerTypeTable,
+    RapunzelTypeTable,
+    BookReaderTypeTable
+  };
+  static const char *names[] = {
+    "NONE",
+    "MuLan",
+    "Rapunzel",
+    "Belle",
+    "BookFan",
+    "Other",
+    "Unused"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_UNION, 7, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *AttackerTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_INT, 0, -1 }
+  };
+  static const char *names[] = {
+    "sword_attack_damage"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 1, type_codes, nullptr, nullptr, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *RapunzelTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_INT, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 4 };
+  static const char *names[] = {
+    "hair_length"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *BookReaderTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_INT, 0, -1 }
+  };
+  static const int32_t values[] = { 0, 4 };
+  static const char *names[] = {
+    "books_read"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_STRUCT, 1, type_codes, nullptr, values, names
+  };
+  return &tt;
+}
+
+inline flatbuffers::TypeTable *MovieTypeTable() {
+  static flatbuffers::TypeCode type_codes[] = {
+    { flatbuffers::ET_UTYPE, 0, 0 },
+    { flatbuffers::ET_SEQUENCE, 0, 0 },
+    { flatbuffers::ET_UTYPE, 1, 0 },
+    { flatbuffers::ET_SEQUENCE, 1, 0 }
+  };
+  static flatbuffers::TypeFunction type_refs[] = {
+    CharacterTypeTable
+  };
+  static const char *names[] = {
+    "main_character_type",
+    "main_character",
+    "characters_type",
+    "characters"
+  };
+  static flatbuffers::TypeTable tt = {
+    flatbuffers::ST_TABLE, 4, type_codes, type_refs, nullptr, names
+  };
+  return &tt;
+}
+
 inline const Movie *GetMovie(const void *buf) {
   return flatbuffers::GetRoot<Movie>(buf);
 }
 
+inline Movie *GetMutableMovie(void *buf) {
+  return flatbuffers::GetMutableRoot<Movie>(buf);
+}
+
 inline const char *MovieIdentifier() {
   return "MOVI";
 }
@@ -297,4 +723,10 @@
   fbb.Finish(root, MovieIdentifier());
 }
 
+inline flatbuffers::unique_ptr<MovieT> UnPackMovie(
+    const void *buf,
+    const flatbuffers::resolver_function_t *res = nullptr) {
+  return flatbuffers::unique_ptr<MovieT>(GetMovie(buf)->UnPack(res));
+}
+
 #endif  // FLATBUFFERS_GENERATED_UNIONVECTOR_H_
diff --git a/tests/union_vector/union_vector_generated.js b/tests/union_vector/union_vector_generated.js
new file mode 100644
index 0000000..254c25f
--- /dev/null
+++ b/tests/union_vector/union_vector_generated.js
@@ -0,0 +1,437 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum
+ */
+var Character = {
+  NONE: 0,
+  MuLan: 1,
+  Rapunzel: 2,
+  Belle: 3,
+  BookFan: 4,
+  Other: 5,
+  Unused: 6
+};
+
+/**
+ * @constructor
+ */
+function Attacker() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Attacker}
+ */
+Attacker.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Attacker=} obj
+ * @returns {Attacker}
+ */
+Attacker.getRootAsAttacker = function(bb, obj) {
+  return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+Attacker.prototype.swordAttackDamage = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+Attacker.prototype.mutate_sword_attack_damage = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+Attacker.startAttacker = function(builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} swordAttackDamage
+ */
+Attacker.addSwordAttackDamage = function(builder, swordAttackDamage) {
+  builder.addFieldInt32(0, swordAttackDamage, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+Attacker.endAttacker = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
+/**
+ * @constructor
+ */
+function Rapunzel() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Rapunzel}
+ */
+Rapunzel.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+Rapunzel.prototype.hairLength = function() {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+Rapunzel.prototype.mutate_hair_length = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hair_length
+ * @returns {flatbuffers.Offset}
+ */
+Rapunzel.createRapunzel = function(builder, hair_length) {
+  builder.prep(4, 4);
+  builder.writeInt32(hair_length);
+  return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+function BookReader() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {BookReader}
+ */
+BookReader.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+BookReader.prototype.booksRead = function() {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+BookReader.prototype.mutate_books_read = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} books_read
+ * @returns {flatbuffers.Offset}
+ */
+BookReader.createBookReader = function(builder, books_read) {
+  builder.prep(4, 4);
+  builder.writeInt32(books_read);
+  return builder.offset();
+};
+
+/**
+ * @constructor
+ */
+function Movie() {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  this.bb = null;
+
+  /**
+   * @type {number}
+   */
+  this.bb_pos = 0;
+}
+
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Movie}
+ */
+Movie.prototype.__init = function(i, bb) {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Movie=} obj
+ * @returns {Movie}
+ */
+Movie.getRootAsMovie = function(bb, obj) {
+  return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+Movie.bufferHasIdentifier = function(bb) {
+  return bb.__has_identifier('MOVI');
+};
+
+/**
+ * @returns {Character}
+ */
+Movie.prototype.mainCharacterType = function() {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb_pos + offset)) : Character.NONE;
+};
+
+/**
+ * @param {Character} value
+ * @returns {boolean}
+ */
+Movie.prototype.mutate_main_character_type = function(value) {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+Movie.prototype.mainCharacter = function(obj) {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {Character}
+ */
+Movie.prototype.charactersType = function(index) {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index)) : /** @type {Character} */ (0);
+};
+
+/**
+ * @returns {number}
+ */
+Movie.prototype.charactersTypeLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+Movie.prototype.charactersTypeArray = function() {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Table=} obj
+ * @returns {?flatbuffers.Table}
+ */
+Movie.prototype.characters = function(index, obj) {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__union(obj, this.bb.__vector(this.bb_pos + offset) + index * 4) : null;
+};
+
+/**
+ * @returns {number}
+ */
+Movie.prototype.charactersLength = function() {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+Movie.startMovie = function(builder) {
+  builder.startObject(4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Character} mainCharacterType
+ */
+Movie.addMainCharacterType = function(builder, mainCharacterType) {
+  builder.addFieldInt8(0, mainCharacterType, Character.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} mainCharacterOffset
+ */
+Movie.addMainCharacter = function(builder, mainCharacterOffset) {
+  builder.addFieldOffset(1, mainCharacterOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersTypeOffset
+ */
+Movie.addCharactersType = function(builder, charactersTypeOffset) {
+  builder.addFieldOffset(2, charactersTypeOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<Character>} data
+ * @returns {flatbuffers.Offset}
+ */
+Movie.createCharactersTypeVector = function(builder, data) {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+Movie.startCharactersTypeVector = function(builder, numElems) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersOffset
+ */
+Movie.addCharacters = function(builder, charactersOffset) {
+  builder.addFieldOffset(3, charactersOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+Movie.createCharactersVector = function(builder, data) {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+Movie.startCharactersVector = function(builder, numElems) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+Movie.endMovie = function(builder) {
+  var offset = builder.endObject();
+  return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+Movie.finishMovieBuffer = function(builder, offset) {
+  builder.finish(offset, 'MOVI');
+};
+
+// Exports for Node.js and RequireJS
+this.Character = Character;
+this.Attacker = Attacker;
+this.Rapunzel = Rapunzel;
+this.BookReader = BookReader;
+this.Movie = Movie;
diff --git a/tests/union_vector/union_vector_generated.ts b/tests/union_vector/union_vector_generated.ts
new file mode 100644
index 0000000..62e3105
--- /dev/null
+++ b/tests/union_vector/union_vector_generated.ts
@@ -0,0 +1,427 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+/**
+ * @enum
+ */
+export enum Character{
+  NONE= 0,
+  MuLan= 1,
+  Rapunzel= 2,
+  Belle= 3,
+  BookFan= 4,
+  Other= 5,
+  Unused= 6
+};
+
+/**
+ * @constructor
+ */
+export class Attacker {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Attacker}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Attacker {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Attacker=} obj
+ * @returns {Attacker}
+ */
+static getRootAsAttacker(bb:flatbuffers.ByteBuffer, obj?:Attacker):Attacker {
+  return (obj || new Attacker).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @returns {number}
+ */
+swordAttackDamage():number {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? this.bb.readInt32(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_sword_attack_damage(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startAttacker(builder:flatbuffers.Builder) {
+  builder.startObject(1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} swordAttackDamage
+ */
+static addSwordAttackDamage(builder:flatbuffers.Builder, swordAttackDamage:number) {
+  builder.addFieldInt32(0, swordAttackDamage, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endAttacker(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+}
+/**
+ * @constructor
+ */
+export class Rapunzel {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Rapunzel}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Rapunzel {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+hairLength():number {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_hair_length(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} hair_length
+ * @returns {flatbuffers.Offset}
+ */
+static createRapunzel(builder:flatbuffers.Builder, hair_length: number):flatbuffers.Offset {
+  builder.prep(4, 4);
+  builder.writeInt32(hair_length);
+  return builder.offset();
+};
+
+}
+/**
+ * @constructor
+ */
+export class BookReader {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {BookReader}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):BookReader {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @returns {number}
+ */
+booksRead():number {
+  return this.bb.readInt32(this.bb_pos);
+};
+
+/**
+ * @param {number} value
+ * @returns {boolean}
+ */
+mutate_books_read(value:number):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 0);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeInt32(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} books_read
+ * @returns {flatbuffers.Offset}
+ */
+static createBookReader(builder:flatbuffers.Builder, books_read: number):flatbuffers.Offset {
+  builder.prep(4, 4);
+  builder.writeInt32(books_read);
+  return builder.offset();
+};
+
+}
+/**
+ * @constructor
+ */
+export class Movie {
+  /**
+   * @type {flatbuffers.ByteBuffer}
+   */
+  bb: flatbuffers.ByteBuffer;
+
+  /**
+   * @type {number}
+   */
+  bb_pos:number = 0;
+/**
+ * @param {number} i
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {Movie}
+ */
+__init(i:number, bb:flatbuffers.ByteBuffer):Movie {
+  this.bb_pos = i;
+  this.bb = bb;
+  return this;
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @param {Movie=} obj
+ * @returns {Movie}
+ */
+static getRootAsMovie(bb:flatbuffers.ByteBuffer, obj?:Movie):Movie {
+  return (obj || new Movie).__init(bb.readInt32(bb.position()) + bb.position(), bb);
+};
+
+/**
+ * @param {flatbuffers.ByteBuffer} bb
+ * @returns {boolean}
+ */
+static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean {
+  return bb.__has_identifier('MOVI');
+};
+
+/**
+ * @returns {Character}
+ */
+mainCharacterType():Character {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+  return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb_pos + offset)) : Character.NONE;
+};
+
+/**
+ * @param {Character} value
+ * @returns {boolean}
+ */
+mutate_main_character_type(value:Character):boolean {
+  var offset = this.bb.__offset(this.bb_pos, 4);
+
+  if (offset === 0) {
+    return false;
+  }
+
+  this.bb.writeUint8(this.bb_pos + offset, value);
+  return true;
+};
+
+/**
+ * @param {flatbuffers.Table} obj
+ * @returns {?flatbuffers.Table}
+ */
+mainCharacter<T extends flatbuffers.Table>(obj:T):T|null {
+  var offset = this.bb.__offset(this.bb_pos, 6);
+  return offset ? this.bb.__union(obj, this.bb_pos + offset) : null;
+};
+
+/**
+ * @param {number} index
+ * @returns {Character}
+ */
+charactersType(index: number):Character|null {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? /** @type {Character} */ (this.bb.readUint8(this.bb.__vector(this.bb_pos + offset) + index)) : /** @type {Character} */ (0);
+};
+
+/**
+ * @returns {number}
+ */
+charactersTypeLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @returns {Uint8Array}
+ */
+charactersTypeArray():Uint8Array|null {
+  var offset = this.bb.__offset(this.bb_pos, 8);
+  return offset ? new Uint8Array(this.bb.bytes().buffer, this.bb.bytes().byteOffset + this.bb.__vector(this.bb_pos + offset), this.bb.__vector_len(this.bb_pos + offset)) : null;
+};
+
+/**
+ * @param {number} index
+ * @param {flatbuffers.Table=} obj
+ * @returns {?flatbuffers.Table}
+ */
+characters<T extends flatbuffers.Table>(index: number, obj:T):T|null {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__union(obj, this.bb.__vector(this.bb_pos + offset) + index * 4) : null;
+};
+
+/**
+ * @returns {number}
+ */
+charactersLength():number {
+  var offset = this.bb.__offset(this.bb_pos, 10);
+  return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ */
+static startMovie(builder:flatbuffers.Builder) {
+  builder.startObject(4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Character} mainCharacterType
+ */
+static addMainCharacterType(builder:flatbuffers.Builder, mainCharacterType:Character) {
+  builder.addFieldInt8(0, mainCharacterType, Character.NONE);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} mainCharacterOffset
+ */
+static addMainCharacter(builder:flatbuffers.Builder, mainCharacterOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(1, mainCharacterOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersTypeOffset
+ */
+static addCharactersType(builder:flatbuffers.Builder, charactersTypeOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(2, charactersTypeOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<Character>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createCharactersTypeVector(builder:flatbuffers.Builder, data:Character[]):flatbuffers.Offset {
+  builder.startVector(1, data.length, 1);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addInt8(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startCharactersTypeVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(1, numElems, 1);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} charactersOffset
+ */
+static addCharacters(builder:flatbuffers.Builder, charactersOffset:flatbuffers.Offset) {
+  builder.addFieldOffset(3, charactersOffset, 0);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {Array.<flatbuffers.Offset>} data
+ * @returns {flatbuffers.Offset}
+ */
+static createCharactersVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset {
+  builder.startVector(4, data.length, 4);
+  for (var i = data.length - 1; i >= 0; i--) {
+    builder.addOffset(data[i]);
+  }
+  return builder.endVector();
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {number} numElems
+ */
+static startCharactersVector(builder:flatbuffers.Builder, numElems:number) {
+  builder.startVector(4, numElems, 4);
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @returns {flatbuffers.Offset}
+ */
+static endMovie(builder:flatbuffers.Builder):flatbuffers.Offset {
+  var offset = builder.endObject();
+  return offset;
+};
+
+/**
+ * @param {flatbuffers.Builder} builder
+ * @param {flatbuffers.Offset} offset
+ */
+static finishMovieBuffer(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {
+  builder.finish(offset, 'MOVI');
+};
+
+}