Merge branch '0.17.0' into upstream
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index a9698d7..d3dc5d0 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -9,6 +9,9 @@
 env:
   BUILD_DEPS: automake bison flex git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config
 
+permissions:
+  contents: read
+
 jobs:
   # TODO windows and macos
   compiler:
@@ -52,7 +55,7 @@
     needs: compiler
     runs-on: ubuntu-20.04
     env:
-      GRADLE_VERSION: 7.4.2
+      GRADLE_VERSION: 7.5.1
     steps:
       - uses: actions/checkout@v3
 
@@ -71,7 +74,7 @@
       - name: Setup gradle
         run: |
           wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip
-          (echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -)
+          (echo "f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -)
           unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip
           sudo mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle
           sudo ln -s /usr/local/gradle/bin/gradle /usr/local/bin
diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml
index 5ae7ba7..69b8cbe 100644
--- a/.github/workflows/cmake.yml
+++ b/.github/workflows/cmake.yml
@@ -9,6 +9,9 @@
 env:
   BUILD_DEPS: bison flex g++ libboost-all-dev libevent-dev libssl-dev make cmake
 
+permissions:
+  contents: read
+
 jobs:
   compiler:
     runs-on: ubuntu-20.04
diff --git a/.gitignore b/.gitignore
index 6278185..a469311 100644
--- a/.gitignore
+++ b/.gitignore
@@ -201,9 +201,9 @@
 /lib/delphi/*.local
 /lib/delphi/*.identcache
 /lib/delphi/test/skip/bin
-/lib/delphi/test/serializer/*.dat
+/lib/delphi/test/serializer/**/*.dat
 /lib/delphi/test/serializer/bin
-/lib/delphi/test/thrift-testing
+/lib/delphi/test/thrift-testing/*.thrift
 /lib/delphi/**/*.identcache
 /lib/delphi/**/*.local
 /lib/delphi/**/*.dcu
@@ -285,7 +285,7 @@
 /lib/go/src
 /lib/go/test/fuzz/gopathfuzz
 /lib/go/test/gopath/
-/lib/go/test/ThriftTest.thrift
+/lib/go/test/ThriftTest*.thrift
 /lib/nodets/test-compiled/
 /lib/ocaml/_build/
 /lib/ocaml/_tags
@@ -355,7 +355,7 @@
 /test/erl/_build/
 /test/erl/rebar.lock
 /test/go/bin/
-/test/go/ThriftTest.thrift
+/test/go/ThriftTest*.thrift
 /test/go/gopath
 /test/go/pkg/
 /test/go/src/code.google.com/
@@ -442,3 +442,11 @@
 /tutorial/netstd/Client/Properties/launchSettings.json
 /ylwrap
 
+# Unit test generated artifacts
+
+CMakeCache.txt
+CMakeFiles
+compiler/cpp/tests/*.cmake
+compiler/cpp/tests/Testing/
+compiler/cpp/tests/bin/
+compiler/cpp/tests/*.a
diff --git a/ApacheThrift.nuspec b/ApacheThrift.nuspec
index a5629e8..3404347 100644
--- a/ApacheThrift.nuspec
+++ b/ApacheThrift.nuspec
@@ -19,14 +19,14 @@
      the "Thrift" project.
   2. nuget setApiKey <your-api-key>
   3. nuget pack ApacheThrift.nuspec -Symbols -SymbolPackageFormat snupkg
-  4. nuget push ApacheThrift.0.17.0.nupkg -Source https://api.nuget.org/v3/index.json
+  4. nuget push ApacheThrift.0.18.0.nupkg -Source https://api.nuget.org/v3/index.json
   -->
 
 <package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
   <metadata>
     <id>ApacheThrift</id>
-    <version>0.17.0</version>
-    <title>Apache Thrift 0.17.0</title>
+    <version>0.18.0</version>
+    <title>Apache Thrift 0.18.0</title>
     <authors>Apache Thrift Developers</authors>
     <owners>Apache Software Foundation</owners>
     <license type="expression">Apache-2.0</license>
@@ -36,7 +36,7 @@
     <description>
       Contains runtime libraries from lib/netstd for netstandard2.0 framework development.
     </description>
-    <repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.17.0" />
+    <repository type="GitHub" url="https://github.com/apache/thrift" branch="release/0.18.0" />
     <tags>Apache Thrift RPC</tags>
   </metadata>
   <files>
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7119628..859d944 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -28,7 +28,7 @@
 
 # PACKAGE_VERSION is used by cpack scripts currently
 # Both thrift_VERSION and PACKAGE_VERSION should be the same for now
-set(thrift_VERSION "0.17.0")
+set(thrift_VERSION "0.18.0")
 set(PACKAGE_VERSION ${thrift_VERSION})
 
 project("thrift" VERSION ${PACKAGE_VERSION})
diff --git a/LANGUAGES.md b/LANGUAGES.md
index f787b93..9d989da 100644
--- a/LANGUAGES.md
+++ b/LANGUAGES.md
@@ -319,7 +319,7 @@
 <td align=left><a href="https://github.com/apache/thrift/blob/master/lib/rs/README.md">Rust</a></td>
 <!-- Since -----------------><td>0.11.0</td>
 <!-- Build Systems ---------><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
-<!-- Language Levels -------><td>1.40.0</td><td>1.xx.x</td>
+<!-- Language Levels -------><td>1.61.0</td><td>1.xx.x</td>
 <!-- Field types -----------><td><img src="doc/images/cred.png" alt=""/></td>
 <!-- Low-Level Transports --><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td>
 <!-- Transport Wrappers ----><td><img src="doc/images/cgrn.png" alt="Yes"/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td><td><img src="doc/images/cred.png" alt=""/></td>
diff --git a/Makefile.am b/Makefile.am
index c3e5f8a..95c610e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -78,7 +78,7 @@
 space := $(empty) $(empty)
 comma := ,
 
-CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_NETSTD@ @MAYBE_NODETS@ @MAYBE_KOTLIN@
+CROSS_LANGS = @MAYBE_CPP@ @MAYBE_C_GLIB@ @MAYBE_CL@ @MAYBE_D@ @MAYBE_JAVA@ @MAYBE_PYTHON@ @MAYBE_PY3@ @MAYBE_RUBY@ @MAYBE_PERL@ @MAYBE_PHP@ @MAYBE_GO@ @MAYBE_NODEJS@ @MAYBE_DART@ @MAYBE_ERLANG@ @MAYBE_LUA@ @MAYBE_RS@ @MAYBE_NETSTD@ @MAYBE_NODETS@ @MAYBE_KOTLIN@
 CROSS_LANGS_COMMA_SEPARATED = $(subst $(space),$(comma),$(CROSS_LANGS))
 
 if WITH_PY3
diff --git a/Thrift.podspec b/Thrift.podspec
index 4e3abbd..7350be4 100644
--- a/Thrift.podspec
+++ b/Thrift.podspec
@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name          = 'Thrift'
-  s.version       = '0.17.0'
+  s.version       = '0.18.0'
   s.summary       = "Apache Thrift is a lightweight, language-independent software stack with an associated code generation mechanism for RPC."
   s.description   = <<-DESC
 The Apache Thrift scalable cross-language software framework for networked services development combines a software stack with a code generation engine to build services that work efficiently and seamlessly between many programming languages.
@@ -10,6 +10,6 @@
   s.author        = { 'Apache Thrift Developers' => 'dev@thrift.apache.org' }
   s.ios.deployment_target = '9.0'
   s.osx.deployment_target = '10.10'
-  s.source        = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.17.0' }
+  s.source        = { :git => 'https://github.com/apache/thrift.git', :tag => 'v0.18.0' }
   s.source_files  = 'lib/swift/Sources/*.swift'
 end
diff --git a/appveyor.yml b/appveyor.yml
index 5fe31db..1a7f026 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -19,7 +19,7 @@
 
 # build Apache Thrift on AppVeyor - https://ci.appveyor.com
 
-version: '0.17.0.{build}'
+version: '0.18.0.{build}'
 
 shallow_clone: true
 
diff --git a/bower.json b/bower.json
index 6ddfb38..a6ef878 100644
--- a/bower.json
+++ b/bower.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "homepage": "https://github.com/apache/thrift.git",
   "authors": [
     "Apache Thrift <dev@thrift.apache.org>"
diff --git a/build/cmake/ThriftConfig.cmake.in b/build/cmake/ThriftConfig.cmake.in
index f82c0a5..c055200 100644
--- a/build/cmake/ThriftConfig.cmake.in
+++ b/build/cmake/ThriftConfig.cmake.in
@@ -24,7 +24,9 @@
 set_and_check(THRIFT_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
 set_and_check(THRIFT_CMAKE_DIR "@PACKAGE_CMAKE_INSTALL_DIR@")
 set_and_check(THRIFT_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@")
-set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@")
+if(NOT DEFINED THRIFT_COMPILER)
+    set(THRIFT_COMPILER "${THRIFT_BIN_DIR}/thrift@CMAKE_EXECUTABLE_SUFFIX@")
+endif()
 
 if (NOT TARGET thrift::thrift)
     include("${THRIFT_CMAKE_DIR}/thriftTargets.cmake")
diff --git a/build/docker/README.md b/build/docker/README.md
index f07faaa..1746d6d 100644
--- a/build/docker/README.md
+++ b/build/docker/README.md
@@ -172,14 +172,15 @@
 | C++ gcc   | 5.4.0         | 7.4.0         |       |
 | C++ clang | 3.8           | 6.0           |       |
 | C# (mono) | 4.2.1.0       | 4.6.2.7       |       |
-| c_glib    | 2.48.2        | 2.56.4        |       |
+| c\_glib    | 2.48.2        | 2.56.4        |       |
+| cl (sbcl) |               | 1.5.3         |       |
 | d         | 2.087.0       | 2.087.0       |       |
 | dart      | 2.0.0         | 2.4.0         |       |
 | delphi    |               |               | Not in CI |
 | erlang    | OTP-18        | OTP-23        |       |
 | go        | 1.15.10       | 1.16.2        |       |
 | haxe      | 3.2.1         | 3.4.4         | THRIFT-4352: avoid 3.4.2 |
-| java      | 1.8.0_191     | 11.0.3        |       |
+| java      | 1.8.0\_191     | 11.0.3        |       |
 | js        | Node.js 6.17.1, V8 5.1.281.111, npm 3.10.10 | Node.js 10.18.0, V8 6.8.275.32, npm 6.13.4 |     |
 | lua       |               | 5.2.4         | Lua 5.3: see THRIFT-4386 |
 | netstd    | 6.0           | 6.0           |       |
@@ -190,6 +191,6 @@
 | python    | 2.7.12        | 2.7.15        |       |
 | python3   | 3.5.2         | 3.6.8         |       |
 | ruby      | 2.3.1p112     | 2.5.1p57      |       |
-| rust      | 1.40.0        | 1.40.0        |       |
+| rust      | 1.61.0        | 1.61.0        |       |
 | smalltalk |               |               | Not in CI |
 | swift     |               | 5.1.4         |       |
diff --git a/build/docker/old/ubuntu-artful/Dockerfile b/build/docker/old/ubuntu-artful/Dockerfile
index d1f58d6..8068265 100644
--- a/build/docker/old/ubuntu-artful/Dockerfile
+++ b/build/docker/old/ubuntu-artful/Dockerfile
@@ -85,6 +85,17 @@
       qtbase5-dev \
       qtbase5-dev-tools
 
+ENV SBCL_VERSION 1.4.5
+RUN \
+`# Common Lisp (sbcl) dependencies` \
+    curl --version && \
+    curl -O -J -L https://kent.dl.sourceforge.net/project/sbcl/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+    tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+    cd sbcl-${SBCL_VERSION}-x86-64-linux && \
+    ./install.sh && \
+    sbcl --version && \
+    rm -rf sbcl*
+
 ENV D_VERSION     2.080.0
 ENV DMD_DEB       dmd_2.080.0-0_amd64.deb
 RUN \
diff --git a/build/docker/ubuntu-disco/Dockerfile b/build/docker/old/ubuntu-disco/Dockerfile
similarity index 64%
rename from build/docker/ubuntu-disco/Dockerfile
rename to build/docker/old/ubuntu-disco/Dockerfile
index ee3f19f..2e802e5 100644
--- a/build/docker/ubuntu-disco/Dockerfile
+++ b/build/docker/old/ubuntu-disco/Dockerfile
@@ -22,8 +22,8 @@
 ### Add apt repos
 
 RUN apt-get update && \
-    apt-get dist-upgrade -y && \
-    apt-get install -y --no-install-recommends \
+      apt-get dist-upgrade -y && \
+      apt-get install -y --no-install-recommends \
       apt \
       apt-transport-https \
       apt-utils \
@@ -34,26 +34,26 @@
 
 # Dart
 RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
-    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
       /etc/apt/sources.list.d/dart_stable.list
 
 # dotnet (netcore)
 RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
-    wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
-    chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
-    chown root:root /etc/apt/sources.list.d/microsoft-prod.list
+      wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
+      chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
+      chown root:root /etc/apt/sources.list.d/microsoft-prod.list
 
 # erlang
 RUN wget -O- https://packages.erlang-solutions.com/ubuntu/erlang_solutions.asc | apt-key add - && \
-    echo "deb https://packages.erlang-solutions.com/ubuntu disco contrib" | tee /etc/apt/sources.list.d/erlang.list
+      echo "deb https://packages.erlang-solutions.com/ubuntu disco contrib" | tee /etc/apt/sources.list.d/erlang.list
 
 # node.js
 RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
-    echo "deb https://deb.nodesource.com/node_10.x disco main" | tee /etc/apt/sources.list.d/nodesource.list
+      echo "deb https://deb.nodesource.com/node_10.x disco main" | tee /etc/apt/sources.list.d/nodesource.list
 
 ### install general dependencies
 RUN apt-get update && apt-get install -y --no-install-recommends \
-`# General dependencies` \
+      `# General dependencies` \
       bash-completion \
       bison \
       build-essential \
@@ -75,13 +75,13 @@
 
 # lib/as3 (ActionScript)
 RUN mkdir -p /usr/local/adobe/flex/4.6 && \
-    cd /usr/local/adobe/flex/4.6 && \
-    wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
-    unzip flex_sdk_4.6.zip
+      cd /usr/local/adobe/flex/4.6 && \
+      wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
+      unzip flex_sdk_4.6.zip
 ENV FLEX_HOME /usr/local/adobe/flex/4.6
 
 RUN apt-get install -y --no-install-recommends \
-`# C++ dependencies` \
+      `# C++ dependencies` \
       libboost-all-dev \
       libevent-dev \
       libssl-dev \
@@ -89,45 +89,57 @@
       qtbase5-dev \
       qtbase5-dev-tools
 
+ENV SBCL_VERSION 1.5.3
+RUN \
+      `# Common Lisp (sbcl) dependencies` \
+      curl --version && \
+      curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
+      tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+      cd sbcl-${SBCL_VERSION}-x86-64-linux && \
+      ./install.sh && \
+      sbcl --version && \
+      cd .. && \
+      rm -rf sbcl*
+
 ENV D_VERSION     2.087.0
 ENV DMD_DEB       dmd_2.087.0-0_amd64.deb
 RUN \
-`# D dependencies` \
-    wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
-    dpkg --install ${DMD_DEB} && \
-    rm -f ${DMD_DEB} && \
-    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
-    git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
-    mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-libevent-2.0 && \
-    git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
-    mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-openssl-1.1.0h
+      `# D dependencies` \
+      wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
+      dpkg --install ${DMD_DEB} && \
+      rm -f ${DMD_DEB} && \
+      mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+      git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
+      mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-libevent-2.0 && \
+      git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
+      mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-openssl-1.1.0h
 
 ENV DART_VERSION 2.7.2-1
 RUN apt-get install -y --no-install-recommends \
-`# Dart dependencies` \
+      `# Dart dependencies` \
       dart=$DART_VERSION
 ENV PATH /usr/lib/dart/bin:$PATH
 
 RUN apt-get install -y --no-install-recommends \
-`# dotnet core dependencies` \
+      `# dotnet core dependencies` \
       dotnet-sdk-6.0 \
       dotnet-runtime-6.0 \
       aspnetcore-runtime-6.0 \
       dotnet-apphost-pack-6.0
 
 RUN apt-get install -y --no-install-recommends \
-`# Erlang dependencies` \
+      `# Erlang dependencies` \
       erlang && \
-    wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \
-    chmod 755 /usr/bin/rebar3 && \
-    rebar3 --version
+      wget https://s3.amazonaws.com/rebar3/rebar3 -O /usr/bin/rebar3 && \
+      chmod 755 /usr/bin/rebar3 && \
+      rebar3 --version
 
 RUN apt-get install -y --no-install-recommends \
-`# GlibC dependencies` \
+      `# GlibC dependencies` \
       libglib2.0-dev
 
 # golang
@@ -136,34 +148,34 @@
 ENV GOLANG_DOWNLOAD_SHA256 464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6
 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
       echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
-            tar -C /usr/local -xzf golang.tar.gz && \
-                  ln -s /usr/local/go/bin/go /usr/local/bin && \
-                        rm golang.tar.gz
+      tar -C /usr/local -xzf golang.tar.gz && \
+      ln -s /usr/local/go/bin/go /usr/local/bin && \
+      rm golang.tar.gz
 
 RUN apt-get install -y --no-install-recommends \
-`# Haxe dependencies` \
+      `# Haxe dependencies` \
       haxe \
       neko \
       neko-dev && \
-    haxelib setup --always /usr/share/haxe/lib && \
-    haxelib install --always hxcpp 2>&1 > /dev/null
+      haxelib setup --always /usr/share/haxe/lib && \
+      haxelib install --always hxcpp 2>&1 > /dev/null
 
-ENV GRADLE_VERSION="7.4.2"
+ENV GRADLE_VERSION="7.5.1"
 RUN apt-get install -y --no-install-recommends \
-`# Java dependencies` \
+      `# Java dependencies` \
       ant \
       ant-optional \
       maven \
       openjdk-11-jdk-headless && \
-`# Gradle` \
+      `# Gradle` \
       wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
-      (echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
+      (echo "f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
       unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
       mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
       ln -s /usr/local/gradle/bin/gradle /usr/local/bin
 
 RUN apt-get install -y --no-install-recommends \
-`# Lua dependencies` \
+      `# Lua dependencies` \
       lua5.2 \
       lua5.2-dev
 # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
@@ -171,12 +183,12 @@
 # need to update our luasocket code, lua doesn't have luaL_openlib any more
 
 RUN apt-get install -y --no-install-recommends \
-`# Node.js dependencies` \
+      `# Node.js dependencies` \
       nodejs
 
 # Test dependencies for running puppeteer
 RUN apt-get install -y --no-install-recommends \
-`# JS dependencies` \
+      `# JS dependencies` \
       libxss1 \
       libxtst6
 
@@ -189,7 +201,7 @@
 #     opam install --yes oasis
 
 RUN apt-get install -y --no-install-recommends \
-`# Perl dependencies` \
+      `# Perl dependencies` \
       libbit-vector-perl \
       libclass-accessor-class-perl \
       libcrypt-ssleay-perl \
@@ -198,7 +210,7 @@
       libtest-exception-perl
 
 RUN apt-get install -y --no-install-recommends \
-`# Php dependencies` \
+      `# Php dependencies` \
       php \
       php-cli \
       php-dev \
@@ -208,7 +220,7 @@
       composer
 
 RUN apt-get install -y --no-install-recommends \
-`# Python dependencies` \
+      `# Python dependencies` \
       python-all \
       python-all-dbg \
       python-all-dev \
@@ -220,10 +232,10 @@
       python-twisted \
       python-wheel \
       python-zope.interface && \
-   pip install --upgrade backports.ssl_match_hostname
+      pip install --upgrade backports.ssl_match_hostname
 
 RUN apt-get install -y --no-install-recommends \
-`# Python3 dependencies` \
+      `# Python3 dependencies` \
       python3-all \
       python3-all-dbg \
       python3-all-dev \
@@ -236,13 +248,13 @@
       python3-zope.interface
 
 RUN apt-get install -y --no-install-recommends \
-`# Ruby dependencies` \
+      `# Ruby dependencies` \
       ruby \
       ruby-dev \
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 ENV PATH /root/.cargo/bin:$PATH
 
 # Swift on Linux for cross tests
@@ -255,11 +267,11 @@
 
 # Locale(s) for cpp unit tests
 RUN apt-get install -y --no-install-recommends \
-`# Locale dependencies` \
+      `# Locale dependencies` \
       locales && \
-    locale-gen en_US.UTF-8 && \
-    locale-gen de_DE.UTF-8 && \
-    update-locale
+      locale-gen en_US.UTF-8 && \
+      locale-gen de_DE.UTF-8 && \
+      update-locale
 
 # cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer
 # don't need this on disco, nobody uses it
@@ -274,9 +286,9 @@
 
 # Clean up
 RUN rm -rf /var/cache/apt/* && \
-    rm -rf /var/lib/apt/lists/* && \
-    rm -rf /tmp/* && \
-    rm -rf /var/tmp/*
+      rm -rf /var/lib/apt/lists/* && \
+      rm -rf /tmp/* && \
+      rm -rf /var/tmp/*
 
 ENV THRIFT_ROOT /thrift
 RUN mkdir -p $THRIFT_ROOT/src
diff --git a/build/docker/ubuntu-bionic/Dockerfile b/build/docker/ubuntu-bionic/Dockerfile
index 54b384e..a673351 100644
--- a/build/docker/ubuntu-bionic/Dockerfile
+++ b/build/docker/ubuntu-bionic/Dockerfile
@@ -22,8 +22,8 @@
 ### Add apt repos
 
 RUN apt-get update && \
-    apt-get dist-upgrade -y && \
-    apt-get install -y --no-install-recommends --fix-missing \
+      apt-get dist-upgrade -y && \
+      apt-get install -y --no-install-recommends --fix-missing \
       apt \
       apt-transport-https \
       apt-utils \
@@ -34,22 +34,22 @@
 
 # Dart
 RUN curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
-    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
       /etc/apt/sources.list.d/dart_stable.list
 
 # dotnet (netcore)
 RUN curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
-    wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
-    chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
-    chown root:root /etc/apt/sources.list.d/microsoft-prod.list
+      wget -q -O /etc/apt/sources.list.d/microsoft-prod.list https://packages.microsoft.com/config/ubuntu/18.04/prod.list && \
+      chown root:root /etc/apt/trusted.gpg.d/microsoft.gpg && \
+      chown root:root /etc/apt/sources.list.d/microsoft-prod.list
 
 # node.js
 RUN curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
-    echo "deb https://deb.nodesource.com/node_10.x bionic main" | tee /etc/apt/sources.list.d/nodesource.list
+      echo "deb https://deb.nodesource.com/node_10.x bionic main" | tee /etc/apt/sources.list.d/nodesource.list
 
 ### install general dependencies
 RUN apt-get update && apt-get install -y --no-install-recommends \
-`# General dependencies` \
+      `# General dependencies` \
       bash-completion \
       bison \
       build-essential \
@@ -71,15 +71,15 @@
 
 # lib/as3 (ActionScript)
 RUN mkdir -p /usr/local/adobe/flex/4.6 && \
-    cd /usr/local/adobe/flex/4.6 && \
-    wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
-    unzip flex_sdk_4.6.zip
+      cd /usr/local/adobe/flex/4.6 && \
+      wget -q "http://download.macromedia.com/pub/flex/sdk/flex_sdk_4.6.zip" && \
+      unzip flex_sdk_4.6.zip
 ENV FLEX_HOME /usr/local/adobe/flex/4.6
 
 # TODO: "apt-get install" without "apt-get update" in the same "RUN" step can cause cache issues if modified later.
 # See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
 RUN apt-get install -y --no-install-recommends \
-`# C++ dependencies` \
+      `# C++ dependencies` \
       libboost-all-dev \
       libevent-dev \
       libssl-dev \
@@ -87,31 +87,43 @@
       qtbase5-dev \
       qtbase5-dev-tools
 
+ENV SBCL_VERSION 1.5.3
+RUN \
+      `# Common Lisp (sbcl) dependencies` \
+      curl --version && \
+      curl -o sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 -J -L https://sourceforge.net/projects/sbcl/files/sbcl/${SBCL_VERSION}/sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2/download?use_mirror=managedway# && \
+      tar xjf sbcl-${SBCL_VERSION}-x86-64-linux-binary.tar.bz2 && \
+      cd sbcl-${SBCL_VERSION}-x86-64-linux && \
+      ./install.sh && \
+      sbcl --version && \
+      cd .. && \
+      rm -rf sbcl*
+
 ENV D_VERSION     2.087.0
 ENV DMD_DEB       dmd_2.087.0-0_amd64.deb
 RUN \
-`# D dependencies` \
-    wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
-    dpkg --install ${DMD_DEB} && \
-    rm -f ${DMD_DEB} && \
-    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
-    git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
-    mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-libevent-2.0 && \
-    git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
-    mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-openssl-1.1.0h
+      `# D dependencies` \
+      wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
+      dpkg --install ${DMD_DEB} && \
+      rm -f ${DMD_DEB} && \
+      mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+      git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
+      mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-libevent-2.0 && \
+      git clone -b 'v2.0.0+1.1.0h' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.1.0h && \
+      mv deimos-openssl-1.1.0h/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-openssl-1.1.0h/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-openssl-1.1.0h
 
 ENV DART_VERSION 2.7.2-1
 RUN apt-get install -y --no-install-recommends \
-`# Dart dependencies` \
+      `# Dart dependencies` \
       dart=$DART_VERSION
 ENV PATH /usr/lib/dart/bin:$PATH
 
 RUN apt-get install -y --no-install-recommends \
-`# dotnet core dependencies` \
+      `# dotnet core dependencies` \
       dotnet-sdk-6.0 \
       dotnet-runtime-6.0 \
       aspnetcore-runtime-6.0 \
@@ -121,14 +133,14 @@
 ARG ERLANG_OTP_VERSION=23.3.4.11
 ARG ERLANG_REBAR_VERSION=3.18.0
 RUN apt-get update && apt-get install -y --no-install-recommends libncurses5-dev && \
-    curl -ssLo /usr/local/bin/kerl https://raw.githubusercontent.com/kerl/kerl/master/kerl && chmod +x /usr/local/bin/kerl && \
-    kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
-    curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
-    rebar3 --version
+      curl -ssLo /usr/local/bin/kerl https://raw.githubusercontent.com/kerl/kerl/master/kerl && chmod +x /usr/local/bin/kerl && \
+      kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
+      curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
+      rebar3 --version
 ENV PATH /usr/local/lib/otp/bin:$PATH
 
 RUN apt-get install -y --no-install-recommends \
-`# GlibC dependencies` \
+      `# GlibC dependencies` \
       libglib2.0-dev
 
 # golang
@@ -137,34 +149,34 @@
 ENV GOLANG_DOWNLOAD_SHA256 464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6
 RUN curl -fsSL "$GOLANG_DOWNLOAD_URL" -o golang.tar.gz && \
       echo "$GOLANG_DOWNLOAD_SHA256  golang.tar.gz" | sha256sum -c - && \
-            tar -C /usr/local -xzf golang.tar.gz && \
-                  ln -s /usr/local/go/bin/go /usr/local/bin && \
-                        rm golang.tar.gz
+      tar -C /usr/local -xzf golang.tar.gz && \
+      ln -s /usr/local/go/bin/go /usr/local/bin && \
+      rm golang.tar.gz
 
 RUN apt-get install -y --no-install-recommends \
-`# Haxe dependencies` \
+      `# Haxe dependencies` \
       haxe \
       neko \
       neko-dev && \
-    haxelib setup --always /usr/share/haxe/lib && \
-    haxelib install --always hxcpp 2>&1 > /dev/null
+      haxelib setup --always /usr/share/haxe/lib && \
+      haxelib install --always hxcpp 2>&1 > /dev/null
 
-ENV GRADLE_VERSION="7.4.2"
+ENV GRADLE_VERSION="7.5.1"
 RUN apt-get install -y --no-install-recommends \
-`# Java dependencies` \
+      `# Java dependencies` \
       ant \
       ant-optional \
       maven \
       openjdk-11-jdk-headless && \
-`# Gradle` \
+      `# Gradle` \
       wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
-      (echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
+      (echo "f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
       unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
       mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
       ln -s /usr/local/gradle/bin/gradle /usr/local/bin
 
 RUN apt-get install -y --no-install-recommends \
-`# Lua dependencies` \
+      `# Lua dependencies` \
       lua5.2 \
       lua5.2-dev
 # https://bugs.launchpad.net/ubuntu/+source/lua5.3/+bug/1707212
@@ -172,24 +184,24 @@
 # need to update our luasocket code, lua doesn't have luaL_openlib any more
 
 RUN apt-get install -y --no-install-recommends \
-`# Node.js dependencies` \
+      `# Node.js dependencies` \
       nodejs
 
 # Test dependencies for running puppeteer
 RUN apt-get install -y --no-install-recommends \
-`# JS dependencies` \
+      `# JS dependencies` \
       libxss1 \
       libxtst6
 
 RUN apt-get install -y --no-install-recommends \
-`# OCaml dependencies` \
+      `# OCaml dependencies` \
       ocaml \
       opam && \
-    opam init --yes && \
-    opam install --yes oasis
+      opam init --yes && \
+      opam install --yes oasis
 
 RUN apt-get install -y --no-install-recommends \
-`# Perl dependencies` \
+      `# Perl dependencies` \
       libbit-vector-perl \
       libclass-accessor-class-perl \
       libcrypt-ssleay-perl \
@@ -198,7 +210,7 @@
       libtest-exception-perl
 
 RUN apt-get install -y --no-install-recommends \
-`# Php dependencies` \
+      `# Php dependencies` \
       php \
       php-cli \
       php-dev \
@@ -208,7 +220,7 @@
       composer
 
 RUN apt-get install -y --no-install-recommends \
-`# Python dependencies` \
+      `# Python dependencies` \
       python-all \
       python-all-dbg \
       python-all-dev \
@@ -220,10 +232,10 @@
       python-twisted \
       python-wheel \
       python-zope.interface && \
-   pip install --upgrade backports.ssl_match_hostname
+      pip install --upgrade backports.ssl_match_hostname
 
 RUN apt-get install -y --no-install-recommends \
-`# Python3 dependencies` \
+      `# Python3 dependencies` \
       python3-all \
       python3-all-dbg \
       python3-all-dev \
@@ -236,39 +248,39 @@
       python3-zope.interface
 
 RUN apt-get install -y --no-install-recommends \
-`# Ruby dependencies` \
+      `# Ruby dependencies` \
       ruby \
       ruby-dev \
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 ENV PATH /root/.cargo/bin:$PATH
 
 # Swift on Linux for cross tests
 RUN cd / && \
-    wget --quiet https://swift.org/builds/swift-5.1.4-release/ubuntu1804/swift-5.1.4-RELEASE/swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
-    tar xf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \
-    rm swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
-    swift --version
+      wget --quiet https://swift.org/builds/swift-5.1.4-release/ubuntu1804/swift-5.1.4-RELEASE/swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
+      tar xf swift-5.1.4-RELEASE-ubuntu18.04.tar.gz --strip-components=1 && \
+      rm swift-5.1.4-RELEASE-ubuntu18.04.tar.gz && \
+      swift --version
 
 # Locale(s) for cpp unit tests
 RUN apt-get install -y --no-install-recommends \
-`# Locale dependencies` \
+      `# Locale dependencies` \
       locales && \
-    locale-gen en_US.UTF-8 && \
-    locale-gen de_DE.UTF-8 && \
-    update-locale
+      locale-gen en_US.UTF-8 && \
+      locale-gen de_DE.UTF-8 && \
+      update-locale
 
 # cppcheck-1.82 has a nasty cpp parser bug, so we're using something newer
 RUN apt-get install -y --no-install-recommends \
-`# Static Code Analysis dependencies` \
+      `# Static Code Analysis dependencies` \
       cppcheck \
       sloccount && \
-    pip install flake8 && \
-    wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \
-    dpkg -i cppcheck_1.83-2_amd64.deb && \
-    rm cppcheck_1.83-2_amd64.deb
+      pip install flake8 && \
+      wget -q "https://launchpad.net/ubuntu/+source/cppcheck/1.83-2/+build/14874703/+files/cppcheck_1.83-2_amd64.deb" && \
+      dpkg -i cppcheck_1.83-2_amd64.deb && \
+      rm cppcheck_1.83-2_amd64.deb
 
 # NOTE: this does not reduce the image size but adds an additional layer.
 # # Clean up
diff --git a/build/docker/ubuntu-xenial/Dockerfile b/build/docker/ubuntu-xenial/Dockerfile
index aec9bd3..7cb58e8 100644
--- a/build/docker/ubuntu-xenial/Dockerfile
+++ b/build/docker/ubuntu-xenial/Dockerfile
@@ -28,8 +28,8 @@
 ### Add apt repos
 
 RUN apt-get update && \
-    apt-get dist-upgrade -y && \
-    apt-get install -y --no-install-recommends \
+      apt-get dist-upgrade -y && \
+      apt-get install -y --no-install-recommends \
       apt \
       apt-transport-https \
       apt-utils \
@@ -37,26 +37,26 @@
       software-properties-common \
       wget && \
 
-# Dart
-    curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
-    curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
+      # Dart
+      curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
+      curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > \
       /etc/apt/sources.list.d/dart_stable.list && \
 
-# dotnet (core)
-    curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
-    echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \
+      # dotnet (core)
+      curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > /etc/apt/trusted.gpg.d/microsoft.gpg && \
+      echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > \
       /etc/apt/sources.list.d/dotnetdev.list && \
 
-# node.js
-    curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
-    echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list && \
+      # node.js
+      curl -sL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - && \
+      echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee /etc/apt/sources.list.d/nodesource.list && \
 
-# ruby 2.4
-    apt-add-repository ppa:brightbox/ruby-ng
+      # ruby 2.4
+      apt-add-repository ppa:brightbox/ruby-ng
 
 ### install general dependencies
 RUN apt-get update && apt-get install -y --no-install-recommends \
-`# General dependencies` \
+      `# General dependencies` \
       bash-completion \
       bison \
       build-essential \
@@ -77,7 +77,7 @@
 # TODO: "apt-get install" without "apt-get update" in the same "RUN" step can cause cache issues if modified later.
 # See https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#run
 RUN apt-get install -y --no-install-recommends \
-`# C++ dependencies` \
+      `# C++ dependencies` \
       libboost-dev \
       libboost-filesystem-dev \
       libboost-program-options-dev \
@@ -93,28 +93,28 @@
 ENV D_VERSION     2.087.0
 ENV DMD_DEB       dmd_2.087.0-0_amd64.deb
 RUN \
-`# D dependencies` \
-    wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
-    dpkg --install ${DMD_DEB} && \
-    rm -f ${DMD_DEB} && \
-    mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
-    git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
-    mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-libevent-2.0 && \
-    git clone -b 'v1.1.6+1.0.1g' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.0.1g && \
-    mv deimos-openssl-1.0.1g/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
-    mv deimos-openssl-1.0.1g/C/* /usr/include/dmd/druntime/import/C/ && \
-    rm -rf deimos-openssl-1.0.1g
+      `# D dependencies` \
+      wget -q http://downloads.dlang.org/releases/2.x/${D_VERSION}/${DMD_DEB} && \
+      dpkg --install ${DMD_DEB} && \
+      rm -f ${DMD_DEB} && \
+      mkdir -p /usr/include/dmd/druntime/import/deimos /usr/include/dmd/druntime/import/C && \
+      git clone -b 'v2.0.2+2.0.16' https://github.com/D-Programming-Deimos/libevent.git deimos-libevent-2.0 && \
+      mv deimos-libevent-2.0/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-libevent-2.0/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-libevent-2.0 && \
+      git clone -b 'v1.1.6+1.0.1g' https://github.com/D-Programming-Deimos/openssl.git deimos-openssl-1.0.1g && \
+      mv deimos-openssl-1.0.1g/deimos/* /usr/include/dmd/druntime/import/deimos/ && \
+      mv deimos-openssl-1.0.1g/C/* /usr/include/dmd/druntime/import/C/ && \
+      rm -rf deimos-openssl-1.0.1g
 
 ENV DART_VERSION 2.7.2-1
 RUN apt-get install -y --no-install-recommends \
-`# Dart dependencies` \
+      `# Dart dependencies` \
       dart=$DART_VERSION
 ENV PATH /usr/lib/dart/bin:$PATH
 
 RUN apt-get install -y --no-install-recommends \
-`# dotnet core dependencies` \
+      `# dotnet core dependencies` \
       dotnet-sdk-6.0 \
       dotnet-runtime-6.0 \
       aspnetcore-runtime-6.0 \
@@ -124,15 +124,15 @@
 ARG ERLANG_OTP_VERSION=18.3.4.11
 ARG ERLANG_REBAR_VERSION=3.13.2
 RUN apt-get update && apt-get install -y --no-install-recommends automake libncurses5-dev && \
-    curl https://raw.githubusercontent.com/kerl/kerl/master/kerl -o /usr/local/bin/kerl && chmod +x /usr/local/bin/kerl && \
-    kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
-    curl https://s3.amazonaws.com/rebar3/rebar3 -o /usr/local/bin/rebar3 && chmod +x /usr/local/bin/rebar3 && \
-    curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
-    rebar3 --version
+      curl https://raw.githubusercontent.com/kerl/kerl/master/kerl -o /usr/local/bin/kerl && chmod +x /usr/local/bin/kerl && \
+      kerl build $ERLANG_OTP_VERSION && kerl install $ERLANG_OTP_VERSION /usr/local/lib/otp/ && . /usr/local/lib/otp/activate && \
+      curl https://s3.amazonaws.com/rebar3/rebar3 -o /usr/local/bin/rebar3 && chmod +x /usr/local/bin/rebar3 && \
+      curl -ssLo /usr/local/bin/rebar3 https://github.com/erlang/rebar3/releases/download/${ERLANG_REBAR_VERSION}/rebar3 && chmod +x /usr/local/bin/rebar3 && \
+      rebar3 --version
 ENV PATH /usr/local/lib/otp/bin:$PATH
 
 RUN apt-get install -y --no-install-recommends \
-`# GlibC dependencies` \
+      `# GlibC dependencies` \
       libglib2.0-dev
 
 # golang
@@ -146,26 +146,26 @@
       rm golang.tar.gz
 
 RUN apt-get install -y --no-install-recommends \
-`# Haxe dependencies` \
+      `# Haxe dependencies` \
       haxe \
       neko \
       neko-dev \
       libneko0 && \
-    haxelib setup --always /usr/share/haxe/lib && \
-    haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null
+      haxelib setup --always /usr/share/haxe/lib && \
+      haxelib install --always hxcpp 3.4.64 2>&1 > /dev/null
 # note: hxcpp 3.4.185 (latest) no longer ships static libraries, and caused a build failure
 
-ENV GRADLE_VERSION="7.4.2"
+ENV GRADLE_VERSION="7.5.1"
 RUN apt-get install -y --no-install-recommends \
-`# Java dependencies` \
+      `# Java dependencies` \
       ant \
       ant-optional \
       openjdk-8-jdk \
       maven \
       unzip && \
-`# Gradle` \
+      `# Gradle` \
       wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip && \
-      (echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
+      (echo "f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -) && \
       unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip && \
       mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle && \
       ln -s /usr/local/gradle/bin/gradle /usr/local/bin
@@ -179,12 +179,12 @@
 # lua5.3 does not install alternatives so stick with 5.2 here
 
 RUN apt-get install -y --no-install-recommends \
-`# Node.js dependencies` \
+      `# Node.js dependencies` \
       nodejs
 
 # Test dependencies for running puppeteer
 RUN apt-get install -y --no-install-recommends \
-`# JS dependencies` \
+      `# JS dependencies` \
       libxss1 \
       libxtst6 \
       libatk-bridge2.0-0 \
@@ -199,7 +199,7 @@
 #     opam install --yes oasis
 
 RUN apt-get install -y --no-install-recommends \
-`# Perl dependencies` \
+      `# Perl dependencies` \
       libbit-vector-perl \
       libclass-accessor-class-perl \
       libcrypt-ssleay-perl \
@@ -208,7 +208,7 @@
       libtest-exception-perl
 
 RUN apt-get install -y --no-install-recommends \
-`# Php dependencies` \
+      `# Php dependencies` \
       php7.0 \
       php7.0-cli \
       php7.0-dev \
@@ -218,7 +218,7 @@
       composer
 
 RUN apt-get install -y --no-install-recommends \
-`# Python dependencies` \
+      `# Python dependencies` \
       python-all \
       python-all-dbg \
       python-all-dev \
@@ -240,24 +240,24 @@
       python3-twisted \
       python3-wheel \
       python3-zope.interface && \
-    pip install --upgrade backports.ssl_match_hostname
+      pip install --upgrade backports.ssl_match_hostname
 
 RUN apt-get install -y --no-install-recommends \
-`# Ruby dependencies` \
+      `# Ruby dependencies` \
       ruby2.4 \
       ruby2.4-dev \
       ruby-bundler
 
 # Rust dependencies
-RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.40.0 -y
+RUN curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain 1.61.0 -y
 
 # Locale(s) for cpp unit tests
 RUN apt-get install -y --no-install-recommends \
-`# Locale dependencies` \
+      `# Locale dependencies` \
       locales && \
-    locale-gen en_US.UTF-8 && \
-    locale-gen de_DE.UTF-8 && \
-    update-locale
+      locale-gen en_US.UTF-8 && \
+      locale-gen de_DE.UTF-8 && \
+      update-locale
 
 # NOTE: this does not reduce the image size but adds an additional layer.
 # # Clean up
diff --git a/compiler/cpp/CMakeLists.txt b/compiler/cpp/CMakeLists.txt
index 717b645..b0f1235 100644
--- a/compiler/cpp/CMakeLists.txt
+++ b/compiler/cpp/CMakeLists.txt
@@ -46,6 +46,8 @@
 set(compiler_core
     src/thrift/common.cc
     src/thrift/generate/t_generator.cc
+    src/thrift/generate/validator_parser.cc
+    src/thrift/generate/validator_parser.h
     src/thrift/parse/t_typedef.cc
     src/thrift/parse/parse.cc
     src/thrift/version.h
@@ -71,35 +73,51 @@
     endif()
 endmacro()
 
+# This macro adds an option THRIFT_VALIDATOR_COMPILER_${NAME}
+# that allows enabling or disabling certain languages' validator
+macro(THRIFT_ADD_VALIDATOR_COMPILER name description initial)
+    string(TOUPPER "THRIFT_COMPILER_${name}" enabler)
+    set(src "src/thrift/generate/${name}_validator_generator.cc")
+    list(APPEND "src/thrift/generate/${name}_validator_generator.h")
+    option(${enabler} ${description} ${initial})
+    if(${enabler})
+        list(APPEND thrift-compiler_SOURCES ${src})
+    endif()
+endmacro()
+
 # The following compiler can be enabled or disabled
-THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" ON)
-THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" ON)
-THRIFT_ADD_COMPILER(d       "Enable compiler for D" ON)
-THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" ON)
-THRIFT_ADD_COMPILER(delphi  "Enable compiler for Delphi" ON)
-THRIFT_ADD_COMPILER(erl     "Enable compiler for Erlang" ON)
-THRIFT_ADD_COMPILER(go      "Enable compiler for Go" ON)
-THRIFT_ADD_COMPILER(gv      "Enable compiler for GraphViz" ON)
-THRIFT_ADD_COMPILER(haxe    "Enable compiler for Haxe" ON)
-THRIFT_ADD_COMPILER(html    "Enable compiler for HTML Documentation" ON)
-THRIFT_ADD_COMPILER(markdown "Enable compiler for Markdown Documentation" ON)
-THRIFT_ADD_COMPILER(java    "Enable compiler for Java"   ON)
-THRIFT_ADD_COMPILER(javame  "Enable compiler for Java ME" ON)
-THRIFT_ADD_COMPILER(js      "Enable compiler for JavaScript" ON)
-THRIFT_ADD_COMPILER(json    "Enable compiler for JSON" ON)
-THRIFT_ADD_COMPILER(kotlin  "Enable compiler for Kotlin" ON)
-THRIFT_ADD_COMPILER(lua     "Enable compiler for Lua" ON)
-THRIFT_ADD_COMPILER(netstd  "Enable compiler for .NET Standard" ON)
-THRIFT_ADD_COMPILER(ocaml   "Enable compiler for OCaml" ON)
-THRIFT_ADD_COMPILER(perl    "Enable compiler for Perl" ON)
-THRIFT_ADD_COMPILER(php     "Enable compiler for PHP" ON)
-THRIFT_ADD_COMPILER(py      "Enable compiler for Python 2.0" ON)
-THRIFT_ADD_COMPILER(rb      "Enable compiler for Ruby" ON)
-THRIFT_ADD_COMPILER(rs      "Enable compiler for Rust" ON)
-THRIFT_ADD_COMPILER(st      "Enable compiler for Smalltalk" ON)
-THRIFT_ADD_COMPILER(swift   "Enable compiler for Cocoa Swift" ON)
-THRIFT_ADD_COMPILER(xml     "Enable compiler for XML" ON)
-THRIFT_ADD_COMPILER(xsd     "Enable compiler for XSD" ON)
+THRIFT_ADD_COMPILER(c_glib        "Enable compiler for C with Glib" ON)
+THRIFT_ADD_COMPILER(cl            "Enable compiler for Common LISP" ON)
+THRIFT_ADD_COMPILER(cpp           "Enable compiler for C++" ON)
+THRIFT_ADD_COMPILER(d             "Enable compiler for D" ON)
+THRIFT_ADD_COMPILER(dart          "Enable compiler for Dart" ON)
+THRIFT_ADD_COMPILER(delphi        "Enable compiler for Delphi" ON)
+THRIFT_ADD_COMPILER(erl           "Enable compiler for Erlang" ON)
+THRIFT_ADD_COMPILER(go            "Enable compiler for Go" ON)
+THRIFT_ADD_COMPILER(gv            "Enable compiler for GraphViz" ON)
+THRIFT_ADD_COMPILER(haxe          "Enable compiler for Haxe" ON)
+THRIFT_ADD_COMPILER(html          "Enable compiler for HTML Documentation" ON)
+THRIFT_ADD_COMPILER(markdown      "Enable compiler for Markdown Documentation" ON)
+THRIFT_ADD_COMPILER(java          "Enable compiler for Java"   ON)
+THRIFT_ADD_COMPILER(javame        "Enable compiler for Java ME" ON)
+THRIFT_ADD_COMPILER(js            "Enable compiler for JavaScript" ON)
+THRIFT_ADD_COMPILER(json          "Enable compiler for JSON" ON)
+THRIFT_ADD_COMPILER(kotlin        "Enable compiler for Kotlin" ON)
+THRIFT_ADD_COMPILER(lua           "Enable compiler for Lua" ON)
+THRIFT_ADD_COMPILER(netstd        "Enable compiler for .NET Standard" ON)
+THRIFT_ADD_COMPILER(ocaml         "Enable compiler for OCaml" ON)
+THRIFT_ADD_COMPILER(perl          "Enable compiler for Perl" ON)
+THRIFT_ADD_COMPILER(php           "Enable compiler for PHP" ON)
+THRIFT_ADD_COMPILER(py            "Enable compiler for Python 2.0" ON)
+THRIFT_ADD_COMPILER(rb            "Enable compiler for Ruby" ON)
+THRIFT_ADD_COMPILER(rs            "Enable compiler for Rust" ON)
+THRIFT_ADD_COMPILER(st            "Enable compiler for Smalltalk" ON)
+THRIFT_ADD_COMPILER(swift         "Enable compiler for Cocoa Swift" ON)
+THRIFT_ADD_COMPILER(xml           "Enable compiler for XML" ON)
+THRIFT_ADD_COMPILER(xsd           "Enable compiler for XSD" ON)
+
+# The following compiler can be enabled or disabled by enabling or disabling certain languages
+THRIFT_ADD_VALIDATOR_COMPILER(go           "Enable validator compiler for Go" ON)
 
 # Thrift is looking for include files in the src directory
 # we also add the current binary directory for generated files
diff --git a/compiler/cpp/Makefile.am b/compiler/cpp/Makefile.am
index cc776ef..bb29d8c 100644
--- a/compiler/cpp/Makefile.am
+++ b/compiler/cpp/Makefile.am
@@ -70,12 +70,14 @@
 
 # Specific client generator source
 thrift_SOURCES += src/thrift/generate/t_c_glib_generator.cc \
+                  src/thrift/generate/t_cl_generator.cc \
                   src/thrift/generate/t_cpp_generator.cc \
                   src/thrift/generate/t_d_generator.cc \
                   src/thrift/generate/t_dart_generator.cc \
                   src/thrift/generate/t_delphi_generator.cc \
                   src/thrift/generate/t_erl_generator.cc \
                   src/thrift/generate/t_go_generator.cc \
+                  src/thrift/generate/t_go_generator.h \
                   src/thrift/generate/t_gv_generator.cc \
                   src/thrift/generate/t_haxe_generator.cc \
                   src/thrift/generate/t_html_generator.cc \
@@ -97,7 +99,11 @@
                   src/thrift/generate/t_st_generator.cc \
                   src/thrift/generate/t_swift_generator.cc \
                   src/thrift/generate/t_xml_generator.cc \
-                  src/thrift/generate/t_xsd_generator.cc
+                  src/thrift/generate/t_xsd_generator.cc \
+                  src/thrift/generate/validator_parser.cc \
+                  src/thrift/generate/validator_parser.h \
+                  src/thrift/generate/go_validator_generator.cc \
+                  src/thrift/generate/go_validator_generator.h
 
 thrift_CPPFLAGS = -I$(srcdir)/src
 thrift_CXXFLAGS = -Wall -Wextra -pedantic -Werror
diff --git a/compiler/cpp/compiler.vcxproj b/compiler/cpp/compiler.vcxproj
index ae77f3d..9fbf903 100644
--- a/compiler/cpp/compiler.vcxproj
+++ b/compiler/cpp/compiler.vcxproj
@@ -54,6 +54,7 @@
     <ClCompile Include="src\thrift\audit\t_audit.cpp" />
     <ClCompile Include="src\thrift\common.cc" />
     <ClCompile Include="src\thrift\generate\t_c_glib_generator.cc" />
+    <ClCompile Include="src\thrift\generate\t_cl_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_cpp_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_d_generator.cc" />
     <ClCompile Include="src\thrift\generate\t_dart_generator.cc" />
diff --git a/compiler/cpp/src/thrift/common.cc b/compiler/cpp/src/thrift/common.cc
index 6dcd855..3a28407 100644
--- a/compiler/cpp/src/thrift/common.cc
+++ b/compiler/cpp/src/thrift/common.cc
@@ -23,6 +23,7 @@
 t_type* g_type_void;
 t_type* g_type_string;
 t_type* g_type_binary;
+t_type* g_type_uuid;
 t_type* g_type_bool;
 t_type* g_type_i8;
 t_type* g_type_i16;
@@ -35,6 +36,7 @@
   g_type_string = new t_base_type("string", t_base_type::TYPE_STRING);
   g_type_binary = new t_base_type("string", t_base_type::TYPE_STRING);
   ((t_base_type*)g_type_binary)->set_binary(true);
+  g_type_uuid = new t_base_type("string", t_base_type::TYPE_UUID);
   g_type_bool = new t_base_type("bool", t_base_type::TYPE_BOOL);
   g_type_i8 = new t_base_type("i8", t_base_type::TYPE_I8);
   g_type_i16 = new t_base_type("i16", t_base_type::TYPE_I16);
@@ -46,6 +48,8 @@
 void clearGlobals() {
   delete g_type_void;
   delete g_type_string;
+  delete g_type_binary;
+  delete g_type_uuid;
   delete g_type_bool;
   delete g_type_i8;
   delete g_type_i16;
diff --git a/compiler/cpp/src/thrift/common.h b/compiler/cpp/src/thrift/common.h
index 06392cd..059421d 100644
--- a/compiler/cpp/src/thrift/common.h
+++ b/compiler/cpp/src/thrift/common.h
@@ -29,6 +29,7 @@
 extern t_type* g_type_void;
 extern t_type* g_type_string;
 extern t_type* g_type_binary;
+extern t_type* g_type_uuid;
 extern t_type* g_type_bool;
 extern t_type* g_type_i8;
 extern t_type* g_type_i16;
diff --git a/compiler/cpp/src/thrift/generate/go_validator_generator.cc b/compiler/cpp/src/thrift/generate/go_validator_generator.cc
new file mode 100644
index 0000000..1f5a3ad
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/go_validator_generator.cc
@@ -0,0 +1,906 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U go_validator_generator.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/go_validator_generator.h"
+#include "thrift/generate/validator_parser.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+std::string go_validator_generator::get_field_reference_name(t_field* field) {
+  t_type* type(field->get_type());
+  std::string tgt;
+  t_const_value* def_value;
+  go_generator->get_publicized_name_and_def_value(field, &tgt, &def_value);
+  tgt = "p." + tgt;
+  if (go_generator->is_pointer_field(field)
+      && (type->is_base_type() || type->is_enum() || type->is_container())) {
+    tgt = "*" + tgt;
+  }
+  return tgt;
+}
+
+void go_validator_generator::generate_struct_validator(std::ostream& out, t_struct* tstruct) {
+  std::vector<t_field*> members = tstruct->get_members();
+  validation_parser parser(tstruct);
+  for (auto it = members.begin(); it != members.end(); it++) {
+    t_field* field(*it);
+    const std::vector<validation_rule*>& rules
+        = parser.parse_field(field->get_type(), field->annotations_);
+    if (rules.size() == 0) {
+      continue;
+    }
+    bool opt = field->get_req() == t_field::T_OPTIONAL;
+    t_type* type = field->get_type();
+    std::string tgt = get_field_reference_name(field);
+    std::string field_symbol = tstruct->get_name() + "." + field->get_name();
+    generate_field_validator(out, generator_context{field_symbol, "", tgt, opt, type, rules});
+  }
+}
+
+void go_validator_generator::generate_field_validator(std::ostream& out,
+                                                      const generator_context& context) {
+  t_type* type = context.type;
+  if (type->is_typedef()) {
+    type = type->get_true_type();
+  }
+  if (type->is_enum()) {
+    if (context.tgt[0] == '*') {
+      out << indent() << "if " << context.tgt.substr(1) << " != nil {" << endl;
+      indent_up();
+    }
+    generate_enum_field_validator(out, context);
+    if (context.tgt[0] == '*') {
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+    return;
+  } else if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    if (context.tgt[0] == '*') {
+      out << indent() << "if " << context.tgt.substr(1) << " != nil {" << endl;
+      indent_up();
+    }
+    switch (tbase) {
+    case t_base_type::TYPE_UUID:
+    case t_base_type::TYPE_VOID:
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      generate_integer_field_validator(out, context);
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      generate_double_field_validator(out, context);
+      break;
+    case t_base_type::TYPE_STRING:
+      generate_string_field_validator(out, context);
+      break;
+    case t_base_type::TYPE_BOOL:
+      generate_bool_field_validator(out, context);
+      break;
+    }
+    if (context.tgt[0] == '*') {
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+    return;
+  } else if (type->is_list()) {
+    return generate_list_field_validator(out, context);
+  } else if (type->is_set()) {
+    return generate_set_field_validator(out, context);
+  } else if (type->is_map()) {
+    return generate_map_field_validator(out, context);
+  } else if (type->is_struct() || type->is_xception()) {
+    return generate_struct_field_validator(out, context);
+  }
+  throw "validator error: unsupported type: " + type->get_name();
+}
+
+void go_validator_generator::generate_enum_field_validator(std::ostream& out,
+                                                           const generator_context& context) {
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+    std::string key = (*it)->get_name();
+
+    if (key == "vt.in") {
+      if (values.size() > 1) {
+        std::string exist = GenID("_exist");
+        out << indent() << "var " << exist << " bool" << endl;
+
+        std::string src = GenID("_src");
+        out << indent() << src << " := []int64{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          out << "int64(";
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else {
+            out << (*it)->get_enum()->get_value();
+          }
+          out << ")";
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if int64(" << context.tgt << ") == src {" << endl;
+        indent_up();
+        out << indent() << exist << " = true" << endl;
+        out << indent() << "break" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        out << indent() << "if " << exist << " == false {" << endl;
+      } else {
+        out << indent() << "if int64(" << context.tgt << ") != int64(";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else {
+          out << values[0]->get_enum()->get_value();
+        }
+        out << ") {" << endl;
+      }
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+      if (values.size() > 1) {
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    } else if (key == "vt.not_in") {
+      if (values.size() > 1) {
+        std::string src = GenID("_src");
+        out << indent() << src << " := []int64{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          out << "int64(";
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else {
+            out << (*it)->get_enum()->get_value();
+          }
+          out << ")";
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if int64(" << context.tgt << ") == src {" << endl;
+      } else {
+        out << indent() << "if int64(" << context.tgt << ") == ";
+        out << "int64(";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else {
+          out << values[0]->get_enum()->get_value();
+        }
+        out << ") {" << endl;
+      }
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.not_in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+      if (values.size() > 1) {
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    } else if (key == "vt.defined_only") {
+      if (values[0]->get_bool()) {
+        out << indent() << "if (" << context.tgt << ").String() == \"<UNSET>\" ";
+      } else {
+        continue;
+      }
+      out << "{" << endl;
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+          << " check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+  }
+}
+
+void go_validator_generator::generate_bool_field_validator(std::ostream& out,
+                                                           const generator_context& context) {
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+    std::string key = (*it)->get_name();
+
+    if (key == "vt.const") {
+      out << indent() << "if " << context.tgt << " != ";
+      if (values[0]->is_field_reference()) {
+        out << get_field_reference_name(values[0]->get_field_reference());
+      } else {
+        if (values[0]->get_bool()) {
+          out << "true";
+        } else {
+          out << "false";
+        }
+      }
+    }
+    out << "{" << endl;
+    indent_up();
+    out << indent()
+        << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+        << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+        << " check failed\")" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+}
+
+void go_validator_generator::generate_double_field_validator(std::ostream& out,
+                                                             const generator_context& context) {
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+
+    std::map<std::string, std::string> signs{{"vt.lt", ">="},
+                                             {"vt.le", ">"},
+                                             {"vt.gt", "<="},
+                                             {"vt.ge", "<"}};
+    std::string key = (*it)->get_name();
+    auto key_it = signs.find(key);
+    if (key_it != signs.end()) {
+      out << indent() << "if " << context.tgt << " " << key_it->second << " ";
+      if (values[0]->is_field_reference()) {
+        out << get_field_reference_name(values[0]->get_field_reference());
+      } else {
+        out << values[0]->get_double();
+      }
+      out << "{" << endl;
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+          << " check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+      continue;
+    } else if (key == "vt.in") {
+      if (values.size() > 1) {
+        std::string exist = GenID("_exist");
+        out << indent() << "var " << exist << " bool" << endl;
+
+        std::string src = GenID("_src");
+        out << indent() << src << " := []float64{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else {
+            out << (*it)->get_double();
+          }
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if " << context.tgt << " == src {" << endl;
+        indent_up();
+        out << indent() << exist << " = true" << endl;
+        out << indent() << "break" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        out << indent() << "if " << exist << " == false {" << endl;
+      } else {
+        out << indent() << "if " << context.tgt << " != ";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else {
+          out << values[0]->get_double();
+        }
+        out << "{" << endl;
+      }
+
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.not_in") {
+      if (values.size() > 1) {
+        std::string src = GenID("_src");
+        out << indent() << src << " := []float64{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else {
+            out << (*it)->get_double();
+          }
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if " << context.tgt << " == src {" << endl;
+      } else {
+        out << indent() << "if " << context.tgt << " == ";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else {
+          out << values[0]->get_double();
+        }
+        out << "{" << endl;
+      }
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.not_in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+      if (values.size() > 1) {
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    }
+  }
+}
+
+void go_validator_generator::generate_integer_field_validator(std::ostream& out,
+                                                              const generator_context& context) {
+  auto generate_current_type = [](std::ostream& out, t_type* type) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_I8:
+      out << "int8";
+      break;
+    case t_base_type::TYPE_I16:
+      out << "int16";
+      break;
+    case t_base_type::TYPE_I32:
+      out << "int32";
+      break;
+    case t_base_type::TYPE_I64:
+      out << "int64";
+      break;
+    default:
+      throw "validator error: unsupported integer type: " + type->get_name();
+    }
+  };
+
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+
+    std::map<std::string, std::string> signs{{"vt.lt", ">="},
+                                             {"vt.le", ">"},
+                                             {"vt.gt", "<="},
+                                             {"vt.ge", "<"}};
+    std::string key = (*it)->get_name();
+    auto key_it = signs.find(key);
+    if (key_it != signs.end()) {
+      out << indent() << "if " << context.tgt << " " << key_it->second << " ";
+      if (values[0]->is_field_reference()) {
+        out << get_field_reference_name(values[0]->get_field_reference());
+      } else if (values[0]->is_validation_function()) {
+        generate_current_type(out, context.type);
+        out << "(";
+        validation_value::validation_function* func = values[0]->get_function();
+        if (func->name == "len") {
+          out << "len(";
+          if (func->arguments[0]->is_field_reference()) {
+            out << get_field_reference_name(func->arguments[0]->get_field_reference());
+          }
+          out << ")";
+        }
+        out << ")";
+      } else {
+        out << values[0]->get_int();
+      }
+      out << "{" << endl;
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+          << " check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.in") {
+      if (values.size() > 1) {
+        std::string exist = GenID("_exist");
+        out << indent() << "var " << exist << " bool" << endl;
+
+        std::string src = GenID("_src");
+        out << indent() << src << " := []";
+        generate_current_type(out, context.type);
+        out << "{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else if ((*it)->is_validation_function()) {
+            generate_current_type(out, context.type);
+            out << "(";
+            validation_value::validation_function* func = (*it)->get_function();
+            if (func->name == "len") {
+              out << "len(";
+              if (func->arguments[0]->is_field_reference()) {
+                out << get_field_reference_name(func->arguments[0]->get_field_reference());
+              }
+              out << ")";
+            }
+            out << ")";
+          } else {
+            out << (*it)->get_int();
+          }
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if " << context.tgt << " == src {" << endl;
+        indent_up();
+        out << indent() << exist << " = true" << endl;
+        out << indent() << "break" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        out << indent() << "if " << exist << " == false {" << endl;
+      } else {
+        out << indent() << "if " << context.tgt << " != ";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else if (values[0]->is_validation_function()) {
+          generate_current_type(out, context.type);
+          out << "(";
+          validation_value::validation_function* func = values[0]->get_function();
+          if (func->name == "len") {
+            out << "len(";
+            if (func->arguments[0]->is_field_reference()) {
+              out << get_field_reference_name(func->arguments[0]->get_field_reference());
+            }
+            out << ")";
+          }
+          out << ")";
+        } else {
+          out << values[0]->get_int();
+        }
+        out << "{" << endl;
+      }
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.not_in") {
+      if (values.size() > 1) {
+        std::string src = GenID("_src");
+        out << indent() << src << " := []";
+        t_base_type::t_base tbase = ((t_base_type*)context.type)->get_base();
+        switch (tbase) {
+        case t_base_type::TYPE_I8:
+          out << "int8";
+          break;
+        case t_base_type::TYPE_I16:
+          out << "int16";
+          break;
+        case t_base_type::TYPE_I32:
+          out << "int32";
+          break;
+        case t_base_type::TYPE_I64:
+          out << "int64";
+          break;
+        default:
+          throw "validator error: unsupported integer type: " + context.type->get_name();
+        }
+        out << "{";
+        for (auto it = values.begin(); it != values.end(); it++) {
+          if (it != values.begin()) {
+            out << ", ";
+          }
+          if ((*it)->is_field_reference()) {
+            out << get_field_reference_name((*it)->get_field_reference());
+          } else if ((*it)->is_validation_function()) {
+            generate_current_type(out, context.type);
+            out << "(";
+            validation_value::validation_function* func = (*it)->get_function();
+            if (func->name == "len") {
+              out << "len(";
+              if (func->arguments[0]->is_field_reference()) {
+                out << get_field_reference_name(func->arguments[0]->get_field_reference());
+              }
+              out << ")";
+            }
+            out << ")";
+          } else {
+            out << (*it)->get_int();
+          }
+        }
+        out << "}" << endl;
+
+        out << indent() << "for _, src := range " << src << " {" << endl;
+        indent_up();
+        out << indent() << "if " << context.tgt << " == src {" << endl;
+      } else {
+        out << indent() << "if " << context.tgt << " == ";
+        if (values[0]->is_field_reference()) {
+          out << get_field_reference_name(values[0]->get_field_reference());
+        } else if (values[0]->is_validation_function()) {
+          generate_current_type(out, context.type);
+          out << "(";
+          validation_value::validation_function* func = values[0]->get_function();
+          if (func->name == "len") {
+            out << "len(";
+            if (func->arguments[0]->is_field_reference()) {
+              out << get_field_reference_name(func->arguments[0]->get_field_reference());
+            }
+            out << ")";
+          }
+          out << ")";
+        } else {
+          out << values[0]->get_int();
+        }
+        out << "{" << endl;
+      }
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"vt.not_in\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol
+          << " not valid, rule vt.not_in check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+      if (values.size() > 1) {
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    }
+  }
+}
+
+void go_validator_generator::generate_string_field_validator(std::ostream& out,
+                                                             const generator_context& context) {
+  std::string target = context.tgt;
+  t_type* type = context.type;
+  if (type->is_typedef()) {
+    type = type->get_true_type();
+  }
+  if (type->is_binary()) {
+    target = GenID("_tgt");
+    out << indent() << target << " := "
+        << "string(" << context.tgt << ")" << endl;
+  }
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+    std::string key = (*it)->get_name();
+
+    if (key == "vt.const") {
+      out << indent() << "if " << target << " != ";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+    } else if (key == "vt.min_size" || key == "vt.max_size") {
+      out << indent() << "if len(" << target << ") ";
+      if (key == "vt.min_size") {
+        out << "<";
+      } else {
+        out << ">";
+      }
+      out << " int(";
+      if (values[0]->is_field_reference()) {
+        out << get_field_reference_name(values[0]->get_field_reference());
+      } else if (values[0]->is_validation_function()) {
+        validation_value::validation_function* func = values[0]->get_function();
+        if (func->name == "len") {
+          out << "len(";
+          if (func->arguments[0]->is_field_reference()) {
+            out << "string(";
+            out << get_field_reference_name(values[0]->get_field_reference());
+            out << ")";
+          }
+          out << ")";
+        }
+      } else {
+        out << values[0]->get_int();
+      }
+      out << ")";
+    } else if (key == "vt.pattern") {
+      out << indent() << "if ok, _ := regexp.MatchString(" << target << ",";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+      out << "); ok ";
+    } else if (key == "vt.prefix") {
+      out << indent() << "if !strings.HasPrefix(" << target << ",";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+      out << ")";
+    } else if (key == "vt.suffix") {
+      out << indent() << "if !strings.HasSuffix(" << target << ",";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+      out << ")";
+    } else if (key == "vt.contains") {
+      out << indent() << "if !strings.Contains(" << target << ",";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+      out << ")";
+    } else if (key == "vt.not_contains") {
+      out << indent() << "if strings.Contains(" << target << ",";
+      if (values[0]->is_field_reference()) {
+        out << "string(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << "\"" << values[0]->get_string() << "\"";
+      }
+      out << ")";
+    }
+    out << "{" << endl;
+    indent_up();
+    out << indent()
+        << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+        << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+        << " check failed\")" << endl;
+    indent_down();
+    out << indent() << "}" << endl;
+  }
+}
+
+void go_validator_generator::generate_set_field_validator(std::ostream& out,
+                                                          const generator_context& context) {
+  return generate_list_field_validator(out, context);
+}
+
+void go_validator_generator::generate_list_field_validator(std::ostream& out,
+                                                           const generator_context& context) {
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    std::string key = (*it)->get_name();
+    if (key == "vt.min_size" || key == "vt.max_size") {
+      out << indent() << "if len(" << context.tgt << ")";
+      if (key == "vt.min_size") {
+        out << " < ";
+      } else {
+        out << " > ";
+      }
+      if (values[0]->is_field_reference()) {
+        out << "int(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << values[0]->get_int();
+      }
+      out << "{" << endl;
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+          << " check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.elem") {
+      out << indent() << "for i := 0; i < len(" << context.tgt << ");i++ {" << endl;
+      indent_up();
+      std::string src = GenID("_elem");
+      out << indent() << src << " := " << context.tgt << "[i]" << endl;
+      t_type* elem_type;
+      if (context.type->is_list()) {
+        elem_type = ((t_list*)context.type)->get_elem_type();
+      } else {
+        elem_type = ((t_set*)context.type)->get_elem_type();
+      }
+      generator_context ctx{context.field_symbol + ".elem",
+                            "",
+                            src,
+                            false,
+                            elem_type,
+                            std::vector<validation_rule*>{(*it)->get_inner()}};
+      generate_field_validator(out, ctx);
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+  }
+}
+
+void go_validator_generator::generate_map_field_validator(std::ostream& out,
+                                                          const generator_context& context) {
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    std::string key = (*it)->get_name();
+    if (key == "vt.min_size" || key == "vt.max_size") {
+      out << indent() << "if len(" << context.tgt << ")";
+      if (key == "vt.min_size") {
+        out << " < ";
+      } else {
+        out << " > ";
+      }
+      if (values[0]->is_field_reference()) {
+        out << "int(";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << ")";
+      } else {
+        out << values[0]->get_int();
+      }
+      out << "{" << endl;
+      indent_up();
+      out << indent()
+          << "return thrift.NewValidationException(thrift.VALIDATION_FAILED, \"" + key + "\", \""
+          << context.field_symbol << "\", \"" << context.field_symbol << " not valid, rule " << key
+          << " check failed\")" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.key") {
+      std::string src = GenID("_key");
+      out << indent() << "for " << src << " := range " << context.tgt << " {" << endl;
+      indent_up();
+      generator_context ctx{context.field_symbol + ".key",
+                            "",
+                            src,
+                            false,
+                            ((t_map*)context.type)->get_key_type(),
+                            std::vector<validation_rule*>{(*it)->get_inner()}};
+      generate_field_validator(out, ctx);
+      indent_down();
+      out << indent() << "}" << endl;
+    } else if (key == "vt.value") {
+      std::string src = GenID("_value");
+      out << indent() << "for _, " << src << " := range " << context.tgt << " {" << endl;
+      indent_up();
+      generator_context ctx{context.field_symbol + ".value",
+                            "",
+                            src,
+                            false,
+                            ((t_map*)context.type)->get_val_type(),
+                            std::vector<validation_rule*>{(*it)->get_inner()}};
+      generate_field_validator(out, ctx);
+      indent_down();
+      out << indent() << "}" << endl;
+    }
+  }
+}
+
+void go_validator_generator::generate_struct_field_validator(std::ostream& out,
+                                                             const generator_context& context) {
+  bool generate_valid = true;
+  validation_rule* last_valid_rule = nullptr;
+  for (auto it = context.rules.begin(); it != context.rules.end(); it++) {
+    const std::vector<validation_value*>& values = (*it)->get_values();
+    if (values.size() == 0) {
+      continue;
+    }
+    std::string key = (*it)->get_name();
+
+    if (key == "vt.skip") {
+      if (values[0]->is_field_reference() || !values[0]->get_bool()) {
+        generate_valid = true;
+      } else if (values[0]->get_bool()) {
+        generate_valid = false;
+      }
+      last_valid_rule = *it;
+    }
+  }
+  if (generate_valid) {
+    if (last_valid_rule == nullptr) {
+      out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
+      indent_up();
+      out << indent() << "return err" << endl;
+      indent_down();
+      out << indent() << "}" << endl;
+    } else {
+      const std::vector<validation_value*>& values = last_valid_rule->get_values();
+      if (!values[0]->get_bool()) {
+        out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
+        indent_up();
+        out << indent() << "return err" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+      } else if (values[0]->is_field_reference()) {
+        out << indent() << "if !";
+        out << get_field_reference_name(values[0]->get_field_reference());
+        out << "{" << endl;
+        indent_up();
+        out << indent() << "if err := " << context.tgt << ".Validate(); err != nil {" << endl;
+        indent_up();
+        out << indent() << "return err" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+        indent_down();
+        out << indent() << "}" << endl;
+      }
+    }
+  }
+}
diff --git a/compiler/cpp/src/thrift/generate/go_validator_generator.h b/compiler/cpp/src/thrift/generate/go_validator_generator.h
new file mode 100644
index 0000000..27ce29b
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/go_validator_generator.h
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 T_GO_VALIDATOR_GENERATOR_H
+#define T_GO_VALIDATOR_GENERATOR_H
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/generate/t_go_generator.h"
+#include "thrift/generate/validator_parser.h"
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <vector>
+
+class go_validator_generator {
+public:
+  go_validator_generator(t_go_generator* gg) : go_generator(gg){};
+  void generate_struct_validator(std::ostream& out, t_struct* tstruct);
+
+  struct generator_context {
+    std::string field_symbol;
+    std::string src;
+    std::string tgt;
+    bool opt;
+    t_type* type;
+    std::vector<validation_rule*> rules;
+  };
+
+private:
+  void generate_field_validator(std::ostream& out, const generator_context& context);
+  void generate_enum_field_validator(std::ostream& out, const generator_context& context);
+  void generate_bool_field_validator(std::ostream& out, const generator_context& context);
+  void generate_integer_field_validator(std::ostream& out, const generator_context& context);
+  void generate_double_field_validator(std::ostream& out, const generator_context& context);
+  void generate_string_field_validator(std::ostream& out, const generator_context& context);
+  void generate_list_field_validator(std::ostream& out, const generator_context& context);
+  void generate_set_field_validator(std::ostream& out, const generator_context& context);
+  void generate_map_field_validator(std::ostream& out, const generator_context& context);
+  void generate_struct_field_validator(std::ostream& out, const generator_context& context);
+
+  void indent_up() { go_generator->indent_up(); }
+  void indent_down() { go_generator->indent_down(); }
+  std::string indent() { return go_generator->indent(); }
+
+  //std::string get_field_name(t_field* field);  -- no impl?
+  std::string get_field_reference_name(t_field* field);
+
+  std::string GenID(std::string id) { return id + std::to_string(tmp_[id]++); };
+
+  t_go_generator* go_generator;
+
+  std::map<std::string, int> tmp_;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
index 8cb82c1..4ce9c5f 100644
--- a/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
@@ -723,6 +723,8 @@
       return "T_I64";
     case t_base_type::TYPE_DOUBLE:
       return "T_DOUBLE";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "T_I32";
diff --git a/compiler/cpp/src/thrift/generate/t_cl_generator.cc b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
new file mode 100644
index 0000000..06b6b65
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_cl_generator.cc
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 2008- Patrick Collison <patrick@collison.ie>
+ * Copyright (c) 2006- Facebook
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 <string>
+#include <fstream>
+#include <iostream>
+#include <vector>
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sstream>
+#include <string>
+#include <algorithm>
+
+#include "thrift/platform.h"
+#include "t_oop_generator.h"
+
+using namespace std;
+
+
+/**
+ * Common Lisp code generator.
+ *
+ * @author Patrick Collison <patrick@collison.ie>
+ */
+class t_cl_generator : public t_oop_generator {
+ public:
+  t_cl_generator(
+      t_program* program,
+      const std::map<std::string, std::string>& parsed_options,
+      const std::string& option_string)
+    : t_oop_generator(program)
+  {
+    no_asd = false;
+    system_prefix = "thrift-gen-";
+
+    std::map<std::string, std::string>::const_iterator iter;
+
+    for(iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if(iter->first.compare("no_asd") == 0) {
+        no_asd = true;
+      } else if (iter->first.compare("sys_pref") == 0) {
+	system_prefix = iter->second;
+      } else {
+        throw "unknown option cl:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-cl";
+    copy_options_ = option_string;
+  }
+
+  void init_generator() override;
+  void close_generator() override;
+
+  void generate_typedef     (t_typedef*  ttypedef) override;
+  void generate_enum        (t_enum*     tenum) override;
+  void generate_const       (t_const*    tconst) override;
+  void generate_struct      (t_struct*   tstruct) override;
+  void generate_xception    (t_struct*   txception) override;
+  void generate_service     (t_service*  tservice) override;
+  void generate_cl_struct (std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_cl_struct_internal (std::ostream& out, t_struct* tstruct, bool is_exception);
+  void generate_exception_sig(std::ostream& out, t_function* f);
+  std::string render_const_value(t_type* type, t_const_value* value);
+
+  std::string cl_autogen_comment();
+  void asdf_def(std::ostream &out);
+  void package_def(std::ostream &out);
+  void package_in(std::ostream &out);
+  std::string generated_package();
+  std::string prefix(std::string name);
+  std::string package_of(t_program* program);
+  std::string package();
+  std::string render_includes();
+
+  std::string type_name(t_type* ttype);
+  std::string typespec (t_type *t);
+  std::string function_signature(t_function* tfunction);
+  std::string argument_list(t_struct* tstruct);
+
+  std::string cl_docstring(std::string raw);
+
+ private:
+
+  int temporary_var;
+  /**
+   * Isolate the variable definitions, as they can require structure definitions
+   */
+  ofstream_with_content_based_conditional_update f_asd_;
+  ofstream_with_content_based_conditional_update f_types_;
+  ofstream_with_content_based_conditional_update f_vars_;
+
+  std::string copy_options_;
+
+  bool no_asd;
+  std::string system_prefix;
+};
+
+
+void t_cl_generator::init_generator() {
+  MKDIR(get_out_dir().c_str());
+  string program_dir = get_out_dir() + "/" + program_name_;
+  MKDIR(program_dir.c_str());
+
+  temporary_var = 0;
+
+  string f_types_name = program_dir + "/" + program_name_ + "-types.lisp";
+  string f_vars_name = program_dir + "/" + program_name_ + "-vars.lisp";
+
+  f_types_.open(f_types_name);
+  f_types_ << cl_autogen_comment() << endl;
+  f_vars_.open(f_vars_name);
+  f_vars_ << cl_autogen_comment() << endl;
+
+  package_def(f_types_);
+  package_in(f_types_);
+  package_in(f_vars_);
+
+  if (!no_asd) {
+    string f_asd_name = program_dir + "/" + system_prefix + program_name_ + ".asd";
+    f_asd_.open(f_asd_name);
+    f_asd_ << cl_autogen_comment() << endl;
+    asdf_def(f_asd_);
+  }
+}
+
+/**
+ * Renders all the imports necessary for including another Thrift program
+ */
+string t_cl_generator::render_includes() {
+  const vector<t_program*>& includes = program_->get_includes();
+  string result = "";
+  result += ":depends-on (:thrift";
+  for (auto include : includes) {
+    result += " :" + system_prefix + underscore(include->get_name());
+  }
+  result += ")\n";
+  return result;
+}
+
+string t_cl_generator::package_of(t_program* program) {
+  string prefix = program->get_namespace("cl");
+  return prefix.empty() ? "thrift-generated" : prefix;
+}
+
+string t_cl_generator::package() {
+  return package_of(program_);
+}
+
+string t_cl_generator::prefix(string symbol) {
+  return "\"" + symbol + "\"";
+}
+
+string t_cl_generator::cl_autogen_comment() {
+  return
+    std::string(";;; ") + "Autogenerated by Thrift\n" +
+    ";;; DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING\n" +
+    ";;; options string: " + copy_options_ + "\n";
+}
+
+string t_cl_generator::cl_docstring(string raw) {
+  replace(raw.begin(), raw.end(), '"', '\'');
+  return raw;
+}
+
+
+void t_cl_generator::close_generator() {
+  f_asd_.close();
+  f_types_.close();
+  f_vars_.close();
+}
+
+string t_cl_generator::generated_package() {
+  return program_->get_namespace("cpp");
+}
+
+void t_cl_generator::asdf_def(std::ostream &out) {
+  out << "(asdf:defsystem #:" << system_prefix << program_name_ << endl;
+  indent_up();
+  out << indent() << render_includes()
+      << indent() << ":serial t" << endl
+      << indent() << ":components ("
+      << "(:file \"" << program_name_ << "-types\") "
+      << "(:file \"" << program_name_ << "-vars\")))" << endl;
+  indent_down();
+}
+
+/***
+ * Generate a package definition. Add use references equivalent to the idl file's include statements.
+ */
+void t_cl_generator::package_def(std::ostream &out) {
+  const vector<t_program*>& includes = program_->get_includes();
+
+  out << "(thrift:def-package :" << package();
+  if ( includes.size() > 0 ) {
+    out << " :use (";
+    for (auto include : includes) {
+      out << " :" << include->get_name();
+    }
+    out << ")";
+  }
+  out << ")" << endl << endl;
+}
+
+void t_cl_generator::package_in(std::ostream &out) {
+  out << "(cl:in-package :" << package() << ")" << endl << endl;
+}
+
+/**
+ * Generates a typedef. This is not done in Common Lisp, types are all implicit.
+ *
+ * @param ttypedef The type definition
+ */
+void t_cl_generator::generate_typedef(t_typedef* ttypedef) {
+  (void)ttypedef;
+}
+
+void t_cl_generator::generate_enum(t_enum* tenum) {
+  f_types_ << "(thrift:def-enum " << prefix(tenum->get_name()) << endl;
+
+  vector<t_enum_value*> constants = tenum->get_constants();
+  vector<t_enum_value*>::iterator c_iter;
+  int value = -1;
+
+  indent_up();
+  f_types_ << indent() << "(";
+  for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
+    value = (*c_iter)->get_value();
+
+    if(c_iter != constants.begin()) f_types_ << endl << indent() << " ";
+
+    f_types_ << "(\"" << (*c_iter)->get_name() << "\" . " << value << ")";
+  }
+  indent_down();
+  f_types_ << "))" << endl << endl;
+}
+
+/**
+ * Generate a constant value
+ */
+void t_cl_generator::generate_const(t_const* tconst) {
+  t_type* type = tconst->get_type();
+  string name = tconst->get_name();
+  t_const_value* value = tconst->get_value();
+
+  f_vars_ << "(thrift:def-constant " << prefix(name) << " " << render_const_value(type, value) << ")"
+          << endl << endl;
+}
+
+/**
+ * Prints the value of a constant with the given type. Note that type checking
+ * is NOT performed in this function as it is always run beforehand using the
+ * validate_types method in main.cc
+ */
+string t_cl_generator::render_const_value(t_type* type, t_const_value* value) {
+  type = get_true_type(type);
+  std::ostringstream out;
+  if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_STRING:
+      out << "\"" << value->get_string() << "\"";
+      break;
+    case t_base_type::TYPE_BOOL:
+      out << (value->get_integer() > 0 ? "t" : "nil");
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      out << value->get_integer();
+      break;
+    case t_base_type::TYPE_DOUBLE:
+      if (value->get_type() == t_const_value::CV_INTEGER) {
+        out << value->get_integer();
+      } else {
+        out << value->get_double();
+      }
+      break;
+    default:
+      throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
+    }
+  } else if (type->is_enum()) {
+    indent(out) << value->get_integer();
+  } else if (type->is_struct() || type->is_xception()) {
+    out << (type->is_struct() ? "(make-instance '" : "(make-exception '") <<
+           lowercase(type->get_name()) << " " << endl;
+    indent_up();
+
+    const vector<t_field*>& fields = ((t_struct*)type)->get_members();
+    vector<t_field*>::const_iterator f_iter;
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      t_type* field_type = nullptr;
+      for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+        if ((*f_iter)->get_name() == v_iter->first->get_string()) {
+          field_type = (*f_iter)->get_type();
+        }
+      }
+      if (field_type == nullptr) {
+        throw "type error: " + type->get_name() + " has no field " + v_iter->first->get_string();
+      }
+
+      out << indent() << ":" << v_iter->first->get_string() << " " <<
+        render_const_value(field_type, v_iter->second) << endl;
+    }
+    out << indent() << ")";
+
+    indent_down();
+  } else if (type->is_map()) {
+    // emit an hash form with both keys and values to be evaluated
+    t_type* ktype = ((t_map*)type)->get_key_type();
+    t_type* vtype = ((t_map*)type)->get_val_type();
+    out << "(thrift:map ";
+    indent_up();
+    const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
+    map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << endl << indent()
+          << "(cl:cons " << render_const_value(ktype, v_iter->first) << " "
+          << render_const_value(vtype, v_iter->second) << ")";
+    }
+    indent_down();
+    out << indent() << ")";
+  } else if (type->is_list() || type->is_set()) {
+    t_type* etype;
+    if (type->is_list()) {
+      etype = ((t_list*)type)->get_elem_type();
+    } else {
+      etype = ((t_set*)type)->get_elem_type();
+    }
+    if (type->is_set()) {
+      out << "(thrift:set" << endl;
+    } else {
+      out << "(thrift:list" << endl;
+    }
+    indent_up();
+    indent_up();
+    const vector<t_const_value*>& val = value->get_list();
+    vector<t_const_value*>::const_iterator v_iter;
+    for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
+      out << indent() << render_const_value(etype, *v_iter) << endl;
+    }
+    out << indent() << ")";
+    indent_down();
+    indent_down();
+  } else {
+    throw "CANNOT GENERATE CONSTANT FOR TYPE: " + type->get_name();
+  }
+  return out.str();
+}
+
+void t_cl_generator::generate_struct(t_struct* tstruct) {
+  generate_cl_struct(f_types_, tstruct, false);
+}
+
+void t_cl_generator::generate_xception(t_struct* txception) {
+  generate_cl_struct(f_types_, txception, true);
+}
+
+void t_cl_generator::generate_cl_struct_internal(std::ostream& out, t_struct* tstruct, bool is_exception) {
+  (void)is_exception;
+  const vector<t_field*>& members = tstruct->get_members();
+  vector<t_field*>::const_iterator m_iter;
+
+  out << "(";
+
+  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
+    t_const_value* value = (*m_iter)->get_value();
+    t_type* type = (*m_iter)->get_type();
+
+    if (m_iter != members.begin()) {
+      out << endl << indent() << " ";
+    }
+    out << "(" << prefix((*m_iter)->get_name()) << " " <<
+        ( (nullptr != value) ? render_const_value(type, value) : "nil" ) <<
+        " :id " << (*m_iter)->get_key();
+    if ( type->is_base_type() && "string" == typespec(type) )
+      if ( ((t_base_type*)type)->is_binary() )
+        out << " :type binary";
+      else
+        out << " :type string";
+    else
+      out << " :type " << typespec(type);
+    if ( (*m_iter)->get_req() == t_field::T_OPTIONAL ) {
+      out << " :optional t";
+    }
+    if ( (*m_iter)->has_doc()) {
+      out << " :documentation \"" << cl_docstring((*m_iter)->get_doc()) << "\"";
+    }
+    out <<")";
+  }
+
+  out << ")";
+}
+
+void t_cl_generator::generate_cl_struct(std::ostream& out, t_struct* tstruct, bool is_exception = false) {
+  std::string name = type_name(tstruct);
+  out << (is_exception ? "(thrift:def-exception " : "(thrift:def-struct ") <<
+      prefix(name) << endl;
+  indent_up();
+  if ( tstruct->has_doc() ) {
+    out << indent() ;
+    out << "\"" << cl_docstring(tstruct->get_doc()) << "\"" << endl;
+  }
+  out << indent() ;
+  generate_cl_struct_internal(out, tstruct, is_exception);
+  indent_down();
+  out << ")" << endl << endl;
+}
+
+void t_cl_generator::generate_exception_sig(std::ostream& out, t_function* f) {
+  generate_cl_struct_internal(out, f->get_xceptions(), true);
+}
+
+void t_cl_generator::generate_service(t_service* tservice) {
+  string extends_client;
+  vector<t_function*> functions = tservice->get_functions();
+  vector<t_function*>::iterator f_iter;
+
+  if (tservice->get_extends() != nullptr) {
+    extends_client = type_name(tservice->get_extends());
+  }
+
+  extends_client = extends_client.empty() ? "nil" : prefix(extends_client);
+
+  f_types_ << "(thrift:def-service " << prefix(service_name_) << " "
+           << extends_client;
+
+  indent_up();
+
+  if ( tservice->has_doc()) {
+      f_types_ << endl << indent()
+               << "(:documentation \"" << cl_docstring(tservice->get_doc()) << "\")";
+    }
+
+  for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
+    t_function* function = *f_iter;
+    string fname = function->get_name();
+    string signature = function_signature(function);
+    t_struct* exceptions = function->get_xceptions();
+    const vector<t_field*>& xmembers = exceptions->get_members();
+
+    f_types_ << endl << indent() << "(:method " << prefix(fname);
+    f_types_ << " (" << signature << " "  << typespec((*f_iter)->get_returntype()) << ")";
+    if (xmembers.size() > 0) {
+      f_types_ << endl << indent() << " :exceptions " ;
+      generate_exception_sig(f_types_, function);
+    }
+    if ( (*f_iter)->is_oneway() ) {
+      f_types_ << endl << indent() << " :oneway t";
+    }
+    if ( (*f_iter)->has_doc() ) {
+      f_types_ << endl << indent() << " :documentation \""
+               << cl_docstring((*f_iter)->get_doc()) << "\"";
+  }
+    f_types_ << ")";
+  }
+
+  f_types_ << ")" << endl << endl;
+
+  indent_down();
+}
+
+string t_cl_generator::typespec(t_type *t) {
+  t = get_true_type(t);
+
+  if (t -> is_binary()){
+    return "binary";
+  } else if (t->is_base_type()) {
+    return type_name(t);
+  } else if (t->is_map()) {
+    t_map *m = (t_map*) t;
+    return "(thrift:map " + typespec(m->get_key_type()) + " " +
+      typespec(m->get_val_type()) + ")";
+  } else if (t->is_struct() || t->is_xception()) {
+    return "(struct " + prefix(type_name(t)) + ")";
+  } else if (t->is_list()) {
+    return "(thrift:list " + typespec(((t_list*) t)->get_elem_type()) + ")";
+  } else if (t->is_set()) {
+    return "(thrift:set " + typespec(((t_set*) t)->get_elem_type()) + ")";
+  } else if (t->is_enum()) {
+    return "(enum \"" + ((t_enum*) t)->get_name() + "\")";
+  } else {
+    throw "Sorry, I don't know how to generate this: " + type_name(t);
+  }
+}
+
+string t_cl_generator::function_signature(t_function* tfunction) {
+  return argument_list(tfunction->get_arglist());
+}
+
+string t_cl_generator::argument_list(t_struct* tstruct) {
+  stringstream res;
+  res << "(";
+
+  const vector<t_field*>& fields = tstruct->get_members();
+  vector<t_field*>::const_iterator f_iter;
+  bool first = true;
+  for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
+    if (first) {
+      first = false;
+    } else {
+      res << " ";
+    }
+    res << "(" + prefix((*f_iter)->get_name()) << " " <<
+      typespec((*f_iter)->get_type()) << " " <<
+      (*f_iter)->get_key() <<  ")";
+
+
+  }
+  res << ")";
+  return res.str();
+}
+
+string t_cl_generator::type_name(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+
+  if (program != nullptr && program != program_)
+    prefix = package_of(program) == package() ? "" : package_of(program) + ":";
+
+  string name = ttype->get_name();
+
+  if (ttype->is_struct() || ttype->is_xception())
+    name = lowercase(ttype->get_name());
+
+  return prefix + name;
+}
+
+THRIFT_REGISTER_GENERATOR(
+    cl,
+    "Common Lisp",
+    "    no_asd:          Do not define ASDF systems for each generated Thrift program.\n"
+    "    sys_pref=        The prefix to give ASDF system names. Default: thrift-gen-\n")
diff --git a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
index d9898b7..dd444bc 100644
--- a/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_cpp_generator.cc
@@ -689,7 +689,7 @@
       out << tenum->get_name() << "::type&";
     }
     out << " val) " ;
-	scope_up(out);
+    scope_up(out);
 
     out << indent() << "std::map<int, const char*>::const_iterator it = _"
              << tenum->get_name() << "_VALUES_TO_NAMES.find(val);" << endl;
@@ -1221,7 +1221,7 @@
 
   // Declare all fields
   for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-	generate_java_doc(out, *m_iter);
+    generate_java_doc(out, *m_iter);
     indent(out) << declare_field(*m_iter,
                                  false,
                                  (pointers && !(*m_iter)->get_type()->is_xception()),
@@ -2475,11 +2475,11 @@
   indent_up();
   if (style != "Cob") {
     f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr
-		<< " prot";
-	if (style == "Concurrent") {
-		f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
-	}
-	f_header_ << ") ";
+        << " prot";
+    if (style == "Concurrent") {
+        f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
+    }
+    f_header_ << ") ";
 
     if (extends.empty()) {
       if (style == "Concurrent") {
@@ -2498,12 +2498,12 @@
     }
 
     f_header_ << indent() << service_name_ << style << "Client" << short_suffix << "(" << prot_ptr
-		<< " iprot, " << prot_ptr << " oprot";
-	if (style == "Concurrent") {
-		f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
-	}
-	f_header_ << ") ";
-	
+        << " iprot, " << prot_ptr << " oprot";
+    if (style == "Concurrent") {
+        f_header_ << ", std::shared_ptr< ::apache::thrift::async::TConcurrentClientSyncInfo> sync";
+    }
+    f_header_ << ") ";
+    
     if (extends.empty()) {
       if (style == "Concurrent") {
         f_header_ << ": sync_(sync)" << endl;
@@ -4398,9 +4398,9 @@
 string t_cpp_generator::type_name(t_type* ttype, bool in_typedef, bool arg) {
   if (ttype->is_base_type()) {
     string bname = base_type_name(((t_base_type*)ttype)->get_base());
-    std::map<string, string>::iterator it = ttype->annotations_.find("cpp.type");
-    if (it != ttype->annotations_.end()) {
-      bname = it->second;
+    std::map<string, std::vector<string>>::iterator it = ttype->annotations_.find("cpp.type");
+    if (it != ttype->annotations_.end() && !it->second.empty()) {
+      bname = it->second.back();
     }
 
     if (!arg) {
@@ -4660,6 +4660,8 @@
       return "::apache::thrift::protocol::T_I64";
     case t_base_type::TYPE_DOUBLE:
       return "::apache::thrift::protocol::T_DOUBLE";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "::apache::thrift::protocol::T_I32";
diff --git a/compiler/cpp/src/thrift/generate/t_d_generator.cc b/compiler/cpp/src/thrift/generate/t_d_generator.cc
index afae5b5..f9e4856 100644
--- a/compiler/cpp/src/thrift/generate/t_d_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_d_generator.cc
@@ -74,9 +74,9 @@
 
   // D reserved words are suffixed with an underscore
   static string suffix_if_reserved(const string& name) {
-	const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name);
-	string ret = isIn ? name + "_" : name;
-	return ret;
+    const bool isIn = std::binary_search(std::begin(d_reserved_words), std::end(d_reserved_words), name);
+    string ret = isIn ? name + "_" : name;
+    return ret;
   }
 
   void init_generator() override {
@@ -403,8 +403,8 @@
       out << indent() << "// Your implementation goes here." << endl << indent() << "writeln(\""
           << suffix_if_reserved((*f_iter)->get_name()) << " called\");" << endl;
 
-	  t_type* rt = (*f_iter)->get_returntype();
-	  if (!rt->is_void()) {
+      t_type* rt = (*f_iter)->get_returntype();
+      if (!rt->is_void()) {
         indent(out) << "return typeof(return).init;" << endl;
       }
 
diff --git a/compiler/cpp/src/thrift/generate/t_dart_generator.cc b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
index 65d0f53..61cd981 100644
--- a/compiler/cpp/src/thrift/generate/t_dart_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_dart_generator.cc
@@ -2216,6 +2216,8 @@
       case t_base_type::TYPE_DOUBLE:
         result += " = 0.0";
         break;
+      default:
+        throw "compiler error: unhandled type";
       }
 
     } else if (ttype->is_enum()) {
@@ -2297,6 +2299,8 @@
       return "TType.I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType.DOUBLE";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "TType.I32";
@@ -2351,6 +2355,8 @@
   case t_base_type::TYPE_STRING:
     result = "";
     break;
+  default:
+    throw "compiler error: unhandled type";
   }
 
   return result;
diff --git a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
index 8383cea..625179f 100644
--- a/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_delphi_generator.cc
@@ -73,6 +73,7 @@
     events_ = false;
     xmldoc_ = false;
     async_ = false;
+    com_types_ = false;
     for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
       if( iter->first.compare("ansistr_binary") == 0) {
         ansistr_binary_ = true;
@@ -86,11 +87,17 @@
         xmldoc_ = true;
       } else if( iter->first.compare("async") == 0) {
         async_ = true;
+      } else if( iter->first.compare("com_types") == 0) {
+        com_types_ = true;
       } else {
         throw "unknown option delphi:" + iter->first;
       }
     }
 
+    if(com_types_ && ansistr_binary_) {
+      throw "com_types and ansistr_binary are mutually exclusive";
+    }
+
     out_dir_base_ = "gen-delphi";
     escape_.clear();
     escape_['\''] = "''";
@@ -417,6 +424,7 @@
   bool events_;
   bool xmldoc_;
   bool async_;
+  bool com_types_;
   void indent_up_impl() { ++indent_impl_; };
   void indent_down_impl() { --indent_impl_; };
   std::string indent_impl() {
@@ -804,6 +812,9 @@
   generate_delphi_doc(f_all, program_);
   f_all << "unit " << unitname << ";" << endl << endl;
   f_all << "{$WARN SYMBOL_DEPRECATED OFF}" << endl << endl;
+  if(com_types_) {
+    f_all << "{$MINENUMSIZE 4}" << endl << endl;
+  }
   f_all << "interface" << endl << endl;
   f_all << "uses" << endl;
 
@@ -831,18 +842,13 @@
 
   f_all << "const" << endl;
   indent_up();
-  indent(f_all) << "c" << tmp_unit
-                << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";"
-                << endl;
-  indent(f_all) << "c" << tmp_unit
-                << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";"
-                << endl;
-  indent(f_all) << "c" << tmp_unit
-                << "_Option_ConstPrefix    = " << (constprefix_ ? "True" : "False") << ";" << endl;
-  indent(f_all) << "c" << tmp_unit << "_Option_Events         = " << (events_ ? "True" : "False")
-                << ";" << endl;
-  indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc         = " << (xmldoc_ ? "True" : "False")
-                << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_AnsiStr_Binary = " << (ansistr_binary_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_Register_Types = " << (register_types_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_ConstPrefix    = " << (constprefix_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_Events         = " << (events_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_XmlDoc         = " << (xmldoc_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_Async          = " << (async_ ? "True" : "False") << ";" << endl;
+  indent(f_all) << "c" << tmp_unit << "_Option_COM_types      = " << (com_types_ ? "True" : "False") << ";" << endl;
   indent_down();
 
   f_all << endl;
@@ -1018,6 +1024,7 @@
   // known base types
   types_known[type_name(g_type_string)] = 1;
   types_known[type_name(g_type_binary)] = 1;
+  types_known[type_name(g_type_uuid)] = 1;
   types_known[type_name(g_type_bool)] = 1;
   types_known[type_name(g_type_i8)] = 1;
   types_known[type_name(g_type_i16)] = 1;
@@ -1392,6 +1399,9 @@
     case t_base_type::TYPE_STRING:
       render << "'" << get_escaped_string(value) << "'";
       break;
+    case t_base_type::TYPE_UUID:
+      render << "['{" << value->get_uuid() << "}']";
+      break;
     case t_base_type::TYPE_BOOL:
       render << ((value->get_integer() > 0) ? "True" : "False");
       break;
@@ -2697,12 +2707,15 @@
           if (ansistr_binary_) {
             out << "ReadAnsiString();";
           } else {
-            out << "ReadBinary();";
+            out << (com_types_ ? "ReadBinaryCOM();" :  "ReadBinary();");
           }
         } else {
           out << "ReadString();";
         }
         break;
+      case t_base_type::TYPE_UUID:
+        out << "ReadUuid();";
+        break;
       case t_base_type::TYPE_BOOL:
         out << "ReadBool();";
         break;
@@ -2904,6 +2917,9 @@
         }
         out << name << ");";
         break;
+      case t_base_type::TYPE_UUID:
+        out << "WriteUuid(" << name << ");";
+        break;
       case t_base_type::TYPE_BOOL:
         out << "WriteBool(" << name << ");";
         break;
@@ -3138,9 +3154,9 @@
   } else if (ttype->is_set()) {
     t_set* tset = (t_set*)ttype;
     if (b_cls) {
-      typ_nm = "THashSetImpl";
+      typ_nm = "TThriftHashSetImpl";
     } else {
-      typ_nm = "IHashSet";
+      typ_nm = "IThriftHashSet";
     }
     return typ_nm + "<" + type_name(tset->get_elem_type()) + ">";
   } else if (ttype->is_list()) {
@@ -3189,6 +3205,7 @@
 
     // these should be const'ed for optimal performamce
     case t_base_type::TYPE_STRING: // refcounted pointer
+    case t_base_type::TYPE_UUID:   // refcounted pointer
     case t_base_type::TYPE_I64:    // larger than 32 bit
     case t_base_type::TYPE_DOUBLE: // larger than 32 bit
       return "const ";
@@ -3236,11 +3253,13 @@
       if (ansistr_binary_) {
         return "System.AnsiString";
       } else {
-        return "SysUtils.TBytes";
+        return com_types_ ? "IThriftBytes" : "SysUtils.TBytes";
       }
     } else {
-      return "System.string";
+      return com_types_ ? "System.WideString" : "System.string";
     }
+  case t_base_type::TYPE_UUID:
+    return "System.TGuid";
   case t_base_type::TYPE_BOOL:
     return "System.Boolean";
   case t_base_type::TYPE_I8:
@@ -3310,11 +3329,11 @@
   // deprecated method? only at intf decl!
   if( full_cls == "") {
     auto iter = tfunction->annotations_.find("deprecated");
-    if( tfunction->annotations_.end() != iter) {
+    if( tfunction->annotations_.end() != iter && !iter->second.empty()) {
       signature += " deprecated";
       // empty annotation values end up with "1" somewhere, ignore these as well
-      if ((iter->second.length() > 0) && (iter->second != "1")) {
-        signature += " " + make_pascal_string_literal(iter->second);
+      if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
+        signature += " " + make_pascal_string_literal(iter->second.back());
       }
       signature += ";";
     }
@@ -3407,6 +3426,8 @@
       throw "NO T_VOID CONSTRUCT";
     case t_base_type::TYPE_STRING:
       return "TType.String_";
+    case t_base_type::TYPE_UUID:
+      return "TType.Uuid";
     case t_base_type::TYPE_BOOL:
       return "TType.Bool_";
     case t_base_type::TYPE_I8:
@@ -3455,6 +3476,8 @@
       } else {
         return "''";
       }
+    case t_base_type::TYPE_UUID:
+      return "System.TGuid.Empty";
     case t_base_type::TYPE_BOOL:
       return "False";
     case t_base_type::TYPE_I8:
@@ -4059,6 +4082,9 @@
                        << type_name(ttype, false, true, false, false) 
                        << ">.ToString( System.Ord( Self." 
                        << prop_name((*f_iter), is_exception) << ")));" << endl;
+    } else if (ttype->is_uuid()) {
+      indent_impl(out) << tmp_sb << ".Append( GUIDToString(Self." << prop_name((*f_iter), is_exception) << "));"
+                       << endl;
     } else {
       indent_impl(out) << tmp_sb << ".Append( Self." << prop_name((*f_iter), is_exception) << ");"
                        << endl;
@@ -4114,4 +4140,5 @@
     "    constprefix:     Name TConstants classes after IDL to reduce ambiguities\n"
     "    events:          Enable and use processing events in the generated code.\n"
     "    xmldoc:          Enable XMLDoc comments for Help Insight etc.\n"
-    "    async:           Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n")
+    "    async:           Generate IAsync interface to use Parallel Programming Library (XE7+ only).\n"
+    "    com_types:       Use COM-compatible data types (e.g. WideString).\n")
diff --git a/compiler/cpp/src/thrift/generate/t_erl_generator.cc b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
index c06ea43..1f4fd50 100644
--- a/compiler/cpp/src/thrift/generate/t_erl_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_erl_generator.cc
@@ -1168,6 +1168,8 @@
       return "?tType_I64";
     case t_base_type::TYPE_DOUBLE:
       return "?tType_DOUBLE";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "?tType_I32";
@@ -1211,6 +1213,8 @@
       return "i64";
     case t_base_type::TYPE_DOUBLE:
       return "double";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "i32";
diff --git a/compiler/cpp/src/thrift/generate/t_generator.cc b/compiler/cpp/src/thrift/generate/t_generator.cc
index a2bc9d6..f26690b 100644
--- a/compiler/cpp/src/thrift/generate/t_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_generator.cc
@@ -237,7 +237,7 @@
   if ((language == "csharp") || (language == "netcore")) {
     failure("The '%s' target is no longer available. Use 'netstd' instead.", language.c_str());
   }
-  
+
   if (iter == the_map.end()) {
     return nullptr;
   }
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.cc b/compiler/cpp/src/thrift/generate/t_go_generator.cc
index f4b94a4..e0ca489 100644
--- a/compiler/cpp/src/thrift/generate/t_go_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.cc
@@ -41,6 +41,8 @@
 #include "thrift/platform.h"
 #include "thrift/version.h"
 #include "thrift/generate/t_generator.h"
+#include "thrift/generate/t_go_generator.h"
+#include "thrift/generate/go_validator_generator.h"
 
 using std::map;
 using std::ostream;
@@ -49,8 +51,6 @@
 using std::stringstream;
 using std::vector;
 
-static const string endl = "\n"; // avoid ostream << std::endl flushes
-
 /**
  * A helper for automatically formatting the emitted Go code from the Thrift
  * IDL per the Go style guide.
@@ -62,277 +62,6 @@
  */
 bool format_go_output(const string& file_path);
 
-const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
-static std::string package_flag;
-
-/**
- * Go code generator.
- */
-class t_go_generator : public t_generator {
-public:
-  t_go_generator(t_program* program,
-                 const std::map<std::string, std::string>& parsed_options,
-                 const std::string& option_string)
-    : t_generator(program) {
-    (void)option_string;
-    std::map<std::string, std::string>::const_iterator iter;
-
-
-    gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
-    gen_package_prefix_ = "";
-    package_flag = "";
-    read_write_private_ = false;
-    ignore_initialisms_ = false;
-    skip_remote_ = false;
-    for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
-      if( iter->first.compare("package_prefix") == 0) {
-        gen_package_prefix_ = (iter->second);
-      } else if( iter->first.compare("thrift_import") == 0) {
-        gen_thrift_import_ = (iter->second);
-      } else if( iter->first.compare("package") == 0) {
-        package_flag = (iter->second);
-      } else if( iter->first.compare("read_write_private") == 0) {
-        read_write_private_ = true;
-      } else if( iter->first.compare("ignore_initialisms") == 0) {
-        ignore_initialisms_ =  true;
-      } else if( iter->first.compare("skip_remote") == 0) {
-        skip_remote_ =  true;
-      } else {
-        throw "unknown option go:" + iter->first;
-      }
-    }
-
-    out_dir_base_ = "gen-go";
-  }
-
-  /**
-   * Init and close methods
-   */
-
-  void init_generator() override;
-  void close_generator() override;
-
-  /**
-   * Program-level generation functions
-   */
-
-  void generate_typedef(t_typedef* ttypedef) override;
-  void generate_enum(t_enum* tenum) override;
-  void generate_const(t_const* tconst) override;
-  void generate_struct(t_struct* tstruct) override;
-  void generate_xception(t_struct* txception) override;
-  void generate_service(t_service* tservice) override;
-
-  std::string render_const_value(t_type* type, t_const_value* value, const string& name, bool opt = false);
-
-  /**
-   * Struct generation code
-   */
-
-  void generate_go_struct(t_struct* tstruct, bool is_exception);
-  void generate_go_struct_definition(std::ostream& out,
-                                     t_struct* tstruct,
-                                     bool is_xception = false,
-                                     bool is_result = false,
-                                     bool is_args = false);
-  void generate_go_struct_initializer(std::ostream& out,
-                                      t_struct* tstruct,
-                                      bool is_args_or_result = false);
-  void generate_isset_helpers(std::ostream& out,
-                              t_struct* tstruct,
-                              const string& tstruct_name,
-                              bool is_result = false);
-  void generate_countsetfields_helper(std::ostream& out,
-                                      t_struct* tstruct,
-                                      const string& tstruct_name,
-                                      bool is_result = false);
-  void generate_go_struct_reader(std::ostream& out,
-                                 t_struct* tstruct,
-                                 const string& tstruct_name,
-                                 bool is_result = false);
-  void generate_go_struct_writer(std::ostream& out,
-                                 t_struct* tstruct,
-                                 const string& tstruct_name,
-                                 bool is_result = false,
-                                 bool uses_countsetfields = false);
-  void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name);
-  void generate_go_function_helpers(t_function* tfunction);
-  void get_publicized_name_and_def_value(t_field* tfield,
-                                         string* OUT_pub_name,
-                                         t_const_value** OUT_def_value) const;
-
-  /**
-   * Service-level generation functions
-   */
-
-  void generate_service_helpers(t_service* tservice);
-  void generate_service_interface(t_service* tservice);
-  void generate_service_client(t_service* tservice);
-  void generate_service_remote(t_service* tservice);
-  void generate_service_server(t_service* tservice);
-  void generate_process_function(t_service* tservice, t_function* tfunction);
-
-  /**
-   * Serialization constructs
-   */
-
-  void generate_deserialize_field(std::ostream& out,
-                                  t_field* tfield,
-                                  bool declare,
-                                  std::string prefix = "",
-                                  bool inclass = false,
-                                  bool coerceData = false,
-                                  bool inkey = false,
-                                  bool in_container = false);
-
-  void generate_deserialize_struct(std::ostream& out,
-                                   t_struct* tstruct,
-                                   bool is_pointer_field,
-                                   bool declare,
-                                   std::string prefix = "");
-
-  void generate_deserialize_container(std::ostream& out,
-                                      t_type* ttype,
-                                      bool pointer_field,
-                                      bool declare,
-                                      std::string prefix = "");
-
-  void generate_deserialize_set_element(std::ostream& out,
-                                        t_set* tset,
-                                        bool declare,
-                                        std::string prefix = "");
-
-  void generate_deserialize_map_element(std::ostream& out,
-                                        t_map* tmap,
-                                        bool declare,
-                                        std::string prefix = "");
-
-  void generate_deserialize_list_element(std::ostream& out,
-                                         t_list* tlist,
-                                         bool declare,
-                                         std::string prefix = "");
-
-  void generate_serialize_field(std::ostream& out,
-                                t_field* tfield,
-                                std::string prefix = "",
-                                bool inkey = false);
-
-  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
-
-  void generate_serialize_container(std::ostream& out,
-                                    t_type* ttype,
-                                    bool pointer_field,
-                                    std::string prefix = "");
-
-  void generate_serialize_map_element(std::ostream& out,
-                                      t_map* tmap,
-                                      std::string kiter,
-                                      std::string viter);
-
-  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
-
-  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
-
-  void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src);
-
-  void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src);
-
-  void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src);
-
-  void generate_go_docstring(std::ostream& out, t_struct* tstruct);
-
-  void generate_go_docstring(std::ostream& out, t_function* tfunction);
-
-  void generate_go_docstring(std::ostream& out,
-                             t_doc* tdoc,
-                             t_struct* tstruct,
-                             const char* subheader);
-
-  void generate_go_docstring(std::ostream& out, t_doc* tdoc);
-
-  void parse_go_tags(map<string,string>* tags, const string in);
-
-  /**
-   * Helper rendering functions
-   */
-
-  std::string go_autogen_comment();
-  std::string go_package();
-  std::string go_imports_begin(bool consts);
-  std::string go_imports_end();
-  std::string render_includes(bool consts);
-  std::string render_included_programs(string& unused_protection);
-  std::string render_program_import(const t_program* program, string& unused_protection);
-  std::string render_system_packages(std::vector<string> &system_packages);
-  std::string render_import_protection();
-  std::string render_fastbinary_includes();
-  std::string declare_argument(t_field* tfield);
-  std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
-  std::string type_name(t_type* ttype);
-  std::string module_name(t_type* ttype);
-  std::string function_signature(t_function* tfunction, std::string prefix = "");
-  std::string function_signature_if(t_function* tfunction,
-                                    std::string prefix = "",
-                                    bool addError = false);
-  std::string argument_list(t_struct* tstruct);
-  std::string type_to_enum(t_type* ttype);
-  std::string type_to_go_type(t_type* ttype);
-  std::string type_to_go_type_with_opt(t_type* ttype,
-                                       bool optional_field);
-  std::string type_to_go_key_type(t_type* ttype);
-  std::string type_to_spec_args(t_type* ttype);
-
-  static std::string get_real_go_module(const t_program* program) {
-
-    if (!package_flag.empty()) {
-      return package_flag;
-    }
-    std::string real_module = program->get_namespace("go");
-    if (!real_module.empty()) {
-      return real_module;
-    }
-
-    return lowercase(program->get_name());
-  }
-
-private:
-  std::string gen_package_prefix_;
-  std::string gen_thrift_import_;
-  bool read_write_private_;
-  bool ignore_initialisms_;
-  bool skip_remote_;
-
-  /**
-   * File streams
-   */
-
-  ofstream_with_content_based_conditional_update f_types_;
-  std::string f_types_name_;
-  ofstream_with_content_based_conditional_update f_consts_;
-  std::string f_consts_name_;
-  std::stringstream f_const_values_;
-
-  std::string package_name_;
-  std::string package_dir_;
-  std::unordered_map<std::string, std::string> package_identifiers_;
-  std::set<std::string> package_identifiers_set_;
-  std::string read_method_name_;
-  std::string write_method_name_;
-  std::string equals_method_name_;
-
-  std::set<std::string> commonInitialisms;
-
-  std::string camelcase(const std::string& value) const;
-  void fix_common_initialism(std::string& value, int i) const;
-  std::string publicize(const std::string& value, bool is_args_or_result = false) const;
-  std::string publicize(const std::string& value, bool is_args_or_result, const std::string& service_name) const;
-  std::string privatize(const std::string& value) const;
-  std::string new_prefix(const std::string& value) const;
-  static std::string variable_name_to_go_name(const std::string& value);
-  static bool is_pointer_field(t_field* tfield, bool in_container = false);
-  static bool omit_initialization(t_field* tfield);
-};
-
 // returns true if field initialization can be omitted since it has corresponding go type zero value
 // or default value is not set
 bool t_go_generator::omit_initialization(t_field* tfield) {
@@ -368,6 +97,8 @@
       } else {
         return value->get_double() == 0.;
       }
+    default:
+      throw "compiler error: unhandled type";
     }
   }
   return false;
@@ -420,6 +151,8 @@
     case t_base_type::TYPE_I64:
     case t_base_type::TYPE_DOUBLE:
       return !has_default;
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return !has_default;
@@ -969,6 +702,10 @@
   system_packages.push_back("time");
   // For the thrift import, always do rename import to make sure it's called thrift.
   system_packages.push_back("thrift \"" + gen_thrift_import_ + "\"");
+
+  // validator import
+  system_packages.push_back("strings");
+  system_packages.push_back("regexp");
   return "import (\n" + render_system_packages(system_packages);
 }
 
@@ -979,7 +716,7 @@
  * This will have to do in lieu of more intelligent import statement construction
  */
 string t_go_generator::go_imports_end() {
-  return string(
+  string import_end = string(
       ")\n\n"
       "// (needed to ensure safety because of naive import list construction.)\n"
       "var _ = thrift.ZERO\n"
@@ -987,7 +724,11 @@
       "var _ = errors.New\n"
       "var _ = context.Background\n"
       "var _ = time.Now\n"
-      "var _ = bytes.Equal\n\n");
+      "var _ = bytes.Equal\n"
+      "// (needed by validator.)\n"
+      "var _ = strings.Contains\n"
+      "var _ = regexp.MatchString\n\n");
+  return import_end;
 }
 
 /**
@@ -1380,6 +1121,14 @@
  */
 void t_go_generator::generate_go_struct(t_struct* tstruct, bool is_exception) {
   generate_go_struct_definition(f_types_, tstruct, is_exception);
+  // generate Validate function
+  std::string tstruct_name(publicize(tstruct->get_name(), false));
+  f_types_ << "func (p *" << tstruct_name << ") Validate() error {" << endl;
+  indent_up();
+  go_validator_generator(this).generate_struct_validator(f_types_, tstruct);
+  f_types_ << indent() << "return nil" << endl;
+  indent_down();
+  f_types_ << "}" << endl;
 }
 
 void t_go_generator::get_publicized_name_and_def_value(t_field* tfield,
@@ -1494,9 +1243,9 @@
 
       // Check for user defined tags and them if there are any. User defined tags
       // can override the above db and json tags.
-      std::map<string, string>::iterator it = (*m_iter)->annotations_.find("go.tag");
+      std::map<string, std::vector<string>>::iterator it = (*m_iter)->annotations_.find("go.tag");
       if (it != (*m_iter)->annotations_.end()) {
-        parse_go_tags(&tags, it->second);
+        parse_go_tags(&tags, it->second.back());
       }
 
       string gotag;
@@ -4057,6 +3806,9 @@
 
     case t_base_type::TYPE_DOUBLE:
       return "thrift.DOUBLE";
+
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "thrift.I32";
@@ -4144,6 +3896,9 @@
 
     case t_base_type::TYPE_DOUBLE:
       return maybe_pointer + "float64";
+
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return maybe_pointer + publicize(type_name(type));
diff --git a/compiler/cpp/src/thrift/generate/t_go_generator.h b/compiler/cpp/src/thrift/generate/t_go_generator.h
new file mode 100644
index 0000000..5080e1a
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/t_go_generator.h
@@ -0,0 +1,329 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 T_GO_GENERATOR_H
+#define T_GO_GENERATOR_H
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+using std::map;
+using std::ostream;
+using std::ostringstream;
+using std::string;
+using std::stringstream;
+using std::vector;
+
+static const string endl = "\n"; // avoid ostream << std::endl flushes
+
+const string DEFAULT_THRIFT_IMPORT = "github.com/apache/thrift/lib/go/thrift";
+static std::string package_flag;
+
+/**
+ * Go code generator.
+ */
+class t_go_generator : public t_generator {
+public:
+  t_go_generator(t_program* program,
+                 const std::map<std::string, std::string>& parsed_options,
+                 const std::string& option_string)
+    : t_generator(program) {
+    (void)option_string;
+    std::map<std::string, std::string>::const_iterator iter;
+
+    gen_thrift_import_ = DEFAULT_THRIFT_IMPORT;
+    gen_package_prefix_ = "";
+    package_flag = "";
+    read_write_private_ = false;
+    ignore_initialisms_ = false;
+    skip_remote_ = false;
+    for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
+      if (iter->first.compare("package_prefix") == 0) {
+        gen_package_prefix_ = (iter->second);
+      } else if (iter->first.compare("thrift_import") == 0) {
+        gen_thrift_import_ = (iter->second);
+      } else if (iter->first.compare("package") == 0) {
+        package_flag = (iter->second);
+      } else if (iter->first.compare("read_write_private") == 0) {
+        read_write_private_ = true;
+      } else if (iter->first.compare("ignore_initialisms") == 0) {
+        ignore_initialisms_ = true;
+      } else if( iter->first.compare("skip_remote") == 0) {
+        skip_remote_ =  true;
+      } else {
+        throw "unknown option go:" + iter->first;
+      }
+    }
+
+    out_dir_base_ = "gen-go";
+  }
+
+  /**
+   * Init and close methods
+   */
+
+  void init_generator() override;
+  void close_generator() override;
+
+  /**
+   * Program-level generation functions
+   */
+
+  void generate_typedef(t_typedef* ttypedef) override;
+  void generate_enum(t_enum* tenum) override;
+  void generate_const(t_const* tconst) override;
+  void generate_struct(t_struct* tstruct) override;
+  void generate_xception(t_struct* txception) override;
+  void generate_service(t_service* tservice) override;
+
+  std::string render_const_value(t_type* type,
+                                 t_const_value* value,
+                                 const string& name,
+                                 bool opt = false);
+
+  /**
+   * Struct generation code
+   */
+
+  void generate_go_struct(t_struct* tstruct, bool is_exception);
+  void generate_go_struct_definition(std::ostream& out,
+                                     t_struct* tstruct,
+                                     bool is_xception = false,
+                                     bool is_result = false,
+                                     bool is_args = false);
+  void generate_go_struct_initializer(std::ostream& out,
+                                      t_struct* tstruct,
+                                      bool is_args_or_result = false);
+  void generate_isset_helpers(std::ostream& out,
+                              t_struct* tstruct,
+                              const string& tstruct_name,
+                              bool is_result = false);
+  void generate_countsetfields_helper(std::ostream& out,
+                                      t_struct* tstruct,
+                                      const string& tstruct_name,
+                                      bool is_result = false);
+  void generate_go_struct_reader(std::ostream& out,
+                                 t_struct* tstruct,
+                                 const string& tstruct_name,
+                                 bool is_result = false);
+  void generate_go_struct_writer(std::ostream& out,
+                                 t_struct* tstruct,
+                                 const string& tstruct_name,
+                                 bool is_result = false,
+                                 bool uses_countsetfields = false);
+  void generate_go_struct_equals(std::ostream& out, t_struct* tstruct, const string& tstruct_name);
+  void generate_go_function_helpers(t_function* tfunction);
+  void get_publicized_name_and_def_value(t_field* tfield,
+                                         string* OUT_pub_name,
+                                         t_const_value** OUT_def_value) const;
+
+  /**
+   * Service-level generation functions
+   */
+
+  void generate_service_helpers(t_service* tservice);
+  void generate_service_interface(t_service* tservice);
+  void generate_service_client(t_service* tservice);
+  void generate_service_remote(t_service* tservice);
+  void generate_service_server(t_service* tservice);
+  void generate_process_function(t_service* tservice, t_function* tfunction);
+
+  /**
+   * Serialization constructs
+   */
+
+  void generate_deserialize_field(std::ostream& out,
+                                  t_field* tfield,
+                                  bool declare,
+                                  std::string prefix = "",
+                                  bool inclass = false,
+                                  bool coerceData = false,
+                                  bool inkey = false,
+                                  bool in_container = false);
+
+  void generate_deserialize_struct(std::ostream& out,
+                                   t_struct* tstruct,
+                                   bool is_pointer_field,
+                                   bool declare,
+                                   std::string prefix = "");
+
+  void generate_deserialize_container(std::ostream& out,
+                                      t_type* ttype,
+                                      bool pointer_field,
+                                      bool declare,
+                                      std::string prefix = "");
+
+  void generate_deserialize_set_element(std::ostream& out,
+                                        t_set* tset,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_map_element(std::ostream& out,
+                                        t_map* tmap,
+                                        bool declare,
+                                        std::string prefix = "");
+
+  void generate_deserialize_list_element(std::ostream& out,
+                                         t_list* tlist,
+                                         bool declare,
+                                         std::string prefix = "");
+
+  void generate_serialize_field(std::ostream& out,
+                                t_field* tfield,
+                                std::string prefix = "",
+                                bool inkey = false);
+
+  void generate_serialize_struct(std::ostream& out, t_struct* tstruct, std::string prefix = "");
+
+  void generate_serialize_container(std::ostream& out,
+                                    t_type* ttype,
+                                    bool pointer_field,
+                                    std::string prefix = "");
+
+  void generate_serialize_map_element(std::ostream& out,
+                                      t_map* tmap,
+                                      std::string kiter,
+                                      std::string viter);
+
+  void generate_serialize_set_element(std::ostream& out, t_set* tmap, std::string iter);
+
+  void generate_serialize_list_element(std::ostream& out, t_list* tlist, std::string iter);
+
+  void generate_go_equals(std::ostream& out, t_type* ttype, string tgt, string src);
+
+  void generate_go_equals_struct(std::ostream& out, t_type* ttype, string tgt, string src);
+
+  void generate_go_equals_container(std::ostream& out, t_type* ttype, string tgt, string src);
+
+  void generate_go_docstring(std::ostream& out, t_struct* tstruct);
+
+  void generate_go_docstring(std::ostream& out, t_function* tfunction);
+
+  void generate_go_docstring(std::ostream& out,
+                             t_doc* tdoc,
+                             t_struct* tstruct,
+                             const char* subheader);
+
+  void generate_go_docstring(std::ostream& out, t_doc* tdoc);
+
+  void parse_go_tags(map<string, string>* tags, const string in);
+
+  /**
+   * Helper rendering functions
+   */
+
+  std::string go_autogen_comment();
+  std::string go_package();
+  std::string go_imports_begin(bool consts);
+  std::string go_imports_end();
+  std::string render_includes(bool consts);
+  std::string render_included_programs(string& unused_protection);
+  std::string render_program_import(const t_program* program, string& unused_protection);
+  std::string render_system_packages(std::vector<string>& system_packages);
+  std::string render_import_protection();
+  std::string render_fastbinary_includes();
+  std::string declare_argument(t_field* tfield);
+  std::string render_field_initial_value(t_field* tfield, const string& name, bool optional_field);
+  std::string type_name(t_type* ttype);
+  std::string module_name(t_type* ttype);
+  std::string function_signature(t_function* tfunction, std::string prefix = "");
+  std::string function_signature_if(t_function* tfunction,
+                                    std::string prefix = "",
+                                    bool addError = false);
+  std::string argument_list(t_struct* tstruct);
+  std::string type_to_enum(t_type* ttype);
+  std::string type_to_go_type(t_type* ttype);
+  std::string type_to_go_type_with_opt(t_type* ttype, bool optional_field);
+  std::string type_to_go_key_type(t_type* ttype);
+  std::string type_to_spec_args(t_type* ttype);
+
+  void indent_up() { t_generator::indent_up(); }
+  void indent_down() { t_generator::indent_down(); }
+  std::string indent() { return t_generator::indent(); }
+  std::ostream& indent(std::ostream& os) { return t_generator::indent(os); }
+
+  static std::string get_real_go_module(const t_program* program) {
+
+    if (!package_flag.empty()) {
+      return package_flag;
+    }
+    std::string real_module = program->get_namespace("go");
+    if (!real_module.empty()) {
+      return real_module;
+    }
+
+    return lowercase(program->get_name());
+  }
+
+  static bool is_pointer_field(t_field* tfield, bool in_container = false);
+
+private:
+  std::string gen_package_prefix_;
+  std::string gen_thrift_import_;
+  bool read_write_private_;
+  bool ignore_initialisms_;
+  bool skip_remote_;
+
+  /**
+   * File streams
+   */
+
+  ofstream_with_content_based_conditional_update f_types_;
+  std::string f_types_name_;
+  ofstream_with_content_based_conditional_update f_consts_;
+  std::string f_consts_name_;
+  std::stringstream f_const_values_;
+
+  std::string package_name_;
+  std::string package_dir_;
+  std::unordered_map<std::string, std::string> package_identifiers_;
+  std::set<std::string> package_identifiers_set_;
+  std::string read_method_name_;
+  std::string write_method_name_;
+  std::string equals_method_name_;
+
+  std::set<std::string> commonInitialisms;
+
+  std::string camelcase(const std::string& value) const;
+  void fix_common_initialism(std::string& value, int i) const;
+  std::string publicize(const std::string& value, bool is_args_or_result = false) const;
+  std::string publicize(const std::string& value,
+                        bool is_args_or_result,
+                        const std::string& service_name) const;
+  std::string privatize(const std::string& value) const;
+  std::string new_prefix(const std::string& value) const;
+  static std::string variable_name_to_go_name(const std::string& value);
+  static bool omit_initialization(t_field* tfield);
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
index 757f207..8893742 100644
--- a/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_haxe_generator.cc
@@ -544,6 +544,9 @@
     case t_base_type::TYPE_STRING:
       out << '"' << get_escaped_string(value) << '"';
       break;
+    case t_base_type::TYPE_UUID:
+      out << '"' << get_escaped_string(value) << '"';
+      break;
     case t_base_type::TYPE_BOOL:
       out << ((value->get_integer() > 0) ? "true" : "false");
       break;
@@ -1443,6 +1446,9 @@
     case t_base_type::TYPE_STRING:
       return "TType.STRING";
       break;
+    case t_base_type::TYPE_UUID:
+      return "TType.UUID";
+      break;
     case t_base_type::TYPE_BOOL:
       return "TType.BOOL";
       break;
@@ -2222,6 +2228,9 @@
           out << "readString();";
         }
         break;
+      case t_base_type::TYPE_UUID:
+        out << "readUuid();";
+        break;
       case t_base_type::TYPE_BOOL:
         out << "readBool();";
         break;
@@ -2406,6 +2415,9 @@
           out << "writeString(" << name << ");";
         }
         break;
+      case t_base_type::TYPE_UUID:
+        out << "writeUuid(" << name << ");";
+        break;
       case t_base_type::TYPE_BOOL:
         out << "writeBool(" << name << ");";
         break;
@@ -2651,6 +2663,8 @@
     } else {
       return "String";
     }
+  case t_base_type::TYPE_UUID:
+    return "String";
   case t_base_type::TYPE_BOOL:
     return "Bool";
   case t_base_type::TYPE_I8:
@@ -2686,6 +2700,9 @@
       case t_base_type::TYPE_STRING:
         result += " = null";
         break;
+      case t_base_type::TYPE_UUID:
+        result += " = uuid.Uuid.NIL";
+        break;
       case t_base_type::TYPE_BOOL:
         result += " = false";
         break;
@@ -2698,6 +2715,8 @@
       case t_base_type::TYPE_DOUBLE:
         result += " = (double)0";
         break;
+      default:
+        throw "unhandled type";
       }
 
     } else if (ttype->is_enum()) {
@@ -2793,6 +2812,8 @@
       throw "NO T_VOID CONSTRUCT";
     case t_base_type::TYPE_STRING:
       return "TType.STRING";
+    case t_base_type::TYPE_UUID:
+      return "TType.UUID";
     case t_base_type::TYPE_BOOL:
       return "TType.BOOL";
     case t_base_type::TYPE_I8:
@@ -2805,6 +2826,8 @@
       return "TType.I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType.DOUBLE";
+    default:
+      break;
     }
   } else if (type->is_enum()) {
     return "TType.I32";
diff --git a/compiler/cpp/src/thrift/generate/t_java_generator.cc b/compiler/cpp/src/thrift/generate/t_java_generator.cc
index 7dfd10f..a6041d7 100644
--- a/compiler/cpp/src/thrift/generate/t_java_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_java_generator.cc
@@ -371,7 +371,11 @@
     ttype = get_true_type(ttype);
 
     return ttype->is_container() || ttype->is_struct() || ttype->is_xception() || ttype->is_string()
-           || ttype->is_enum();
+           || ttype->is_uuid() || ttype->is_enum();
+  }
+
+  bool is_deprecated(const std::map<std::string, std::vector<std::string>>& annotations) {
+    return annotations.find("deprecated") != annotations.end();
   }
 
   bool is_deprecated(const std::map<std::string, std::string>& annotations) {
@@ -767,6 +771,9 @@
         render << '"' << get_escaped_string(value) << '"';
       }
       break;
+    case t_base_type::TYPE_UUID:
+      render << "java.util.UUID.fromString(\"" << get_escaped_string(value) << "\")";
+      break;
     case t_base_type::TYPE_BOOL:
       render << ((value->get_integer() > 0) ? "true" : "false");
       break;
@@ -1813,6 +1820,9 @@
         case t_base_type::TYPE_I16:
           indent(out) << "out.writeInt(new Short(" << name << ").intValue());" << endl;
           break;
+        case t_base_type::TYPE_UUID:
+          indent(out) << "out.writeUuid(" << name << ");" << endl;
+          break;
         case t_base_type::TYPE_I32:
           indent(out) << "out.writeInt(" << name << ");" << endl;
           break;
@@ -1833,6 +1843,8 @@
           break;
         case t_base_type::TYPE_VOID:
           break;
+        default:
+          throw "compiler error: unhandled type";
         }
       }
     }
@@ -1908,6 +1920,9 @@
         scope_down(out);
       } else {
         switch (bt->get_base()) {
+        case t_base_type::TYPE_I8:
+          indent(out) << prefix << " = in.readByte();" << endl;
+          break;
         case t_base_type::TYPE_I16:
           indent(out) << prefix << " = (short) in.readInt();" << endl;
           break;
@@ -1917,12 +1932,12 @@
         case t_base_type::TYPE_I64:
           indent(out) << prefix << " = in.readLong();" << endl;
           break;
+        case t_base_type::TYPE_UUID:
+          indent(out) << prefix << " = in.readUuid();" << endl;
+          break;
         case t_base_type::TYPE_BOOL:
           indent(out) << prefix << " = (in.readInt()==1);" << endl;
           break;
-        case t_base_type::TYPE_I8:
-          indent(out) << prefix << " = in.readByte();" << endl;
-          break;
         case t_base_type::TYPE_DOUBLE:
           indent(out) << prefix << " = in.readDouble();" << endl;
           break;
@@ -1931,6 +1946,8 @@
           break;
         case t_base_type::TYPE_VOID:
           break;
+        default:
+          throw "compiler error: unhandled type";
         }
       }
     }
@@ -2062,6 +2079,7 @@
     } else if (t->is_base_type()) {
       switch (((t_base_type*)t)->get_base()) {
       case t_base_type::TYPE_STRING:
+      case t_base_type::TYPE_UUID:
         indent(out) << "hashCode = hashCode * " << MUL << " + " << name << ".hashCode();" << endl;
         break;
       case t_base_type::TYPE_BOOL:
@@ -2902,6 +2920,9 @@
     case t_base_type::TYPE_STRING:
       return "org.apache.thrift.protocol.TType.STRING";
       break;
+    case t_base_type::TYPE_UUID:
+      return "org.apache.thrift.protocol.TType.UUID";
+      break;
     case t_base_type::TYPE_BOOL:
       return "org.apache.thrift.protocol.TType.BOOL";
       break;
@@ -2949,7 +2970,7 @@
   indent_up();
   for (auto& annotation : field->annotations_) {
     indent(out) << ".add(new java.util.AbstractMap.SimpleImmutableEntry<>(\"" + annotation.first
-                       + "\", \"" + annotation.second + "\"))"
+                       + "\", \"" + annotation.second.back() + "\"))"
                 << endl;
   }
   indent(out) << ".build().collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, "
@@ -4079,6 +4100,9 @@
     case t_base_type::TYPE_I64:
       out << "readI64();";
       break;
+    case t_base_type::TYPE_UUID:
+      out << "readUuid();";
+      break;
     case t_base_type::TYPE_DOUBLE:
       out << "readDouble();";
       break;
@@ -4389,6 +4413,9 @@
       case t_base_type::TYPE_I64:
         out << "writeI64(" << name << ");";
         break;
+      case t_base_type::TYPE_UUID:
+        out << "writeUuid(" << name << ");";
+        break;
       case t_base_type::TYPE_DOUBLE:
         out << "writeDouble(" << name << ");";
         break;
@@ -4611,6 +4638,8 @@
     } else {
       return "java.lang.String";
     }
+  case t_base_type::TYPE_UUID:
+    return "java.util.UUID";
   case t_base_type::TYPE_BOOL:
     return (in_container ? "java.lang.Boolean" : "boolean");
   case t_base_type::TYPE_I8:
@@ -4652,6 +4681,7 @@
       case t_base_type::TYPE_VOID:
         throw "NO T_VOID CONSTRUCT";
       case t_base_type::TYPE_STRING:
+      case t_base_type::TYPE_UUID:
         result += " = null";
         break;
       case t_base_type::TYPE_BOOL:
@@ -4666,6 +4696,8 @@
       case t_base_type::TYPE_DOUBLE:
         result += " = (double)0";
         break;
+      default:
+        throw "compiler error: unhandled type";
       }
     } else if (ttype->is_enum()) {
       result += " = null";
@@ -4841,8 +4873,12 @@
       return "org.apache.thrift.protocol.TType.I32";
     case t_base_type::TYPE_I64:
       return "org.apache.thrift.protocol.TType.I64";
+    case t_base_type::TYPE_UUID:
+      return "org.apache.thrift.protocol.TType.UUID";
     case t_base_type::TYPE_DOUBLE:
       return "org.apache.thrift.protocol.TType.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "org.apache.thrift.protocol.TType.I32";
@@ -5312,12 +5348,8 @@
   indent(out) << java_override_annotation() << endl;
   indent(out) << "public void clear() {" << endl;
 
-  const vector<t_field*>& members = tstruct->get_members();
-  vector<t_field*>::const_iterator m_iter;
-
   indent_up();
-  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
-    t_field* field = *m_iter;
+  for (auto field : tstruct->get_members()) {
     t_type* t = get_true_type(field->get_type());
 
     if (field->get_value() != nullptr) {
@@ -5326,16 +5358,13 @@
     }
 
     if (type_can_be_null(t)) {
-
       if (reuse_objects_ && (t->is_container() || t->is_struct())) {
         indent(out) << "if (this." << field->get_name() << " != null) {" << endl;
         indent_up();
         indent(out) << "this." << field->get_name() << ".clear();" << endl;
         indent_down();
         indent(out) << "}" << endl;
-
       } else {
-
         indent(out) << "this." << field->get_name() << " = null;" << endl;
       }
       continue;
diff --git a/compiler/cpp/src/thrift/generate/t_javame_generator.cc b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
index b37a43b..4da0869 100644
--- a/compiler/cpp/src/thrift/generate/t_javame_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_javame_generator.cc
@@ -2869,6 +2869,8 @@
       case t_base_type::TYPE_DOUBLE:
         result += " = (double)0";
         break;
+      default:
+        throw "compiler error: unhandled type";
       }
 
     } else if (ttype->is_enum()) {
@@ -2951,6 +2953,8 @@
       return "TType.I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "TType.I32";
diff --git a/compiler/cpp/src/thrift/generate/t_js_generator.cc b/compiler/cpp/src/thrift/generate/t_js_generator.cc
index 5fcac16..03a307f 100644
--- a/compiler/cpp/src/thrift/generate/t_js_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_js_generator.cc
@@ -2697,6 +2697,8 @@
       return "Thrift.Type.I64";
     case t_base_type::TYPE_DOUBLE:
       return "Thrift.Type.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "Thrift.Type.I32";
@@ -2745,6 +2747,9 @@
       break;
     case t_base_type::TYPE_VOID:
       ts_type = "void";
+      break;
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum() || type->is_struct() || type->is_xception()) {
     std::string type_name;
diff --git a/compiler/cpp/src/thrift/generate/t_json_generator.cc b/compiler/cpp/src/thrift/generate/t_json_generator.cc
index e16bc50..5a854ce 100644
--- a/compiler/cpp/src/thrift/generate/t_json_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_json_generator.cc
@@ -268,7 +268,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : ttype->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
@@ -459,7 +461,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : ttypedef->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
@@ -566,7 +570,9 @@
       write_key_and("annotations");
       start_object();
       for (auto & annotation : tenum->annotations_) {
-        write_key_and_string(annotation.first, annotation.second);
+        for (auto& annotation_value : annotation.second) {
+          write_key_and_string(annotation.first, annotation_value);
+        }
       }
       end_object();
   }
@@ -605,7 +611,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : tstruct->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
@@ -645,7 +653,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : tservice->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
@@ -682,7 +692,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : tfunc->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
@@ -728,7 +740,9 @@
     write_key_and("annotations");
     start_object();
     for (auto & annotation : field->annotations_) {
-      write_key_and_string(annotation.first, annotation.second);
+      for (auto& annotation_value : annotation.second) {
+        write_key_and_string(annotation.first, annotation_value);
+      }
     }
     end_object();
   }
diff --git a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
index 3a2afe6..29cf00a 100644
--- a/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_kotlin_generator.cc
@@ -346,6 +346,8 @@
     return "kotlin.Int";
   case t_base_type::TYPE_I64:
     return "kotlin.Long";
+  case t_base_type::TYPE_UUID:
+    return "java.util.UUID";
   case t_base_type::TYPE_DOUBLE:
     return "kotlin.Double";
   default:
@@ -581,7 +583,7 @@
     out << "mapOf(" << endl;
     indent_up();
     for (auto& annotation : field->annotations_) {
-      indent(out) << "\"" + annotation.first + "\" to \"" + annotation.second + "\"," << endl;
+      indent(out) << "\"" + annotation.first + "\" to \"" + annotation.second.back() + "\"," << endl;
     }
     indent_down();
     indent(out) << ")";
@@ -1200,6 +1202,8 @@
     return "writeI32(" + it + ")";
   case t_base_type::TYPE_I64:
     return "writeI64(" + it + ")";
+  case t_base_type::TYPE_UUID:
+    return "writeUuid(" + it + ")";
   case t_base_type::TYPE_DOUBLE:
     return "writeDouble(" + it + ")";
   default:
@@ -1228,6 +1232,8 @@
     return "readI32()";
   case t_base_type::TYPE_I64:
     return "readI64()";
+  case t_base_type::TYPE_UUID:
+    return "readUuid()";
   case t_base_type::TYPE_DOUBLE:
     return "readDouble()";
   default:
@@ -1890,8 +1896,12 @@
       return "org.apache.thrift.protocol.TType.I32";
     case t_base_type::TYPE_I64:
       return "org.apache.thrift.protocol.TType.I64";
+    case t_base_type::TYPE_UUID:
+      return "org.apache.thrift.protocol.TType.UUID";
     case t_base_type::TYPE_DOUBLE:
       return "org.apache.thrift.protocol.TType.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "org.apache.thrift.protocol.TType.I32";
diff --git a/compiler/cpp/src/thrift/generate/t_lua_generator.cc b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
index de3b890..a4b4a37 100644
--- a/compiler/cpp/src/thrift/generate/t_lua_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_lua_generator.cc
@@ -1146,6 +1146,8 @@
       return "TType.I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "TType.I32";
diff --git a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
index 17e90f7..0f6aa22 100644
--- a/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_markdown_generator.cc
@@ -199,7 +199,7 @@
         string fn_name = (*fn_iter)->get_name(); 
         filling.emplace_back();
         fill = &filling.back();
-        (*fill)[1] = "	[ &bull; " + fn_name + "](" 
+        (*fill)[1] = "    [ &bull; " + fn_name + "](" 
           + make_file_link(fname) 
           + "#function-" + str_to_id(name + fn_name) + ")";
       }
diff --git a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
index ad9e579..4cf3db5 100644
--- a/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_netstd_generator.cc
@@ -636,6 +636,9 @@
                 render << '"' << get_escaped_string(value) << '"';
             }
             break;
+        case t_base_type::TYPE_UUID:
+            render << "new System.Guid(\"" << get_escaped_string(value) << "\")";
+            break;
         case t_base_type::TYPE_BOOL:
             render << ((value->get_integer() > 0) ? "true" : "false");
             break;
@@ -2056,8 +2059,8 @@
   if( func->annotations_.end() != iter) {
     out << indent() << "[Obsolete";
     // empty annotation values end up with "1" somewhere, ignore these as well
-    if ((iter->second.length() > 0) && (iter->second != "1")) {
-      out << "(" << make_csharp_string_literal(iter->second) << ")";
+    if ((iter->second.back().length() > 0) && (iter->second.back() != "1")) {
+      out << "(" << make_csharp_string_literal(iter->second.back()) << ")";
     }
     out << "]" << endl;
   }
@@ -2703,6 +2706,9 @@
                     out << "ReadStringAsync(" << CANCELLATION_TOKEN_NAME << ");";
                 }
                 break;
+            case t_base_type::TYPE_UUID:
+                out << "ReadUuidAsync(" << CANCELLATION_TOKEN_NAME << ");";
+                break;
             case t_base_type::TYPE_BOOL:
                 out << "ReadBoolAsync(" << CANCELLATION_TOKEN_NAME << ");";
                 break;
@@ -2906,6 +2912,9 @@
                 }
                 out << name << ", " << CANCELLATION_TOKEN_NAME << ");";
                 break;
+            case t_base_type::TYPE_UUID:
+                out << "WriteUuidAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
+                break;
             case t_base_type::TYPE_BOOL:
                 out << "WriteBoolAsync(" << nullable_name << ", " << CANCELLATION_TOKEN_NAME << ");";
                 break;
@@ -3453,7 +3462,7 @@
     if (ttype->is_set())
     {
         t_set* tset = static_cast<t_set*>(ttype);
-		return "HashSet<" + type_name(tset->get_elem_type()) + ">";
+        return "HashSet<" + type_name(tset->get_elem_type()) + ">";
     }
 
     if (ttype->is_list())
@@ -3492,6 +3501,8 @@
         } else {
             return "string";
         }
+    case t_base_type::TYPE_UUID:
+        return "global::System.Guid";
     case t_base_type::TYPE_BOOL:
         return "bool";
     case t_base_type::TYPE_I8:
@@ -3614,6 +3625,9 @@
                 return " = null";
             }
             break;
+        case t_base_type::TYPE_UUID:
+            return " = System.Guid.Empty";
+            break;
         case t_base_type::TYPE_BOOL:
             return " = false";
             break;
@@ -3725,6 +3739,8 @@
             throw "NO T_VOID CONSTRUCT";
         case t_base_type::TYPE_STRING:
             return "TType.String";
+        case t_base_type::TYPE_UUID:
+            return "TType.Uuid";
         case t_base_type::TYPE_BOOL:
             return "TType.Bool";
         case t_base_type::TYPE_I8:
diff --git a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
index 0a96146..747adcb 100644
--- a/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_ocaml_generator.cc
@@ -61,12 +61,9 @@
     out_dir_base_ = "gen-ocaml";
   }
 
-  /**
-   * Init and close methods
-   */
+  ~t_ocaml_generator() override;
 
   void init_generator() override;
-  void close_generator() override;
 
   /**
    * Program-level generation functions
@@ -147,16 +144,20 @@
    * Helper rendering functions
    */
 
-  std::string ocaml_autogen_comment();
+  /** Need to disable codegen comment for unit tests to be version-agnostic */
+  virtual std::string ocaml_autogen_comment();
+
   std::string ocaml_imports();
   std::string type_name(t_type* ttype);
+  std::string exception_ctor(t_type* ttype);
   std::string function_signature(t_function* tfunction, std::string prefix = "");
   std::string function_type(t_function* tfunc, bool method = false, bool options = false);
   std::string argument_list(t_struct* tstruct);
   std::string type_to_enum(t_type* ttype);
   std::string render_ocaml_type(t_type* type);
 
-private:
+// Need access to output file streams for testing.
+protected:
   /**
    * File streams
    */
@@ -216,9 +217,6 @@
   // Generate constants
   vector<t_const*> consts = program_->get_consts();
   generate_consts(consts);
-
-  // Close the generator
-  close_generator();
 }
 
 /**
@@ -262,12 +260,12 @@
   return "open Thrift";
 }
 
-/**
- * Closes the type files
- */
-void t_ocaml_generator::close_generator() {
-  // Close types file
+t_ocaml_generator::~t_ocaml_generator() {
+  f_consts_.close();
   f_types_.close();
+  f_types_i_.close();
+  f_service_.close();
+  f_service_i_.close();
 }
 
 /**
@@ -914,10 +912,6 @@
   generate_service_interface(tservice);
   generate_service_client(tservice);
   generate_service_server(tservice);
-
-  // Close service file
-  f_service_.close();
-  f_service_i_.close();
 }
 
 /**
@@ -1108,7 +1102,7 @@
       for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
         f_service_ << indent() << "(match result#get_" << (*x_iter)->get_name()
                    << " with None -> () | Some _v ->" << endl;
-        indent(f_service_) << "  raise (" << capitalize(type_name((*x_iter)->get_type()))
+        indent(f_service_) << "  raise (" << capitalize(exception_ctor((*x_iter)->get_type()))
                            << " _v));" << endl;
       }
 
@@ -1270,7 +1264,7 @@
     indent(f_service_) << "with" << endl;
     indent_up();
     for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
-      f_service_ << indent() << "| " << capitalize(type_name((*x_iter)->get_type())) << " "
+      f_service_ << indent() << "| " << capitalize(exception_ctor((*x_iter)->get_type())) << " "
                  << (*x_iter)->get_name() << " -> " << endl;
       indent_up();
       indent_up();
@@ -1673,6 +1667,18 @@
   return prefix + name;
 }
 
+string t_ocaml_generator::exception_ctor(t_type* ttype) {
+  string prefix = "";
+  t_program* program = ttype->get_program();
+  if (program != nullptr && program != program_) {
+    if (!ttype->is_service()) {
+      prefix = capitalize(program->get_name()) + "_types.";
+    }
+  }
+
+  return prefix + capitalize(ttype->get_name());
+}
+
 /**
  * Converts the parse type to a Protocol.t_type enum
  */
@@ -1698,6 +1704,8 @@
       return "Protocol.T_I64";
     case t_base_type::TYPE_DOUBLE:
       return "Protocol.T_DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "Protocol.T_I32";
@@ -1739,6 +1747,8 @@
       return "Int64.t";
     case t_base_type::TYPE_DOUBLE:
       return "float";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return capitalize(((t_enum*)type)->get_name()) + ".t";
diff --git a/compiler/cpp/src/thrift/generate/t_perl_generator.cc b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
index 68bd57f..72de698 100644
--- a/compiler/cpp/src/thrift/generate/t_perl_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_perl_generator.cc
@@ -1003,12 +1003,12 @@
       f_service_ << indent() << "my $" << (*a_iter)->get_name() << " = (" << req << ") ? " << req
                  << " : undef;" << endl;
       /* slist no longer supported
-	  if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) {
+      if (atype->is_string() && ((t_base_type*)atype)->is_string_list()) {
         f_service_ << indent() << "my @" << (*a_iter)->get_name() << " = split(/,/, $"
                    << (*a_iter)->get_name() << ");" << endl << indent() << "$"
                    << (*a_iter)->get_name() << " = \\@" << (*a_iter)->get_name() << endl;
       }
-	  */
+      */
     }
     f_service_ << indent() << "return $self->{impl}->" << (*f_iter)->get_name() << "("
                << argument_list((*f_iter)->get_arglist()) << ");" << endl;
@@ -1666,6 +1666,8 @@
       return "Thrift::TType::I64";
     case t_base_type::TYPE_DOUBLE:
       return "Thrift::TType::DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "Thrift::TType::I32";
diff --git a/compiler/cpp/src/thrift/generate/t_php_generator.cc b/compiler/cpp/src/thrift/generate/t_php_generator.cc
index 39968a6..c6e60c8 100644
--- a/compiler/cpp/src/thrift/generate/t_php_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_php_generator.cc
@@ -62,7 +62,7 @@
     validate_ = false;
     json_serializable_ = false;
     getters_setters_ = false;
-	    
+        
     nsglobal_ = ""; // by default global namespace is empty
     classmap_ = false;
     for (iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
@@ -874,8 +874,8 @@
  * Generates a setter for the generated private fields
  */
 void t_php_generator::generate_reflection_setters(ostringstream& out,
-						  string field_name,
-						  string cap_name) {
+                          string field_name,
+                          string cap_name) {
 
   out << indent() << "public function set" << cap_name << "(" << "$" << field_name << ")" << endl
       << indent() << "{" << endl;
@@ -2798,6 +2798,8 @@
       return "TType::I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType::DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "TType::I32";
@@ -2839,6 +2841,8 @@
       return "int";
     case t_base_type::TYPE_DOUBLE:
       return "double";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "int";
diff --git a/compiler/cpp/src/thrift/generate/t_py_generator.cc b/compiler/cpp/src/thrift/generate/t_py_generator.cc
index 7f3cae5..8ab8b98 100644
--- a/compiler/cpp/src/thrift/generate/t_py_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_py_generator.cc
@@ -280,12 +280,12 @@
   }
 
   static bool is_immutable(t_type* ttype) {
-    std::map<std::string, std::string>::iterator it = ttype->annotations_.find("python.immutable");
+    std::map<std::string, std::vector<std::string>>::iterator it = ttype->annotations_.find("python.immutable");
 
     if (it == ttype->annotations_.end()) {
       // Exceptions are immutable by default.
       return ttype->is_xception();
-    } else if (it->second == "false") {
+    } else if (!it->second.empty() && it->second.back() == "false") {
       return false;
     } else {
       return true;
@@ -2767,6 +2767,8 @@
       return "TType.I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType.DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "TType.I32";
diff --git a/compiler/cpp/src/thrift/generate/t_rb_generator.cc b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
index 116ccaa..2ec5787 100644
--- a/compiler/cpp/src/thrift/generate/t_rb_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rb_generator.cc
@@ -1171,6 +1171,8 @@
       return "::Thrift::Types::I64";
     case t_base_type::TYPE_DOUBLE:
       return "::Thrift::Types::DOUBLE";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "::Thrift::Types::I32";
diff --git a/compiler/cpp/src/thrift/generate/t_rs_generator.cc b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
index 2f26847..5946e1d 100644
--- a/compiler/cpp/src/thrift/generate/t_rs_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_rs_generator.cc
@@ -127,7 +127,7 @@
   void render_const_value_holder(const string& name, t_type* ttype, t_const_value* tvalue);
 
   // Write the actual const value - the right side of a const definition.
-  void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true);
+  void render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned = true, bool is_inline = true);
 
   // Write a const struct (returned from `const_value` method).
   void render_const_struct(t_type* ttype, t_const_value* tvalue);
@@ -141,14 +141,6 @@
   // Write a const map (returned from `const_value` method).
   void render_const_map(t_type* ttype, t_const_value* tvalue);
 
-  // Write the code to insert constant values into a rust vec or set. The
-  // `insert_function` is the rust function that we'll use to insert the elements.
-  void render_container_const_value(
-    const string& insert_function,
-    t_type* ttype,
-    t_const_value* tvalue
-  );
-
   // Write the rust representation of a thrift struct to the generated file. Set `struct_type` to `T_ARGS`
   // if rendering the struct used to pack arguments for a service call. When `struct_type` is `T_ARGS` the
   // struct and its members have module visibility, and all fields are required. When `struct_type` is
@@ -195,10 +187,6 @@
   // user-defined exception to be properly handled as Rust errors.
   void render_exception_struct_error_trait_impls(const string& struct_name, t_struct* tstruct);
 
-  // Write the implementations for the `Default`. This trait allows you to specify only the fields you want
-  // and use `..Default::default()` to fill in the rest.
-  void render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct);
-
   // Write the function that serializes a struct to its wire representation. If `struct_type` is `T_ARGS`
   // then all fields are considered "required", if not, the default optionality is used.
   void render_struct_sync_write(t_struct *tstruct, t_rs_generator::e_struct_type struct_type);
@@ -541,18 +529,21 @@
 void t_rs_generator::render_attributes_and_includes() {
   // turn off some compiler/clippy warnings
 
+  // code may not be used
+  f_gen_ << "#![allow(dead_code)]" << endl;
   // code always includes BTreeMap/BTreeSet/OrderedFloat
   f_gen_ << "#![allow(unused_imports)]" << endl;
   // code might not include imports from crates
   f_gen_ << "#![allow(unused_extern_crates)]" << endl;
   // constructors take *all* struct parameters, which can trigger the "too many arguments" warning
   // some auto-gen'd types can be deeply nested. clippy recommends factoring them out which is hard to autogen
+  // some methods may start with "is_"
   // FIXME: re-enable the 'vec_box' lint see: [THRIFT-5364](https://issues.apache.org/jira/browse/THRIFT-5364)
   // This can happen because we automatically generate a Vec<Box<Type>> when the type is a typedef
   // and it's a forward typedef. This (typedef + forward typedef) can happen in two situations:
   // 1. When the type is recursive
   // 2. When you define types out of order
-  f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box)]" << endl;
+  f_gen_ << "#![allow(clippy::too_many_arguments, clippy::type_complexity, clippy::vec_box, clippy::wrong_self_convention)]" << endl;
   // prevent rustfmt from running against this file
   // lines are too long, code is (thankfully!) not visual-indented, etc.
   // can't use #[rustfmt::skip] see: https://github.com/rust-lang/rust/issues/54726
@@ -684,7 +675,7 @@
 
   f_gen_ << indent() << "pub fn const_value() -> " << to_rust_type(ttype) << " {" << endl;
   indent_up();
-  render_const_value(ttype, tvalue);
+  render_const_value(ttype, tvalue, true, false);
   indent_down();
   f_gen_ << indent() << "}" << endl;
 
@@ -693,7 +684,11 @@
   f_gen_ << endl;
 }
 
-void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned) {
+void t_rs_generator::render_const_value(t_type* ttype, t_const_value* tvalue, bool is_owned, bool is_inline) {
+  if (!is_inline) {
+    f_gen_ << indent();
+  }
+
   if (ttype->is_base_type()) {
     t_base_type* tbase_type = (t_base_type*)ttype;
     switch (tbase_type->get_base()) {
@@ -727,9 +722,9 @@
       throw "cannot generate const value for " + t_base_type::t_base_name(tbase_type->get_base());
     }
   } else if (ttype->is_typedef()) {
-    render_const_value(get_true_type(ttype), tvalue);
+    render_const_value(get_true_type(ttype), tvalue, is_owned, true);
   } else if (ttype->is_enum()) {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_
       << indent()
@@ -739,13 +734,11 @@
       << ").expect(\"expecting valid const value\")"
       << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   } else if (ttype->is_struct() || ttype->is_xception()) {
     render_const_struct(ttype, tvalue);
   } else if (ttype->is_container()) {
-    f_gen_ << indent() << "{" << endl;
-    indent_up();
-
+    // all of them use vec! or from(), extra block is no longer needed
     if (ttype->is_list()) {
       render_const_list(ttype, tvalue);
     } else if (ttype->is_set()) {
@@ -755,111 +748,87 @@
     } else {
       throw "cannot generate const container value for " + ttype->get_name();
     }
-
-    indent_down();
-    f_gen_ << indent() << "}" << endl;
   } else {
     throw "cannot generate const value for " + ttype->get_name();
   }
+
+  if (!is_inline) {
+    f_gen_ << endl;
+  }
 }
 
 void t_rs_generator::render_const_struct(t_type* ttype, t_const_value*) {
   if (((t_struct*)ttype)->is_union()) {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_ << indent() << "unimplemented!()" << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   } else {
-    f_gen_ << indent() << "{" << endl;
+    f_gen_ << "{" << endl;
     indent_up();
     f_gen_ << indent() << "unimplemented!()" << endl;
     indent_down();
-    f_gen_ << indent() << "}" << endl;
+    f_gen_ << indent() << "}";
   }
 }
 
 void t_rs_generator::render_const_list(t_type* ttype, t_const_value* tvalue) {
   t_type* elem_type = ((t_list*)ttype)->get_elem_type();
-  f_gen_ << indent() << "let mut l: Vec<" << to_rust_type(elem_type) << "> = Vec::new();" << endl;
+  f_gen_ << "vec![" << endl;
+  indent_up();
   const vector<t_const_value*>& elems = tvalue->get_list();
   vector<t_const_value*>::const_iterator elem_iter;
   for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    f_gen_ << indent();
     t_const_value* elem_value = (*elem_iter);
-    render_container_const_value("l.push", elem_type, elem_value);
+    render_const_value(elem_type, elem_value);
+    f_gen_ << "," << endl;
   }
-  f_gen_ << indent() << "l" << endl;
+  indent_down();
+  f_gen_ << indent() << "]";
 }
 
 void t_rs_generator::render_const_set(t_type* ttype, t_const_value* tvalue) {
   t_type* elem_type = ((t_set*)ttype)->get_elem_type();
-  f_gen_ << indent() << "let mut s: BTreeSet<" << to_rust_type(elem_type) << "> = BTreeSet::new();" << endl;
+  f_gen_ << "BTreeSet::from([" << endl;
+  indent_up();
   const vector<t_const_value*>& elems = tvalue->get_list();
   vector<t_const_value*>::const_iterator elem_iter;
   for(elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
+    f_gen_ << indent();
     t_const_value* elem_value = (*elem_iter);
-    render_container_const_value("s.insert", elem_type, elem_value);
+    render_const_value(elem_type, elem_value);
+    f_gen_ << "," << endl;
   }
-  f_gen_ << indent() << "s" << endl;
+  indent_down();
+  f_gen_ << indent() << "])";
 }
 
 void t_rs_generator::render_const_map(t_type* ttype, t_const_value* tvalue) {
   t_type* key_type = ((t_map*)ttype)->get_key_type();
   t_type* val_type = ((t_map*)ttype)->get_val_type();
-  f_gen_
-    << indent()
-    << "let mut m: BTreeMap<"
-    << to_rust_type(key_type) << ", " << to_rust_type(val_type)
-    << "> = BTreeMap::new();"
-    << endl;
+  f_gen_ << "BTreeMap::from([" << endl;
+  indent_up();
   const map<t_const_value*, t_const_value*, t_const_value::value_compare>& elems = tvalue->get_map();
   map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator elem_iter;
   for (elem_iter = elems.begin(); elem_iter != elems.end(); ++elem_iter) {
     t_const_value* key_value = elem_iter->first;
     t_const_value* val_value = elem_iter->second;
-    if (get_true_type(key_type)->is_base_type()) {
-      f_gen_ << indent() << "let k = ";
-      render_const_value(key_type, key_value);
-      f_gen_ << ";" << endl;
-    } else {
-      f_gen_ << indent() << "let k = {" << endl;
-      indent_up();
-      render_const_value(key_type, key_value);
-      indent_down();
-      f_gen_ << indent() << "};" << endl;
-    }
-    if (get_true_type(val_type)->is_base_type()) {
-      f_gen_ << indent() << "let v = ";
-      render_const_value(val_type, val_value);
-      f_gen_ << ";" << endl;
-    } else {
-      f_gen_ << indent() << "let v = {" << endl;
-      indent_up();
-      render_const_value(val_type, val_value);
-      indent_down();
-      f_gen_ << indent() << "};" << endl;
-    }
-    f_gen_ <<  indent() << "m.insert(k, v);" << endl;
-  }
-  f_gen_ << indent() << "m" << endl;
-}
 
-void t_rs_generator::render_container_const_value(
-  const string& insert_function,
-  t_type* ttype,
-  t_const_value* tvalue
-) {
-  if (get_true_type(ttype)->is_base_type()) {
-    f_gen_ << indent() << insert_function << "(";
-    render_const_value(ttype, tvalue);
-    f_gen_ << ");" << endl;
-  } else {
-    f_gen_ << indent() << insert_function << "(" << endl;
+    f_gen_ << indent() << "(" << endl;
     indent_up();
-    render_const_value(ttype, tvalue);
+    f_gen_ << indent();
+    render_const_value(key_type, key_value);
+    f_gen_ << "," << endl;
+    f_gen_ << indent();
+    render_const_value(val_type, val_value);
+    f_gen_ << "," << endl;
     indent_down();
-    f_gen_ << indent() << ");" << endl;
+    f_gen_ << indent() << ")," << endl;
   }
+  indent_down();
+  f_gen_ << indent() << "])";
 }
 
 //-----------------------------------------------------------------------------
@@ -1057,9 +1026,6 @@
   render_type_comment(struct_name);
   render_struct_definition(struct_name, tstruct, struct_type);
   render_struct_impl(struct_name, tstruct, struct_type);
-  if (struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION) {
-    render_struct_default_trait_impl(struct_name, tstruct);
-  }
   if (struct_type == t_rs_generator::T_EXCEPTION) {
     render_exception_struct_error_trait_impls(struct_name, tstruct);
   }
@@ -1071,15 +1037,27 @@
   t_rs_generator::e_struct_type struct_type
 ) {
   render_rustdoc((t_doc*) tstruct);
-  f_gen_ << "#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]" << endl;
+
+  const vector<t_field*> members = tstruct->get_sorted_members();
+  vector<t_field*>::const_iterator members_iter;
+  bool need_default = struct_type == t_rs_generator::T_REGULAR || struct_type == t_rs_generator::T_EXCEPTION;
+  for (members_iter = members.begin(); need_default && members_iter != members.end(); ++members_iter) {
+    t_field* member = *members_iter;
+    if (!is_optional(member->get_req())) {
+      need_default = false;
+    }
+  }
+  f_gen_
+    << "#[derive(Clone, Debug"
+    << (need_default ? ", Default" : "")
+    << ", Eq, Hash, Ord, PartialEq, PartialOrd)]"
+    << endl;
   f_gen_ << visibility_qualifier(struct_type) << "struct " << struct_name << " {" << endl;
 
   // render the members
-  vector<t_field*> members = tstruct->get_sorted_members();
   if (!members.empty()) {
     indent_up();
 
-    vector<t_field*>::iterator members_iter;
     for(members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
       t_field* member = (*members_iter);
       t_field::e_req member_req = actual_field_req(member, struct_type);
@@ -1137,49 +1115,6 @@
   f_gen_ << endl;
 }
 
-void t_rs_generator::render_struct_default_trait_impl(const string& struct_name, t_struct* tstruct) {
-  bool has_required_field = false;
-
-  const vector<t_field*>& members = tstruct->get_sorted_members();
-  vector<t_field*>::const_iterator members_iter;
-  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-    t_field* member = *members_iter;
-    if (!is_optional(member->get_req())) {
-      has_required_field = true;
-      break;
-    }
-  }
-
-  if (has_required_field) {
-    return;
-  }
-
-  f_gen_ << "impl Default for " << struct_name << " {" << endl;
-  indent_up();
-  f_gen_ << indent() << "fn default() -> Self {" << endl;
-  indent_up();
-
-  if (members.empty()) {
-    f_gen_ << indent() << struct_name << "{}" << endl;
-  } else {
-    f_gen_ << indent() << struct_name << "{" << endl;
-    indent_up();
-    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-      t_field *member = (*members_iter);
-      string member_name(rust_field_name(member));
-      f_gen_ << indent() << member_name << ": " << opt_in_req_out_value(member->get_type()) << "," << endl;
-    }
-    indent_down();
-    f_gen_ << indent() << "}" << endl;
-  }
-
-  indent_down();
-  f_gen_ << indent() << "}" << endl;
-  indent_down();
-  f_gen_ << "}" << endl;
-  f_gen_ << endl;
-}
-
 void t_rs_generator::render_struct_impl(
   const string& struct_name,
   t_struct* tstruct,
@@ -1616,6 +1551,8 @@
     case t_base_type::TYPE_DOUBLE:
       f_gen_ << indent() << "o_prot.write_double(" + type_var + ".into())?;" << endl;
       return;
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (ttype->is_typedef()) {
     t_typedef* ttypedef = (t_typedef*) ttype;
@@ -1777,29 +1714,35 @@
   f_gen_ << indent() << "}" << endl;
 
   // now read all the fields found
-  f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
-  f_gen_ << indent() << "match field_id {" << endl; // start match
-  indent_up();
-
-  for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
-    t_field* tfield = (*members_iter);
-    f_gen_ << indent() << rust_safe_field_id(tfield->get_key()) << " => {" << endl;
+  // avoid clippy::match_single_binding
+  if (members.empty()) {
+    f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
+  } else {
+    f_gen_ << indent() << "let field_id = field_id(&field_ident)?;" << endl;
+    f_gen_ << indent() << "match field_id {" << endl; // start match
     indent_up();
-    render_type_sync_read("val", tfield->get_type());
-    f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl;
+
+    for (members_iter = members.begin(); members_iter != members.end(); ++members_iter) {
+      t_field* tfield = (*members_iter);
+      f_gen_ << indent() << rust_safe_field_id(tfield->get_key()) << " => {" << endl;
+      indent_up();
+      render_type_sync_read("val", tfield->get_type());
+      f_gen_ << indent() << struct_field_read_temp_variable(tfield) << " = Some(val);" << endl;
+      indent_down();
+      f_gen_ << indent() << "}," << endl;
+    }
+
+    // default case (skip fields)
+    f_gen_ << indent() << "_ => {" << endl;
+    indent_up();
+    f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
     indent_down();
     f_gen_ << indent() << "}," << endl;
+
+    indent_down();
+    f_gen_ << indent() << "};" << endl; // finish match
   }
 
-  // default case (skip fields)
-  f_gen_ << indent() << "_ => {" << endl;
-  indent_up();
-  f_gen_ << indent() << "i_prot.skip(field_ident.field_type)?;" << endl;
-  indent_down();
-  f_gen_ << indent() << "}," << endl;
-
-  indent_down();
-  f_gen_ << indent() << "};" << endl; // finish match
   f_gen_ << indent() << "i_prot.read_field_end()?;" << endl;
   indent_down();
   f_gen_ << indent() << "}" << endl; // finish loop
@@ -1985,6 +1928,8 @@
     case t_base_type::TYPE_DOUBLE:
       f_gen_ << indent() << "let " << type_var << " = OrderedFloat::from(i_prot.read_double()?);" << endl;
       return;
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (ttype->is_typedef()) {
     // FIXME: not a fan of separate `is_boxed` parameter
@@ -3084,6 +3029,8 @@
       return "i64";
     case t_base_type::TYPE_DOUBLE:
       return "OrderedFloat<f64>";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (ttype->is_typedef()) {
     t_typedef* ttypedef = (t_typedef*)ttype;
@@ -3144,6 +3091,8 @@
       return "TType::I64";
     case t_base_type::TYPE_DOUBLE:
       return "TType::Double";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (ttype->is_enum()) {
     return "TType::I32";
@@ -3182,6 +3131,8 @@
       return "Some(0)";
     case t_base_type::TYPE_DOUBLE:
       return "Some(OrderedFloat::from(0.0))";
+    default:
+      throw "compiler error: unhandled type";
     }
 
   } else if (ttype->is_enum() || ttype->is_struct() || ttype->is_xception()) {
diff --git a/compiler/cpp/src/thrift/generate/t_st_generator.cc b/compiler/cpp/src/thrift/generate/t_st_generator.cc
index 109adc7..5edb852 100644
--- a/compiler/cpp/src/thrift/generate/t_st_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_st_generator.cc
@@ -1037,6 +1037,8 @@
       return "TType i64";
     case t_base_type::TYPE_DOUBLE:
       return "TType double";
+    default:
+      throw "compiler error: unhandled type";
     }
   } else if (type->is_enum()) {
     return "TType i32";
diff --git a/compiler/cpp/src/thrift/generate/t_swift_generator.cc b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
index d8eb733..834e31d 100644
--- a/compiler/cpp/src/thrift/generate/t_swift_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_swift_generator.cc
@@ -51,7 +51,7 @@
                     const string& option_string)
     : t_oop_generator(program) {
     update_keywords();
-	
+    
     (void)option_string;
     map<string, string>::const_iterator iter;
 
@@ -292,7 +292,7 @@
 
 protected:
   std::set<std::string> lang_keywords() const override {
-	  return {};
+      return {};
   }
 };
 
@@ -3136,6 +3136,8 @@
           return result + "i64";
         case t_base_type::TYPE_DOUBLE:
           return result + "double";
+        default:
+          throw "compiler error: unhandled type";
       }
     } else if (type->is_enum()) {
       return result + "i32";
@@ -3168,6 +3170,8 @@
           return result + "I64";
         case t_base_type::TYPE_DOUBLE:
           return result + "DOUBLE";
+        default:
+          throw "compiler error: unhandled type";
       }
     } else if (type->is_enum()) {
       return result + "I32";
diff --git a/compiler/cpp/src/thrift/generate/t_xml_generator.cc b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
index b669293..220d50c 100644
--- a/compiler/cpp/src/thrift/generate/t_xml_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_xml_generator.cc
@@ -94,7 +94,7 @@
   void generate_service(t_service* tservice) override;
   void generate_struct(t_struct* tstruct) override;
 
-  void generate_annotations(std::map<std::string, std::string> annotations);
+  void generate_annotations(std::map<std::string, std::vector<std::string>> annotations);
 
 private:
   bool should_merge_includes_;
@@ -165,17 +165,23 @@
 string t_xml_generator::target_namespace(t_program* program) {
   std::map<std::string, std::string> map;
   std::map<std::string, std::string>::iterator iter;
-  map = program->get_namespace_annotations("xml");
-  if ((iter = map.find("targetNamespace")) != map.end()) {
-    return iter->second;
+  std::map<std::string, std::vector<std::string>> annotations;
+  std::map<std::string, std::vector<std::string>>::iterator annotations_iter;
+  annotations = program->get_namespace_annotations("xml");
+  if ((annotations_iter = annotations.find("targetNamespace")) != annotations.end()) {
+    if (!annotations_iter->second.empty()) {
+      return annotations_iter->second.back();
+    }
   }
   map = program->get_namespaces();
   if ((iter = map.find("xml")) != map.end()) {
     return default_ns_prefix + iter->second;
   }
-  map = program->get_namespace_annotations("*");
-  if ((iter = map.find("xml.targetNamespace")) != map.end()) {
-    return iter->second;
+  annotations = program->get_namespace_annotations("*");
+  if ((annotations_iter = annotations.find("xml.targetNamespace")) != annotations.end()) {
+    if (!annotations_iter->second.empty()) {
+      return annotations_iter->second.back();
+    }
   }
   map = program->get_namespaces();
   if ((iter = map.find("*")) != map.end()) {
@@ -432,13 +438,15 @@
 }
 
 void t_xml_generator::generate_annotations(
-    std::map<std::string, std::string> annotations) {
-  std::map<std::string, std::string>::iterator iter;
+    std::map<std::string, std::vector<std::string>> annotations) {
+  std::map<std::string, std::vector<std::string>>::iterator iter;
   for (iter = annotations.begin(); iter != annotations.end(); ++iter) {
-    write_element_start("annotation");
-    write_attribute("key", iter->first);
-    write_attribute("value", iter->second);
-    write_element_end();
+    for (auto& annotations_value : iter->second) {
+      write_element_start("annotation");
+      write_attribute("key", iter->first);
+      write_attribute("value", annotations_value);
+      write_element_end();
+    }
   }
 }
 
diff --git a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
index a10f059..15ede75 100644
--- a/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
+++ b/compiler/cpp/src/thrift/generate/t_xsd_generator.cc
@@ -262,10 +262,10 @@
   f_xsd_.open(f_xsd_name.c_str());
 
   string ns = program_->get_namespace("xsd");
-  const std::map<std::string, std::string> annot = program_->get_namespace_annotations("xsd");
-  const std::map<std::string, std::string>::const_iterator uri = annot.find("uri");
-  if (uri != annot.end()) {
-    ns = uri->second;
+  const std::map<std::string, std::vector<std::string>> annot = program_->get_namespace_annotations("xsd");
+  const std::map<std::string, std::vector<std::string>>::const_iterator uri = annot.find("uri");
+  if (uri != annot.end() && !uri->second.empty()) {
+    ns = uri->second.back();
   }
   if (ns.size() > 0) {
     ns = " targetNamespace=\"" + ns + "\" xmlns=\"" + ns + "\" "
diff --git a/compiler/cpp/src/thrift/generate/validator_parser.cc b/compiler/cpp/src/thrift/generate/validator_parser.cc
new file mode 100644
index 0000000..84261fe
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/validator_parser.cc
@@ -0,0 +1,550 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
+ * This file is programmatically sanitized for style:
+ * astyle --style=1tbs -f -p -H -j -U t_validator_parser.cc
+ *
+ * The output of astyle should not be taken unquestioningly, but it is a good
+ * guide for ensuring uniformity and readability.
+ */
+
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include "thrift/generate/t_generator.h"
+#include "thrift/generate/validator_parser.h"
+#include "thrift/platform.h"
+#include "thrift/version.h"
+#include <algorithm>
+#include <clocale>
+#include <sstream>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+const char* list_delimiter = "[], ";
+
+std::vector<validation_rule*> validation_parser::parse_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  if (type->is_typedef()) {
+    type = type->get_true_type();
+  }
+  if (type->is_enum()) {
+    return parse_enum_field(type, annotations);
+  } else if (type->is_base_type()) {
+    t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
+    switch (tbase) {
+    case t_base_type::TYPE_UUID:
+    case t_base_type::TYPE_VOID:
+      break;
+    case t_base_type::TYPE_I8:
+    case t_base_type::TYPE_I16:
+    case t_base_type::TYPE_I32:
+    case t_base_type::TYPE_I64:
+      return parse_integer_field(type, annotations);
+    case t_base_type::TYPE_DOUBLE:
+      return parse_double_field(type, annotations);
+    case t_base_type::TYPE_STRING:
+      return parse_string_field(type, annotations);
+    case t_base_type::TYPE_BOOL:
+      return parse_bool_field(type, annotations);
+    }
+  } else if (type->is_list()) {
+    return parse_list_field(type, annotations);
+  } else if (type->is_set()) {
+    return parse_set_field(type, annotations);
+  } else if (type->is_map()) {
+    return parse_map_field(type, annotations);
+  } else if (type->is_struct()) {
+    if (((t_struct*)type)->is_union()) {
+      return parse_union_field(type, annotations);
+    }
+    return parse_struct_field(type, annotations);
+  } else if (type->is_xception()) {
+    return parse_xception_field(type, annotations);
+  }
+  throw "validator error: unsupported type: " + type->get_name();
+}
+
+std::vector<validation_rule*> validation_parser::parse_bool_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_bool_rule(rules, "vt.const", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_enum_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  std::vector<validation_rule*> rules;
+  add_bool_rule(rules, "vt.defined_only", annotations);
+  add_enum_list_rule(rules, (t_enum*)type, "vt.in", annotations);
+  add_enum_list_rule(rules, (t_enum*)type, "vt.not_in", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_double_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_double_rule(rules, "vt.lt", annotations);
+  add_double_rule(rules, "vt.le", annotations);
+  add_double_rule(rules, "vt.gt", annotations);
+  add_double_rule(rules, "vt.ge", annotations);
+  add_double_list_rule(rules, "vt.in", annotations);
+  add_double_list_rule(rules, "vt.not_in", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_integer_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_integer_rule(rules, "vt.lt", annotations);
+  add_integer_rule(rules, "vt.le", annotations);
+  add_integer_rule(rules, "vt.gt", annotations);
+  add_integer_rule(rules, "vt.ge", annotations);
+  add_integer_list_rule(rules, "vt.in", annotations);
+  add_integer_list_rule(rules, "vt.not_in", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_string_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_string_rule(rules, "vt.const", annotations);
+  add_integer_rule(rules, "vt.min_size", annotations);
+  add_integer_rule(rules, "vt.max_size", annotations);
+  add_string_rule(rules, "vt.pattern", annotations);
+  add_string_rule(rules, "vt.prefix", annotations);
+  add_string_rule(rules, "vt.suffix", annotations);
+  add_string_rule(rules, "vt.contains", annotations);
+  add_string_rule(rules, "vt.not_contains", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_set_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  return parse_list_field(type, annotations);
+}
+
+std::vector<validation_rule*> validation_parser::parse_list_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_integer_rule(rules, "vt.min_size", annotations);
+  add_integer_rule(rules, "vt.max_size", annotations);
+  std::string elem_prefix("vt.elem");
+  std::map<std::string, std::vector<std::string>> elem_annotations;
+  for (auto it = annotations.begin(); it != annotations.end(); it++) {
+    if (it->first.compare(0, elem_prefix.size(), elem_prefix) == 0) {
+      std::string elem_key = "vt" + it->first.substr(elem_prefix.size());
+      elem_annotations[elem_key] = it->second;
+    }
+  }
+  std::vector<validation_rule*> elem_rules;
+  if (type->is_list()) {
+    elem_rules = parse_field(((t_list*)type)->get_elem_type(), elem_annotations);
+  } else if (type->is_set()) {
+    elem_rules = parse_field(((t_set*)type)->get_elem_type(), elem_annotations);
+  }
+  for (auto it = elem_rules.begin(); it != elem_rules.end(); it++) {
+    validation_rule* rule = new validation_rule(elem_prefix, *it);
+    rules.push_back(rule);
+  }
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_map_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  std::vector<validation_rule*> rules;
+  add_integer_rule(rules, "vt.min_size", annotations);
+  add_integer_rule(rules, "vt.max_size", annotations);
+  std::string key_prefix("vt.key");
+  std::map<std::string, std::vector<std::string>> key_annotations;
+  for (auto it = annotations.begin(); it != annotations.end(); it++) {
+    if (it->first.compare(0, key_prefix.size(), key_prefix) == 0) {
+      std::string key_key = "vt" + it->first.substr(key_prefix.size());
+      key_annotations[key_key] = it->second;
+    }
+  }
+  std::vector<validation_rule*> key_rules;
+  key_rules = parse_field(((t_map*)type)->get_key_type(), key_annotations);
+  for (auto it = key_rules.begin(); it != key_rules.end(); it++) {
+    validation_rule* rule = new validation_rule(key_prefix, *it);
+    rules.push_back(rule);
+  }
+
+  std::string value_prefix("vt.value");
+  std::map<std::string, std::vector<std::string>> value_annotations;
+  for (auto it = annotations.begin(); it != annotations.end(); it++) {
+    if (it->first.compare(0, value_prefix.size(), value_prefix) == 0) {
+      std::string value_key = "vt" + it->first.substr(value_prefix.size());
+      value_annotations[value_key] = it->second;
+    }
+  }
+  std::vector<validation_rule*> value_rules;
+  value_rules = parse_field(((t_map*)type)->get_val_type(), value_annotations);
+  for (auto it = value_rules.begin(); it != value_rules.end(); it++) {
+    validation_rule* rule = new validation_rule(value_prefix, *it);
+    rules.push_back(rule);
+  }
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_struct_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  (void)type;
+  std::vector<validation_rule*> rules;
+  add_bool_rule(rules, "vt.skip", annotations);
+  return rules;
+}
+
+std::vector<validation_rule*> validation_parser::parse_xception_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  return parse_struct_field(type, annotations);
+}
+
+std::vector<validation_rule*> validation_parser::parse_union_field(
+    t_type* type,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  return parse_struct_field(type, annotations);
+}
+
+bool validation_parser::is_reference_field(std::string value) {
+  if (value[0] != '$') {
+    return false;
+  }
+  value.erase(value.begin());
+  t_field* field = this->reference->get_field_by_name(value);
+  return field != nullptr;
+}
+
+bool validation_parser::is_validation_function(std::string value) {
+  if (value[0] != '@') {
+    return false;
+  }
+  return true;
+}
+
+void validation_parser::add_bool_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      validation_rule* rule = new validation_rule(key);
+      validation_value* value;
+      if (is_reference_field(annotation_value)) {
+        t_field* field = get_referenced_field(annotation_value);
+        value = new validation_value(field);
+      } else {
+        bool constant;
+        std::istringstream(it->second.back()) >> std::boolalpha >> constant;
+        value = new validation_value(constant);
+      }
+      rule->append_value(value);
+      rules.push_back(rule);
+    }
+  }
+}
+
+void validation_parser::add_double_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      if (annotation_value.size() == 0) {
+        continue;
+      }
+      validation_rule* rule = new validation_rule(key);
+      validation_value* value;
+      if (is_validation_function(annotation_value)) {
+        validation_value::validation_function* function = get_validation_function(annotation_value);
+        value = new validation_value(function);
+      } else if (is_reference_field(annotation_value)) {
+        t_field* field = get_referenced_field(annotation_value);
+        value = new validation_value(field);
+      } else {
+        double constant = std::stod(annotation_value);
+        value = new validation_value(constant);
+      }
+      rule->append_value(value);
+      rules.push_back(rule);
+    }
+  }
+}
+
+void validation_parser::add_enum_list_rule(
+    std::vector<validation_rule*>& rules,
+    t_enum* enum_,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      if (annotation_value.size() == 0) {
+        continue;
+      }
+      validation_rule* rule = new validation_rule(key);
+      if (annotation_value[0] == '[') {
+        validation_value* value;
+        char* str = strdup(annotation_value.c_str());
+        char* pch = strtok(str, list_delimiter);
+        std::string val;
+        while (pch != NULL) {
+          std::string temp(pch);
+          if (is_validation_function(temp)) {
+            validation_value::validation_function* function = get_validation_function(temp);
+            value = new validation_value(function);
+          } else if (is_reference_field(temp)) {
+            t_field* field = get_referenced_field(temp);
+            value = new validation_value(field);
+          } else if (std::stringstream(temp) >> val) {
+            std::string::size_type dot = val.rfind('.');
+            if (dot != std::string::npos) {
+              val = val.substr(dot + 1);
+            }
+            t_enum_value* enum_val = enum_->get_constant_by_name(val);
+            value = new validation_value(enum_val);
+          } else {
+            delete rule;
+            throw "validator error: validation double list parse failed: " + temp;
+          }
+          rule->append_value(value);
+          pch = strtok(NULL, list_delimiter);
+        }
+      } else {
+        validation_value* value;
+        std::string val = annotation_value;
+        std::string::size_type dot = val.rfind('.');
+        if (dot != std::string::npos) {
+          val = val.substr(dot + 1);
+        }
+        t_enum_value* enum_val = enum_->get_constant_by_name(val);
+        value = new validation_value(enum_val);
+        rule->append_value(value);
+      }
+      rules.push_back(rule);
+    }
+  }
+}
+
+void validation_parser::add_double_list_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  std::map<std::string, std::vector<std::string>> double_rules;
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      if (annotation_value.size() == 0) {
+        continue;
+      }
+      if (annotation_value[0] == '[') {
+        validation_rule* rule = new validation_rule(key);
+        validation_value* value;
+        char* str = strdup(annotation_value.c_str());
+        char* pch = strtok(str, list_delimiter);
+        double val;
+        while (pch != NULL) {
+          std::string temp(pch);
+          if (is_validation_function(temp)) {
+            validation_value::validation_function* function = get_validation_function(temp);
+            value = new validation_value(function);
+          } else if (is_reference_field(temp)) {
+            t_field* field = get_referenced_field(temp);
+            value = new validation_value(field);
+          } else if (std::stringstream(temp) >> val) {
+            value = new validation_value(val);
+          } else {
+            delete rule;
+            throw "validator error: validation double list parse failed: " + temp;
+          }
+          rule->append_value(value);
+          pch = strtok(NULL, list_delimiter);
+        }
+        rules.push_back(rule);
+      } else {
+        double_rules[key].push_back(annotation_value);
+      }
+    }
+  }
+  if (double_rules[key].size() > 0) {
+    add_double_rule(rules, key, double_rules);
+  }
+}
+
+void validation_parser::add_integer_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      if (annotation_value.size() == 0) {
+        continue;
+      }
+      validation_rule* rule = new validation_rule(key);
+      validation_value* value;
+      if (is_reference_field(annotation_value)) {
+        t_field* field = get_referenced_field(annotation_value);
+        value = new validation_value(field);
+      } else if (is_validation_function(annotation_value)) {
+        validation_value::validation_function* function = get_validation_function(annotation_value);
+        value = new validation_value(function);
+      } else {
+        int64_t constant = std::stoll(annotation_value);
+        value = new validation_value(constant);
+      }
+      rule->append_value(value);
+      rules.push_back(rule);
+    }
+  }
+}
+
+void validation_parser::add_integer_list_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  std::map<std::string, std::vector<std::string>> integer_rules;
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      if (annotation_value.size() == 0) {
+        continue;
+      }
+      if (annotation_value[0] == '[') {
+        validation_rule* rule = new validation_rule(key);
+        validation_value* value;
+        char* str = strdup(annotation_value.c_str());
+        char* pch = strtok(str, list_delimiter);
+        int64_t val;
+        while (pch != NULL) {
+          std::string temp(pch);
+          if (is_validation_function(temp)) {
+            validation_value::validation_function* function = get_validation_function(temp);
+            value = new validation_value(function);
+          } else if (is_reference_field(temp)) {
+            t_field* field = get_referenced_field(temp);
+            value = new validation_value(field);
+          } else if (std::stringstream(temp) >> val) {
+            value = new validation_value(val);
+          } else {
+            delete rule;
+            throw "validator error: validation integer list parse failed: " + temp;
+          }
+          rule->append_value(value);
+          pch = strtok(NULL, list_delimiter);
+        }
+        rules.push_back(rule);
+      } else {
+        integer_rules[key].push_back(annotation_value);
+      }
+    }
+  }
+  if (integer_rules[key].size() > 0) {
+    add_integer_rule(rules, key, integer_rules);
+  }
+}
+
+void validation_parser::add_string_rule(
+    std::vector<validation_rule*>& rules,
+    std::string key,
+    std::map<std::string, std::vector<std::string>>& annotations) {
+  auto it = annotations.find(key);
+  if (it != annotations.end() && !it->second.empty()) {
+    for (auto& annotation_value : it->second) {
+      validation_rule* rule = new validation_rule(key);
+      validation_value* value;
+      if (is_reference_field(annotation_value)) {
+        t_field* field = get_referenced_field(annotation_value);
+        value = new validation_value(field);
+      } else {
+        value = new validation_value(annotation_value);
+      }
+      rule->append_value(value);
+      rules.push_back(rule);
+    }
+  }
+}
+
+t_field* validation_parser::get_referenced_field(std::string annotation_value) {
+  annotation_value.erase(annotation_value.begin());
+  return reference->get_field_by_name(annotation_value);
+}
+
+validation_value::validation_function* validation_parser::get_validation_function(
+    std::string annotation_value) {
+  std::string value = annotation_value;
+  value.erase(value.begin());
+  validation_value::validation_function* function = new validation_value::validation_function;
+
+  size_t name_end = value.find_first_of('(');
+  if (name_end >= value.size()) {
+    delete function;
+    throw "validator error: validation function parse failed: " + annotation_value;
+  }
+  function->name = value.substr(0, name_end);
+  value.erase(0, name_end + 1); // name(
+
+  if (function->name == "len") {
+    size_t argument_end = value.find_first_of(')');
+    if (argument_end >= value.size()) {
+      delete function;
+      throw "validator error: validation function parse failed: " + annotation_value;
+    }
+    std::string argument = value.substr(0, argument_end);
+    if (argument.size() > 0 && argument[0] == '$') {
+      t_field* field = get_referenced_field(argument);
+      validation_value* value = new validation_value(field);
+      function->arguments.push_back(value);
+    } else {
+      delete function;
+      throw "validator error: validation function parse failed, unrecognized argument: "
+          + annotation_value;
+    }
+  } else {
+    delete function;
+    throw "validator error: validation function parse failed, function not supported: "
+        + annotation_value;
+  }
+  return function;
+}
\ No newline at end of file
diff --git a/compiler/cpp/src/thrift/generate/validator_parser.h b/compiler/cpp/src/thrift/generate/validator_parser.h
new file mode 100644
index 0000000..5ae8900
--- /dev/null
+++ b/compiler/cpp/src/thrift/generate/validator_parser.h
@@ -0,0 +1,208 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 T_VALIDATOR_GENERATOR_H
+#define T_VALIDATOR_GENERATOR_H
+
+#include "thrift/generate/t_generator.h"
+#include <fstream>
+#include <iostream>
+#include <limits>
+#include <string>
+#include <vector>
+
+class validation_value {
+public:
+  struct validation_function {
+  public:
+    std::string name;
+    std::vector<validation_value*> arguments;
+  };
+
+  enum validation_value_type {
+    VV_INTEGER,
+    VV_DOUBLE,
+    VV_BOOL,
+    VV_ENUM,
+    VV_STRING,
+    VV_FUNCTION,
+    VV_FIELD_REFERENCE,
+    VV_UNKNOWN
+  };
+
+  validation_value() : val_type(VV_UNKNOWN) {}
+  validation_value(const int64_t val) : int_val(val), val_type(VV_INTEGER) {}
+  validation_value(const double val) : double_val(val), val_type(VV_DOUBLE) {}
+  validation_value(const bool val) : bool_val(val), val_type(VV_BOOL) {}
+  validation_value(t_enum_value* val) : enum_val(val), val_type(VV_ENUM) {}
+  validation_value(const std::string val) : string_val(val), val_type(VV_STRING) {}
+  validation_value(validation_function* val) : function_val(val), val_type(VV_FUNCTION) {}
+  validation_value(t_field* val) : field_reference_val(val), val_type(VV_FIELD_REFERENCE) {}
+
+  void set_int(const int64_t val) {
+    int_val = val;
+    val_type = VV_INTEGER;
+  }
+  int64_t get_int() const { return int_val; };
+
+  void set_double(const double val) {
+    double_val = val;
+    val_type = VV_DOUBLE;
+  }
+  double get_double() { return double_val; };
+
+  void set_bool(const bool val) {
+    bool_val = val;
+    val_type = VV_BOOL;
+  }
+  bool get_bool() const { return bool_val; };
+
+  void set_enum(t_enum_value* val) {
+    enum_val = val;
+    val_type = VV_ENUM;
+  }
+  t_enum_value* get_enum() const { return enum_val; };
+
+  void set_string(const std::string val) {
+    string_val = val;
+    val_type = VV_STRING;
+  }
+  std::string get_string() const { return string_val; };
+
+  void set_function(validation_function* val) {
+    function_val = val;
+    val_type = VV_FUNCTION;
+  }
+
+  validation_function* get_function() { return function_val; };
+
+  void set_field_reference(t_field* val) {
+    field_reference_val = val;
+    val_type = VV_FIELD_REFERENCE;
+  }
+  t_field* get_field_reference() const { return field_reference_val; };
+
+  bool is_field_reference() const { return val_type == VV_FIELD_REFERENCE; };
+
+  bool is_validation_function() const { return val_type == VV_FUNCTION; };
+
+  validation_value_type get_type() const { return val_type; };
+
+private:
+  int64_t int_val = 0;
+  double double_val = 0.0;
+  bool bool_val = false;
+  t_enum_value* enum_val = nullptr;
+  std::string string_val;
+  validation_function* function_val = nullptr;
+  t_field* field_reference_val = nullptr;
+
+  validation_value_type val_type;
+};
+
+class validation_rule {
+public:
+  validation_rule(){};
+  validation_rule(std::string name) : name(name){};
+  validation_rule(std::string name, validation_rule* inner) : name(name), inner(inner){};
+
+  std::string get_name() { return name; };
+  void append_value(validation_value* value) { values.push_back(value); }
+  const std::vector<validation_value*>& get_values() { return values; };
+  validation_rule* get_inner() { return inner; };
+
+private:
+  std::string name;
+  std::vector<validation_value*> values;
+  validation_rule* inner = nullptr;
+};
+
+class validation_parser {
+public:
+  validation_parser() {}
+  validation_parser(t_struct* reference) : reference(reference) {}
+  std::vector<validation_rule*> parse_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  void set_reference(t_struct* reference) { this->reference = reference; };
+
+private:
+  std::vector<validation_rule*> parse_bool_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_enum_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_double_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_integer_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_string_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_set_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_list_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_map_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_struct_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_xception_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  std::vector<validation_rule*> parse_union_field(
+      t_type* type,
+      std::map<std::string, std::vector<std::string>>& annotations);
+  bool is_reference_field(std::string value);
+  bool is_validation_function(std::string value);
+  void add_bool_rule(std::vector<validation_rule*>& rules,
+                     std::string key,
+                     std::map<std::string, std::vector<std::string>>& annotations);
+  void add_double_rule(std::vector<validation_rule*>& rules,
+                       std::string key,
+                       std::map<std::string, std::vector<std::string>>& annotations);
+  void add_double_list_rule(std::vector<validation_rule*>& rules,
+                            std::string key,
+                            std::map<std::string, std::vector<std::string>>& annotations);
+  void add_integer_rule(std::vector<validation_rule*>& rules,
+                        std::string key,
+                        std::map<std::string, std::vector<std::string>>& annotations);
+  void add_integer_list_rule(std::vector<validation_rule*>& rules,
+                             std::string key,
+                             std::map<std::string, std::vector<std::string>>& annotations);
+  void add_string_rule(std::vector<validation_rule*>& rules,
+                       std::string key,
+                       std::map<std::string, std::vector<std::string>>& annotations);
+  void add_enum_list_rule(std::vector<validation_rule*>& rules,
+                                t_enum* enum_,
+                                std::string key,
+                                std::map<std::string, std::vector<std::string>>& annotations);
+  t_field* get_referenced_field(std::string annotation_value);
+  validation_value::validation_function* get_validation_function(std::string annotation_value);
+  t_struct* reference = nullptr;
+};
+
+#endif
diff --git a/compiler/cpp/src/thrift/main.cc b/compiler/cpp/src/thrift/main.cc
index c5aa65f..a07f429 100644
--- a/compiler/cpp/src/thrift/main.cc
+++ b/compiler/cpp/src/thrift/main.cc
@@ -738,6 +738,12 @@
         throw "type error: const \"" + name + "\" was declared as string";
       }
       break;
+    case t_base_type::TYPE_UUID:
+      if (value->get_type() != t_const_value::CV_STRING) {
+        throw "type error: const \"" + name + "\" was declared as uuid";
+      }
+      value->get_uuid(); // validates constant
+      break;
     case t_base_type::TYPE_BOOL:
       if (value->get_type() != t_const_value::CV_INTEGER) {
         throw "type error: const \"" + name + "\" was declared as bool";
diff --git a/compiler/cpp/src/thrift/parse/t_base_type.h b/compiler/cpp/src/thrift/parse/t_base_type.h
index 5676f04..4e5228d 100644
--- a/compiler/cpp/src/thrift/parse/t_base_type.h
+++ b/compiler/cpp/src/thrift/parse/t_base_type.h
@@ -36,6 +36,7 @@
   enum t_base {
     TYPE_VOID,
     TYPE_STRING,
+    TYPE_UUID,
     TYPE_BOOL,
     TYPE_I8,
     TYPE_I16,
@@ -55,6 +56,8 @@
 
   bool is_bool() const override { return base_ == TYPE_BOOL; }
 
+  bool is_uuid() const override { return base_ == TYPE_UUID; }
+
   void set_binary(bool val) { binary_ = val; }
 
   bool is_binary() const override { return binary_ && (base_ == TYPE_STRING); }
@@ -69,6 +72,9 @@
     case TYPE_STRING:
       return "string";
       break;
+    case TYPE_UUID:
+      return "uuid";
+      break;
     case TYPE_BOOL:
       return "bool";
       break;
diff --git a/compiler/cpp/src/thrift/parse/t_const_value.h b/compiler/cpp/src/thrift/parse/t_const_value.h
index 5b8156f..452a90c 100644
--- a/compiler/cpp/src/thrift/parse/t_const_value.h
+++ b/compiler/cpp/src/thrift/parse/t_const_value.h
@@ -85,6 +85,17 @@
     }
   }
 
+  void set_uuid(std::string val) {
+    validate_uuid(val);
+    valType_ = CV_STRING;
+    stringVal_ = val;
+  }
+
+  std::string get_uuid() const {
+    validate_uuid(stringVal_);
+    return stringVal_;
+  }
+
   void set_double(double val) {
     valType_ = CV_DOUBLE;
     doubleVal_ = val;
@@ -199,6 +210,34 @@
   t_enum* enum_;
 
   t_const_value_type valType_;
+  
+  void validate_uuid(std::string uuid) const {
+    bool valid = (uuid.length() == 36);
+    const std::string HEXCHARS = std::string("0123456789ABCDEFabcdef");
+
+    // canonical format "01234567-9012-4567-9012-456789012345" expected
+    for( size_t i = 0; valid && (i < uuid.length()); ++i) {
+      switch(i) {
+        case 8:
+        case 13:
+        case 18:
+        case 23:
+          if(uuid[i] != '-') {
+            valid = false;
+          }			  
+          break;
+        default:
+          if(HEXCHARS.find(uuid[i]) == std::string::npos) {
+            valid = false;
+          }			  
+          break;
+      }        
+    }
+
+    if( ! valid) {
+      throw "invalid uuid " + uuid;
+    }
+  }
 };
 
 #endif
diff --git a/compiler/cpp/src/thrift/parse/t_enum_value.h b/compiler/cpp/src/thrift/parse/t_enum_value.h
index 70eee86..c6558d7 100644
--- a/compiler/cpp/src/thrift/parse/t_enum_value.h
+++ b/compiler/cpp/src/thrift/parse/t_enum_value.h
@@ -20,9 +20,9 @@
 #ifndef T_ENUM_VALUE_H
 #define T_ENUM_VALUE_H
 
+#include "thrift/parse/t_doc.h"
 #include <map>
 #include <string>
-#include "thrift/parse/t_doc.h"
 
 /**
  * A constant. These are used inside of enum definitions. Constants are just
@@ -40,7 +40,7 @@
 
   int get_value() const { return value_; }
 
-  std::map<std::string, std::string> annotations_;
+  std::map<std::string, std::vector<std::string>> annotations_;
 
 private:
   std::string name_;
diff --git a/compiler/cpp/src/thrift/parse/t_field.h b/compiler/cpp/src/thrift/parse/t_field.h
index f0a607d..928fdcf 100644
--- a/compiler/cpp/src/thrift/parse/t_field.h
+++ b/compiler/cpp/src/thrift/parse/t_field.h
@@ -21,8 +21,8 @@
 #define T_FIELD_H
 
 #include <map>
-#include <string>
 #include <sstream>
+#include <string>
 
 #include "thrift/parse/t_doc.h"
 #include "thrift/parse/t_type.h"
@@ -106,7 +106,7 @@
     }
   };
 
-  std::map<std::string, std::string> annotations_;
+  std::map<std::string, std::vector<std::string>> annotations_;
 
   bool get_reference() const { return reference_; }
 
diff --git a/compiler/cpp/src/thrift/parse/t_function.h b/compiler/cpp/src/thrift/parse/t_function.h
index d30c8a4..bc0ae46 100644
--- a/compiler/cpp/src/thrift/parse/t_function.h
+++ b/compiler/cpp/src/thrift/parse/t_function.h
@@ -20,10 +20,10 @@
 #ifndef T_FUNCTION_H
 #define T_FUNCTION_H
 
-#include <string>
-#include "thrift/parse/t_type.h"
-#include "thrift/parse/t_struct.h"
 #include "thrift/parse/t_doc.h"
+#include "thrift/parse/t_struct.h"
+#include "thrift/parse/t_type.h"
+#include <string>
 
 /**
  * Representation of a function. Key parts are return type, function name,
@@ -79,7 +79,7 @@
 
   bool is_oneway() const { return oneway_; }
 
-  std::map<std::string, std::string> annotations_;
+  std::map<std::string, std::vector<std::string>> annotations_;
 
 private:
   t_type* returntype_;
diff --git a/compiler/cpp/src/thrift/parse/t_program.h b/compiler/cpp/src/thrift/parse/t_program.h
index b6b1332..23c6463 100644
--- a/compiler/cpp/src/thrift/parse/t_program.h
+++ b/compiler/cpp/src/thrift/parse/t_program.h
@@ -331,20 +331,20 @@
      return namespaces_;
   }
 
-  void set_namespace_annotations(std::string language, std::map<std::string, std::string> annotations) {
+  void set_namespace_annotations(std::string language, std::map<std::string, std::vector<std::string>> annotations) {
     namespace_annotations_[language] = annotations;
   }
 
-  const std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) const {
+  const std::map<std::string, std::vector<std::string>>& get_namespace_annotations(const std::string& language) const {
     auto it = namespace_annotations_.find(language);
     if (namespace_annotations_.end() != it) {
       return it->second;
     }
-    static const std::map<std::string, std::string> emptyMap;
+    static const std::map<std::string, std::vector<std::string>> emptyMap;
     return emptyMap;
   }
 
-  std::map<std::string, std::string>& get_namespace_annotations(const std::string& language) {
+  std::map<std::string, std::vector<std::string>>& get_namespace_annotations(const std::string& language) {
     return namespace_annotations_[language];
   }
 
@@ -400,7 +400,7 @@
   std::map<std::string, std::string> namespaces_;
 
   // Annotations for dynamic namespaces
-  std::map<std::string, std::map<std::string, std::string> > namespace_annotations_;
+  std::map<std::string, std::map<std::string, std::vector<std::string>>> namespace_annotations_;
 
   // C++ extra includes
   std::vector<std::string> cpp_includes_;
diff --git a/compiler/cpp/src/thrift/parse/t_scope.h b/compiler/cpp/src/thrift/parse/t_scope.h
index 17a360f..71ab4f3 100644
--- a/compiler/cpp/src/thrift/parse/t_scope.h
+++ b/compiler/cpp/src/thrift/parse/t_scope.h
@@ -166,6 +166,9 @@
           case t_base_type::TYPE_STRING:
             const_val->set_string(constant->get_value()->get_string());
             break;
+          case t_base_type::TYPE_UUID:
+            const_val->set_uuid(constant->get_value()->get_uuid());
+            break;
           case t_base_type::TYPE_DOUBLE:
             const_val->set_double(constant->get_value()->get_double());
             break;
diff --git a/compiler/cpp/src/thrift/parse/t_type.h b/compiler/cpp/src/thrift/parse/t_type.h
index 63f99ed..f408242 100644
--- a/compiler/cpp/src/thrift/parse/t_type.h
+++ b/compiler/cpp/src/thrift/parse/t_type.h
@@ -20,11 +20,11 @@
 #ifndef T_TYPE_H
 #define T_TYPE_H
 
-#include <string>
-#include <map>
-#include <cstring>
-#include <stdint.h>
 #include "thrift/parse/t_doc.h"
+#include <cstring>
+#include <map>
+#include <stdint.h>
+#include <string>
 
 class t_program;
 
@@ -47,6 +47,7 @@
   virtual bool is_void() const { return false; }
   virtual bool is_base_type() const { return false; }
   virtual bool is_string() const { return false; }
+  virtual bool is_uuid() const { return false; }
   virtual bool is_binary() const { return false; }
   virtual bool is_bool() const { return false; }
   virtual bool is_typedef() const { return false; }
@@ -82,7 +83,7 @@
     return rv;
   }
 
-  std::map<std::string, std::string> annotations_;
+  std::map<std::string, std::vector<std::string>> annotations_;
 
 protected:
   t_type() : program_(nullptr) { ; }
diff --git a/compiler/cpp/src/thrift/thriftl.ll b/compiler/cpp/src/thrift/thriftl.ll
index 810a983..45c5926 100644
--- a/compiler/cpp/src/thrift/thriftl.ll
+++ b/compiler/cpp/src/thrift/thriftl.ll
@@ -76,17 +76,17 @@
 #include "thrift/thrifty.hh"
 #endif
 
-void integer_overflow(char* text) {
+void integer_overflow(const char* text) {
   yyerror("This integer is too big: \"%s\"\n", text);
   exit(1);
 }
 
-void unexpected_token(char* text) {
+void unexpected_token(const char* text) {
   yyerror("Unexpected token in input: \"%s\"\n", text);
   exit(1);
 }
 
-void error_no_longer_supported(char* text, char* replace_with) {
+void error_no_longer_supported(const char* text, const char* replace_with) {
   yyerror("\"%s\" is no longer supported, use \"%s\" instead. Line %d\n", text, replace_with, yylineno);
   exit(1);
 }
@@ -209,29 +209,16 @@
 "true"               { yylval.iconst=1; return tok_int_constant; }
 
 "namespace"          { return tok_namespace;            }
-"cpp_namespace"      { error_unsupported_namespace_decl("cpp"); /* do nothing */ }
 "cpp_include"        { return tok_cpp_include;          }
 "cpp_type"           { return tok_cpp_type;             }
-"java_package"       { error_unsupported_namespace_decl("java_package", "java"); /* do nothing */ }
-"delphi_namespace"   { error_unsupported_namespace_decl("delphi"); /* do nothing */ }
-"php_namespace"      { error_unsupported_namespace_decl("php"); /* do nothing */ }
-"py_module"          { error_unsupported_namespace_decl("py_module", "py"); /* do nothing */ }
-"perl_package"       { error_unsupported_namespace_decl("perl_package", "perl"); /* do nothing */ }
-"ruby_namespace"     { error_unsupported_namespace_decl("ruby"); /* do nothing */ }
-"smalltalk_category" { error_unsupported_namespace_decl("smalltalk_category", "st"); /* do nothing */ }
-"smalltalk_prefix"   { error_unsupported_namespace_decl("smalltalk_prefix", "st"); /* do nothing */ }
 "xsd_all"            { return tok_xsd_all;              }
 "xsd_optional"       { return tok_xsd_optional;         }
 "xsd_nillable"       { return tok_xsd_nillable;         }
-"xsd_namespace"      { error_unsupported_namespace_decl("xsd"); /* do nothing */ }
 "xsd_attrs"          { return tok_xsd_attrs;            }
 "include"            { return tok_include;              }
 "void"               { return tok_void;                 }
 "bool"               { return tok_bool;                 }
-"byte"               {
-  emit_byte_type_warning();
-  return tok_i8;
-}
+"byte"               { emit_byte_type_warning(); return tok_byte; }
 "i8"                 { return tok_i8;                   }
 "i16"                { return tok_i16;                  }
 "i32"                { return tok_i32;                  }
@@ -239,12 +226,7 @@
 "double"             { return tok_double;               }
 "string"             { return tok_string;               }
 "binary"             { return tok_binary;               }
-"slist" {
-  error_no_longer_supported("slist","string");
-}
-"senum" {
-  error_no_longer_supported("senum","string");
-}
+"uuid"               { return tok_uuid;                 }
 "map"                { return tok_map;                  }
 "list"               { return tok_list;                 }
 "set"                { return tok_set;                  }
@@ -262,7 +244,7 @@
 "optional"           { return tok_optional;             }
 "async" {
   pwarning(0, "\"async\" is deprecated.  It is called \"oneway\" now.\n");
-  return tok_oneway;
+  return tok_async;
 }
 "&"                  { return tok_reference;            }
 
diff --git a/compiler/cpp/src/thrift/thrifty.yy b/compiler/cpp/src/thrift/thrifty.yy
index a062a0e..2d67c1a 100644
--- a/compiler/cpp/src/thrift/thrifty.yy
+++ b/compiler/cpp/src/thrift/thrifty.yy
@@ -97,6 +97,7 @@
   t_function*    tfunction;
   t_field*       tfield;
   char*          dtext;
+  char*          keyword;
   t_field::e_req ereq;
   t_annotation*  tannot;
   t_field_id     tfieldid;
@@ -118,55 +119,58 @@
 /**
  * Header keywords
  */
-%token tok_include
-%token tok_namespace
-%token tok_cpp_include
-%token tok_cpp_type
-%token tok_xsd_all
-%token tok_xsd_optional
-%token tok_xsd_nillable
-%token tok_xsd_attrs
+%token<keyword> tok_include
+%token<keyword> tok_namespace
+%token<keyword> tok_cpp_include
+%token<keyword> tok_cpp_type
+%token<keyword> tok_xsd_all
+%token<keyword> tok_xsd_optional
+%token<keyword> tok_xsd_nillable
+%token<keyword> tok_xsd_attrs
 
 /**
  * Base datatype keywords
  */
-%token tok_void
-%token tok_bool
-%token tok_string
-%token tok_binary
-%token tok_i8
-%token tok_i16
-%token tok_i32
-%token tok_i64
-%token tok_double
+%token<keyword> tok_void
+%token<keyword> tok_bool
+%token<keyword> tok_string
+%token<keyword> tok_binary
+%token<keyword> tok_uuid
+%token<keyword> tok_byte
+%token<keyword> tok_i8
+%token<keyword> tok_i16
+%token<keyword> tok_i32
+%token<keyword> tok_i64
+%token<keyword> tok_double
 
 /**
  * Complex type keywords
  */
-%token tok_map
-%token tok_list
-%token tok_set
+%token<keyword> tok_map
+%token<keyword> tok_list
+%token<keyword> tok_set
 
 /**
  * Function modifiers
  */
-%token tok_oneway
+%token<keyword> tok_oneway
+%token<keyword> tok_async
 
 /**
  * Thrift language keywords
  */
-%token tok_typedef
-%token tok_struct
-%token tok_xception
-%token tok_throws
-%token tok_extends
-%token tok_service
-%token tok_enum
-%token tok_const
-%token tok_required
-%token tok_optional
-%token tok_union
-%token tok_reference
+%token<keyword> tok_typedef
+%token<keyword> tok_struct
+%token<keyword> tok_xception
+%token<keyword> tok_throws
+%token<keyword> tok_extends
+%token<keyword> tok_service
+%token<keyword> tok_enum
+%token<keyword> tok_const
+%token<keyword> tok_required
+%token<keyword> tok_optional
+%token<keyword> tok_union
+%token<keyword> tok_reference
 
 /**
  * Grammar nodes
@@ -192,6 +196,7 @@
 
 %type<tfield>    Field
 %type<tfieldid>  FieldIdentifier
+%type<id>        FieldName
 %type<ereq>      FieldRequiredness
 %type<ttype>     FieldType
 %type<tconstv>   FieldValue
@@ -770,6 +775,10 @@
     {
       $$ = true;
     }
+|  tok_async  // deprecated
+    {
+      $$ = true;
+    }
 |
     {
       $$ = false;
@@ -808,9 +817,9 @@
     }
 
 Field:
-  CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
+  CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference FieldName FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
     {
-      pdebug("tok_int_constant : Field -> FieldType tok_identifier");
+      pdebug("tok_int_constant : Field -> FieldType FieldName");
       if ($2.auto_assigned) {
         pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
         if (g_strict >= 192) {
@@ -841,6 +850,171 @@
       }
     }
 
+FieldName:  // identifiers and everything that could be one if it would not be identified as a different token already and excluding the "xsd*" keywords to follow a FieldName
+  tok_identifier
+    {
+      pdebug("FieldName -> tok_identifier");
+      $$ = $1;
+    }
+| tok_namespace
+    {
+      pdebug("FieldName -> tok_namespace");
+      $$ = strdup("namespace");
+    }
+| tok_cpp_include
+    {
+      pdebug("FieldName -> tok_cpp_include");
+      $$ = strdup("cpp_include");
+    }
+/* see THRIFT-5627 "More consistent syntax for cpp_type" -> activate when this issue is resolved
+| tok_cpp_type
+    {
+      pdebug("FieldName -> tok_cpp_type");
+      $$ = $strdup("cpp_type");
+    }
+*/
+| tok_include
+    {
+      pdebug("FieldName -> tok_include");
+      $$ = strdup("include");
+    }
+| tok_void
+    {
+      pdebug("FieldName -> tok_void");
+      $$ = strdup("void");
+    }
+| tok_bool
+    {
+      pdebug("FieldName -> tok_bool");
+      $$ = strdup("bool");
+    }
+| tok_byte
+    {
+      pdebug("FieldName -> tok_byte");
+      $$ = strdup("byte");
+    }
+| tok_i8
+    {
+      pdebug("FieldName -> tok_i8");
+      $$ = strdup("i8");
+    }
+| tok_i16
+    {
+      pdebug("FieldName -> tok_i16");
+      $$ = strdup("i16");
+    }
+| tok_i32
+    {
+      pdebug("FieldName -> tok_i32");
+      $$ = strdup("i32");
+    }
+| tok_i64
+    {
+      pdebug("FieldName -> tok_i64");
+      $$ = strdup("i64");
+    }
+| tok_double
+    {
+      pdebug("FieldName -> tok_double");
+      $$ = strdup("double");
+    }
+| tok_string
+    {
+      pdebug("FieldName -> tok_string");
+      $$ = strdup("string");
+    }
+| tok_binary
+    {
+      pdebug("FieldName -> tok_binary");
+      $$ = strdup("binary");
+    }
+| tok_uuid
+    {
+      pdebug("FieldName -> tok_uuid");
+      $$ = strdup("uuid");
+    }
+| tok_map
+    {
+      pdebug("FieldName -> tok_map");
+      $$ = strdup("map");
+    }
+| tok_list
+    {
+      pdebug("FieldName -> tok_list");
+      $$ = strdup("list");
+    }
+| tok_set
+    {
+      pdebug("FieldName -> tok_set");
+      $$ = strdup("set");
+    }
+| tok_oneway
+    {
+      pdebug("FieldName -> tok_oneway");
+      $$ = strdup("oneway");
+    }
+| tok_async
+    {
+      pdebug("FieldName -> tok_async");
+      $$ = strdup("async");
+    }
+| tok_typedef
+    {
+      pdebug("FieldName -> tok_typedef");
+      $$ = strdup("typedef");
+    }
+| tok_struct
+    {
+      pdebug("FieldName -> tok_struct");
+      $$ = strdup("struct");
+    }
+| tok_union
+    {
+      pdebug("FieldName -> tok_union");
+      $$ = strdup("union");
+    }
+| tok_xception
+    {
+      pdebug("FieldName -> tok_xception");
+      $$ = strdup("exception");
+    }
+| tok_extends
+    {
+      pdebug("FieldName -> tok_extends");
+      $$ = strdup("extends");
+    }
+| tok_throws
+    {
+      pdebug("FieldName -> tok_throws");
+      $$ = strdup("throws");
+    }
+| tok_service
+    {
+      pdebug("FieldName -> tok_service");
+      $$ = strdup("service");
+    }
+| tok_enum
+    {
+      pdebug("FieldName -> tok_enum");
+      $$ = strdup("enum");
+    }
+| tok_const
+    {
+      pdebug("FieldName -> tok_const");
+      $$ = strdup("const");
+    }
+| tok_required
+    {
+      pdebug("FieldName -> tok_required");
+      $$ = strdup("required");
+    }
+| tok_optional
+    {
+      pdebug("FieldName -> tok_optional");
+      $$ = strdup("optional");
+    }
+  
+  
 FieldIdentifier:
   tok_int_constant ':'
     {
@@ -1002,11 +1176,21 @@
       pdebug("BaseType -> tok_binary");
       $$ = g_type_binary;
     }
+| tok_uuid
+    {
+      pdebug("BaseType -> tok_uuid");
+      $$ = g_type_uuid;
+    }
 | tok_bool
     {
       pdebug("BaseType -> tok_bool");
       $$ = g_type_bool;
     }
+| tok_byte
+    {
+      pdebug("BaseType -> tok_byte");
+      $$ = g_type_i8;  // byte is signed in Thrift, just an alias for i8
+    }
 | tok_i8
     {
       pdebug("BaseType -> tok_i8");
@@ -1081,13 +1265,20 @@
     }
 
 ListType:
-  tok_list '<' FieldType '>' CppType
+  tok_list CppType '<' FieldType '>' CppType   // the second CppType is for compatibility reasons = deprecated
     {
       pdebug("ListType -> tok_list<FieldType>");
-      check_for_list_of_bytes($3);
-      $$ = new t_list($3);
-      if ($5 != nullptr) {
-        ((t_container*)$$)->set_cpp_name(std::string($5));
+      check_for_list_of_bytes($4);
+      $$ = new t_list($4);
+      if ($2 != nullptr) {
+        ((t_container*)$$)->set_cpp_name(std::string($2));
+      }
+      if ($6 != nullptr) {
+        ((t_container*)$$)->set_cpp_name(std::string($6));
+        pwarning(1, "The syntax 'list<type> cpp_type \"c++ type\"' is deprecated. Use 'list cpp_type \"c++ type\" <type>' instead.\n");
+      }
+      if (($2 != nullptr) && ($6 != nullptr)) {
+        pwarning(1, "Two cpp_types clauses at list<%>\n", $2);
       }
     }
 
@@ -1117,7 +1308,7 @@
     {
       pdebug("TypeAnnotationList -> TypeAnnotationList , TypeAnnotation");
       $$ = $1;
-      $$->annotations_[$2->key] = $2->val;
+      $$->annotations_[$2->key].push_back($2->val);
       delete $2;
     }
 |
diff --git a/compiler/cpp/src/thrift/version.h b/compiler/cpp/src/thrift/version.h
index 2a4b925..0905b34 100644
--- a/compiler/cpp/src/thrift/version.h
+++ b/compiler/cpp/src/thrift/version.h
@@ -24,6 +24,6 @@
 #pragma once
 #endif // _MSC_VER
 
-#define THRIFT_VERSION "0.17.0"
+#define THRIFT_VERSION "0.18.0"
 
 #endif // _THRIFT_VERSION_H_
diff --git a/compiler/cpp/test/compiler/Included.thrift b/compiler/cpp/test/compiler/Included.thrift
index ce84ab6..fe039ed 100644
--- a/compiler/cpp/test/compiler/Included.thrift
+++ b/compiler/cpp/test/compiler/Included.thrift
@@ -1,3 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 const string foo = "bar"
 
 struct a_struct {
diff --git a/compiler/cpp/test/compiler/Including.thrift b/compiler/cpp/test/compiler/Including.thrift
index 677af7b..f3c6a6f 100644
--- a/compiler/cpp/test/compiler/Including.thrift
+++ b/compiler/cpp/test/compiler/Including.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "Included.thrift"
 
 const string s = "string"
diff --git a/compiler/cpp/test/compiler/Single.thrift b/compiler/cpp/test/compiler/Single.thrift
index 2ec301f..7ba5f64 100644
--- a/compiler/cpp/test/compiler/Single.thrift
+++ b/compiler/cpp/test/compiler/Single.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 const string foo = "bar"
diff --git a/compiler/cpp/test/keyword-samples/const1_return.thrift b/compiler/cpp/test/keyword-samples/const1_return.thrift
index 735e4ac..f75f980 100644
--- a/compiler/cpp/test/keyword-samples/const1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/const1_return.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 const bool return = 0
diff --git a/compiler/cpp/test/keyword-samples/enum1_return.thrift b/compiler/cpp/test/keyword-samples/enum1_return.thrift
index 6d834e1..b3755e0 100644
--- a/compiler/cpp/test/keyword-samples/enum1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/enum1_return.thrift
@@ -1,2 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 enum return {
 }
diff --git a/compiler/cpp/test/keyword-samples/enum2_return.thrift b/compiler/cpp/test/keyword-samples/enum2_return.thrift
index a2caa8e..1c26cc8 100644
--- a/compiler/cpp/test/keyword-samples/enum2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/enum2_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 enum enum_name {
   return
 }
diff --git a/compiler/cpp/test/keyword-samples/exception1_return.thrift b/compiler/cpp/test/keyword-samples/exception1_return.thrift
index eadb338..d89d9e8 100644
--- a/compiler/cpp/test/keyword-samples/exception1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/exception1_return.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 exception return {}
diff --git a/compiler/cpp/test/keyword-samples/exception2_return.thrift b/compiler/cpp/test/keyword-samples/exception2_return.thrift
index 493c352..e1289ed 100644
--- a/compiler/cpp/test/keyword-samples/exception2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/exception2_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 exception exception_name {
   1: required i8 return
 }
diff --git a/compiler/cpp/test/keyword-samples/service1_return.thrift b/compiler/cpp/test/keyword-samples/service1_return.thrift
index 5286a36..c52abb6 100644
--- a/compiler/cpp/test/keyword-samples/service1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service1_return.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 service return {}
diff --git a/compiler/cpp/test/keyword-samples/service2_return.thrift b/compiler/cpp/test/keyword-samples/service2_return.thrift
index 6f7331d..0c77a26 100644
--- a/compiler/cpp/test/keyword-samples/service2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service2_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 service service_name {
   bool function_name(1: i32 return)
 }
diff --git a/compiler/cpp/test/keyword-samples/service3_return.thrift b/compiler/cpp/test/keyword-samples/service3_return.thrift
index c6dd946..fe084d2 100644
--- a/compiler/cpp/test/keyword-samples/service3_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service3_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 service service_name {
   void return()
 }
diff --git a/compiler/cpp/test/keyword-samples/service4_return.thrift b/compiler/cpp/test/keyword-samples/service4_return.thrift
index d0787df..53993f1 100644
--- a/compiler/cpp/test/keyword-samples/service4_return.thrift
+++ b/compiler/cpp/test/keyword-samples/service4_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 exception exception_name {}
 
 service service_name {
diff --git a/compiler/cpp/test/keyword-samples/struct1_return.thrift b/compiler/cpp/test/keyword-samples/struct1_return.thrift
index c82b8b9..9664010 100644
--- a/compiler/cpp/test/keyword-samples/struct1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/struct1_return.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct return {}
diff --git a/compiler/cpp/test/keyword-samples/struct2_return.thrift b/compiler/cpp/test/keyword-samples/struct2_return.thrift
index a0700d1..db123e5 100644
--- a/compiler/cpp/test/keyword-samples/struct2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/struct2_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct struct_name {
   1: required bool return = 1
 }
diff --git a/compiler/cpp/test/keyword-samples/typedef1_return.thrift b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
index f159bb8..142d51f 100644
--- a/compiler/cpp/test/keyword-samples/typedef1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/typedef1_return.thrift
@@ -1 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 typedef bool return
diff --git a/compiler/cpp/test/keyword-samples/union1_return.thrift b/compiler/cpp/test/keyword-samples/union1_return.thrift
index 368df13..af7a8e7 100644
--- a/compiler/cpp/test/keyword-samples/union1_return.thrift
+++ b/compiler/cpp/test/keyword-samples/union1_return.thrift
@@ -1 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 union return {}
diff --git a/compiler/cpp/test/keyword-samples/union2_return.thrift b/compiler/cpp/test/keyword-samples/union2_return.thrift
index 9719d1e..3361a1a 100644
--- a/compiler/cpp/test/keyword-samples/union2_return.thrift
+++ b/compiler/cpp/test/keyword-samples/union2_return.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 union union_name {
   1: optional bool return=1
 }
diff --git a/compiler/cpp/tests/CMakeLists.txt b/compiler/cpp/tests/CMakeLists.txt
index fd8bed2..d9c5209 100644
--- a/compiler/cpp/tests/CMakeLists.txt
+++ b/compiler/cpp/tests/CMakeLists.txt
@@ -76,9 +76,11 @@
     ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/audit/t_audit.cpp
     ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/common.cc
     ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/t_generator.cc
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/validator_parser.cc
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/validator_parser.h
     ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/t_typedef.cc
     ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/parse/parse.cc
-    ${THRIFT_COMPILER_SOURCE_DIR}/thrift/version.h
+    ${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/version.h
 )
 
 # This macro adds an option THRIFT_COMPILER_${NAME}
@@ -96,8 +98,21 @@
     endif()
 endmacro()
 
+# This macro adds an option THRIFT_VALIDATOR_COMPILER_${NAME}
+# that allows enabling or disabling certain languages
+macro(THRIFT_ADD_VALIDATOR_COMPILER name description initial)
+    string(TOUPPER "THRIFT_VALIDATOR_COMPILER_${name}" enabler)
+    set(src "${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/${name}_validator_generator.cc")
+    list(APPEND "${THRIFT_COMPILER_SOURCE_DIR}/src/thrift/generate/${name}_validator_generator.h")
+    option(${enabler} ${description} ${initial})
+    if(${enabler})
+        list(APPEND thrift-compiler_SOURCES ${src})
+    endif()
+endmacro()
+
 # The following compiler with unit tests can be enabled or disabled
 THRIFT_ADD_COMPILER(c_glib  "Enable compiler for C with Glib" OFF)
+THRIFT_ADD_COMPILER(cl      "Enable compiler for Common LISP" OFF)
 THRIFT_ADD_COMPILER(cpp     "Enable compiler for C++" OFF)
 THRIFT_ADD_COMPILER(d       "Enable compiler for D" OFF)
 THRIFT_ADD_COMPILER(dart    "Enable compiler for Dart" OFF)
@@ -113,7 +128,7 @@
 THRIFT_ADD_COMPILER(json    "Enable compiler for JSON" OFF)
 THRIFT_ADD_COMPILER(lua     "Enable compiler for Lua" OFF)
 THRIFT_ADD_COMPILER(netstd  "Enable compiler for .NET Standard" ON)
-THRIFT_ADD_COMPILER(ocaml   "Enable compiler for OCaml" OFF)
+THRIFT_ADD_COMPILER(ocaml   "Enable compiler for OCaml" ON)
 THRIFT_ADD_COMPILER(perl    "Enable compiler for Perl" OFF)
 THRIFT_ADD_COMPILER(php     "Enable compiler for PHP" OFF)
 THRIFT_ADD_COMPILER(py      "Enable compiler for Python 2.0" OFF)
@@ -124,6 +139,9 @@
 THRIFT_ADD_COMPILER(xml     "Enable compiler for XML" OFF)
 THRIFT_ADD_COMPILER(xsd     "Enable compiler for XSD" OFF)
 
+# The following compiler can be enabled or disabled by enabling or disabling certain languages
+THRIFT_ADD_VALIDATOR_COMPILER(go           "Enable validator compiler for Go" ON)
+
 # Thrift is looking for include files in the src directory
 # we also add the current binary directory for generated files
 include_directories(${CMAKE_CURRENT_BINARY_DIR} ${THRIFT_COMPILER_SOURCE_DIR}/src ${CMAKE_CURRENT_SOURCE_DIR}/catch)
diff --git a/compiler/cpp/tests/README.md b/compiler/cpp/tests/README.md
index 91c0625..e45e298 100644
--- a/compiler/cpp/tests/README.md
+++ b/compiler/cpp/tests/README.md
@@ -26,7 +26,7 @@
 ## How to add your tests
 
 - Open **CMakeLists.txt**
-- Set **On** to call of **THRIFT_ADD_COMPILER** for your language
+- Set call of `THRIFT_ADD_COMPILER` for your language to `ON`
 
 ``` cmake 
 THRIFT_ADD_COMPILER(netstd "Enable compiler for .NET Standard" ON)
@@ -85,4 +85,4 @@
 cmake ..
 cmake --build .
 ctest -C Debug -V
-```
\ No newline at end of file
+```
diff --git a/compiler/cpp/tests/ocaml/README.md b/compiler/cpp/tests/ocaml/README.md
new file mode 100644
index 0000000..e79a887
--- /dev/null
+++ b/compiler/cpp/tests/ocaml/README.md
@@ -0,0 +1,16 @@
+## Testing approach
+
+1. Programmatically construct parsed instances of Thrift IDLs using internal
+   types
+2. Generate the OCaml output using the OCaml generator
+3. Capture the generated output in `ostringstream`
+4. Query and compare the outputs in the strings to stored snapshots in the
+   `snapshot_*.cc` files
+
+Run tests in `../tests` directory:
+
+      # Only on changing build definition:
+      cmake -DCMAKE_PREFIX_PATH=/usr/local/opt/bison -DCMAKE_CXX_STANDARD=11 .
+
+      # On each iteration:
+      rm -rf gen-ocaml; cmake --build . && ctest --output-on-failure
diff --git a/compiler/cpp/tests/ocaml/snapshot_exception_types_i.cc b/compiler/cpp/tests/ocaml/snapshot_exception_types_i.cc
new file mode 100644
index 0000000..a7d908f
--- /dev/null
+++ b/compiler/cpp/tests/ocaml/snapshot_exception_types_i.cc
@@ -0,0 +1,27 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you 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.
+
+const char* snapshot(R"""(
+open Thrift
+class serverError :
+object ('a)
+  method copy : 'a
+  method write : Protocol.t -> unit
+end
+exception ServerError of serverError
+val read_serverError : Protocol.t -> serverError
+)""");
diff --git a/compiler/cpp/tests/ocaml/snapshot_service_handle_ex.cc b/compiler/cpp/tests/ocaml/snapshot_service_handle_ex.cc
new file mode 100644
index 0000000..f20d698
--- /dev/null
+++ b/compiler/cpp/tests/ocaml/snapshot_service_handle_ex.cc
@@ -0,0 +1,161 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you 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.
+
+const char* snapshot(R"""(
+open Thrift
+open Service_types
+
+(* HELPER FUNCTIONS AND STRUCTURES *)
+
+class ping_args =
+object (self)
+  method copy =
+      let _new = Oo.copy self in
+    _new
+  method write (oprot : Protocol.t) =
+    oprot#writeStructBegin "ping_args";
+    oprot#writeFieldStop;
+    oprot#writeStructEnd
+end
+let rec read_ping_args (iprot : Protocol.t) =
+  let _str2 = new ping_args in
+    ignore(iprot#readStructBegin);
+    (try while true do
+        let (_,_t3,_id4) = iprot#readFieldBegin in
+        if _t3 = Protocol.T_STOP then
+          raise Break
+        else ();
+        (match _id4 with 
+          | _ -> iprot#skip _t3);
+        iprot#readFieldEnd;
+      done; ()
+    with Break -> ());
+    iprot#readStructEnd;
+    _str2
+
+class ping_result =
+object (self)
+  val mutable _serverError : Errors_types.serverError option = None
+  method get_serverError = _serverError
+  method grab_serverError = match _serverError with None->raise (Field_empty "ping_result.serverError") | Some _x5 -> _x5
+  method set_serverError _x5 = _serverError <- Some _x5
+  method unset_serverError = _serverError <- None
+  method reset_serverError = _serverError <- None
+
+  method copy =
+      let _new = Oo.copy self in
+      if _serverError <> None then
+        _new#set_serverError self#grab_serverError#copy;
+    _new
+  method write (oprot : Protocol.t) =
+    oprot#writeStructBegin "ping_result";
+    (match _serverError with None -> () | Some _v -> 
+      oprot#writeFieldBegin("serverError",Protocol.T_STRUCT,1);
+      _v#write(oprot);
+      oprot#writeFieldEnd
+    );
+    oprot#writeFieldStop;
+    oprot#writeStructEnd
+end
+let rec read_ping_result (iprot : Protocol.t) =
+  let _str8 = new ping_result in
+    ignore(iprot#readStructBegin);
+    (try while true do
+        let (_,_t9,_id10) = iprot#readFieldBegin in
+        if _t9 = Protocol.T_STOP then
+          raise Break
+        else ();
+        (match _id10 with 
+          | 1 -> (if _t9 = Protocol.T_STRUCT then
+              _str8#set_serverError (Errors_types.read_serverError iprot)
+            else
+              iprot#skip _t9)
+          | _ -> iprot#skip _t9);
+        iprot#readFieldEnd;
+      done; ()
+    with Break -> ());
+    iprot#readStructEnd;
+    _str8
+
+class virtual iface =
+object (self)
+  method virtual ping : unit
+end
+
+class client (iprot : Protocol.t) (oprot : Protocol.t) =
+object (self)
+  val mutable seqid = 0
+  method ping  = 
+    self#send_ping;
+    self#recv_ping
+  method private send_ping  = 
+    oprot#writeMessageBegin ("ping", Protocol.CALL, seqid);
+    let args = new ping_args in
+      args#write oprot;
+      oprot#writeMessageEnd;
+      oprot#getTransport#flush
+  method private recv_ping  =
+    let (fname, mtype, rseqid) = iprot#readMessageBegin in
+      (if mtype = Protocol.EXCEPTION then
+        let x = Application_Exn.read iprot in
+          (iprot#readMessageEnd;           raise (Application_Exn.E x))
+      else ());
+      let result = read_ping_result iprot in
+        iprot#readMessageEnd;
+        (match result#get_serverError with None -> () | Some _v ->
+          raise (Errors_types.ServerError _v));
+        ()
+end
+
+class processor (handler : iface) =
+object (self)
+  inherit Processor.t
+
+  val processMap = Hashtbl.create 1
+  method process iprot oprot =
+    let (name, typ, seqid)  = iprot#readMessageBegin in
+      if Hashtbl.mem processMap name then
+        (Hashtbl.find processMap name) (seqid, iprot, oprot)
+      else (
+        iprot#skip(Protocol.T_STRUCT);
+        iprot#readMessageEnd;
+        let x = Application_Exn.create Application_Exn.UNKNOWN_METHOD ("Unknown function "^name) in
+          oprot#writeMessageBegin(name, Protocol.EXCEPTION, seqid);
+          x#write oprot;
+          oprot#writeMessageEnd;
+          oprot#getTransport#flush
+      );
+      true
+  method private process_ping (seqid, iprot, oprot) =
+    let _ = read_ping_args iprot in
+      iprot#readMessageEnd;
+      let result = new ping_result in
+        (try
+          (handler#ping);
+        with
+          | Errors_types.ServerError serverError -> 
+              result#set_serverError serverError
+        );
+        oprot#writeMessageBegin ("ping", Protocol.REPLY, seqid);
+        result#write oprot;
+        oprot#writeMessageEnd;
+        oprot#getTransport#flush
+  initializer
+    Hashtbl.add processMap "ping" self#process_ping;
+end
+
+)""");
diff --git a/compiler/cpp/tests/ocaml/snapshot_typedefs.cc b/compiler/cpp/tests/ocaml/snapshot_typedefs.cc
new file mode 100644
index 0000000..473b2e8
--- /dev/null
+++ b/compiler/cpp/tests/ocaml/snapshot_typedefs.cc
@@ -0,0 +1,22 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you 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.
+
+const char* snapshot(R"""(
+open Thrift
+type decimal = string
+
+)""");
diff --git a/compiler/cpp/tests/ocaml/t_ocaml_generator_tests.cc b/compiler/cpp/tests/ocaml/t_ocaml_generator_tests.cc
new file mode 100644
index 0000000..ea788fc
--- /dev/null
+++ b/compiler/cpp/tests/ocaml/t_ocaml_generator_tests.cc
@@ -0,0 +1,111 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you 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 <list>
+#include <memory>
+#include "../catch/catch.hpp"
+#include <thrift/generate/t_ocaml_generator.cc>
+
+using defs_t = std::list<t_type*>;
+
+/** This subclass is meant to allow accessing the Thrift generated OCaml outputs
+    and keep the tests stable across Thrift versions (as much as possible), but
+    otherwise is identical to the standard OCaml generator. */
+class t_test_ocaml_generator : public t_ocaml_generator {
+public:
+    t_test_ocaml_generator(t_program* program) : t_ocaml_generator(program, {}, "") {}
+
+    /** Override and turn off comment generation which contains a version number
+        to make tests version-independent. */
+    std::string ocaml_autogen_comment() override { return ""; }
+
+    // Allow inspecting the generated code.
+
+    string types() { return f_types_.str(); }
+    string consts() { return f_consts_.str(); }
+    string service() { return f_service_.str(); }
+    string types_i() { return f_types_i_.str(); }
+    string service_i() { return f_service_i_.str(); }
+};
+
+/** Helper to add a list of definitions to a Thrift 'program' (i.e.
+    representation of the IDL) and generate the OCaml outputs. */
+void gen_program(t_generator& gen, t_program& program, defs_t defs) {
+    for (auto def : defs) {
+        if (def->is_typedef()) program.add_typedef(static_cast<t_typedef*>(def));
+        else if (def->is_enum()) program.add_enum(static_cast<t_enum*>(def));
+        else if (def->is_struct()) program.add_struct(static_cast<t_struct*>(def));
+        else if (def->is_xception()) program.add_xception(static_cast<t_struct*>(def));
+        else if (def->is_service()) program.add_service(static_cast<t_service*>(def));
+    }
+
+    gen.generate_program();
+}
+
+TEST_CASE( "t_ocaml_generator - typedefs", "[functional]" )
+{
+    t_program program("Typedefs.thrift", "Typedefs");
+    t_base_type ty_string("string", t_base_type::TYPE_STRING);
+    t_typedef tydef_decimal(&program, &ty_string, "Decimal");
+    t_test_ocaml_generator gen(&program);
+
+    gen_program(gen, program, defs_t {
+        &tydef_decimal
+    });
+
+    #include "snapshot_typedefs.cc"
+    REQUIRE( snapshot == gen.types() );
+}
+
+TEST_CASE( "t_ocaml_generator - handle exception from different module", "[functional]" )
+{
+    t_program errors_thrift("Errors.thrift", "Errors");
+    t_struct server_error(&errors_thrift, "ServerError");
+    server_error.set_xception(true);
+
+    t_test_ocaml_generator errors_gen(&errors_thrift);
+    gen_program(errors_gen, errors_thrift, defs_t {
+        &server_error
+    });
+
+    {
+        #include "snapshot_exception_types_i.cc"
+        REQUIRE( snapshot == errors_gen.types_i() );
+    }
+
+    t_program service_thrift("Service.thrift", "Service");
+    t_service service(&service_thrift);
+    service.set_name("Service");
+    t_base_type ret_type("void", t_base_type::TYPE_VOID);
+    t_struct args(&service_thrift, "ping_args");
+    t_struct throws(&service_thrift, "ping_throws");
+    t_field ex_server_error(&server_error, "serverError", 1);
+    throws.append(&ex_server_error);
+    t_function ping(&ret_type, "ping", &args, &throws);
+    service.add_function(&ping);
+
+    t_test_ocaml_generator service_gen(&service_thrift);
+
+    gen_program(service_gen, service_thrift, defs_t {
+        &service
+    });
+
+    {
+        #include "snapshot_service_handle_ex.cc"
+        REQUIRE( snapshot == service_gen.service() );
+    }
+}
diff --git a/configure.ac b/configure.ac
index de64936..a926e3e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,7 +20,7 @@
 AC_PREREQ(2.65)
 AC_CONFIG_MACRO_DIR([./aclocal])
 
-AC_INIT([thrift], [0.17.0])
+AC_INIT([thrift], [0.18.0])
 
 AC_CONFIG_AUX_DIR([.])
 
@@ -112,6 +112,7 @@
   have_libs="no"
   with_cpp="no"
   with_c_glib="no"
+  with_cl="no"
   with_java="no"
   with_kotlin="no"
   with_python="no"
@@ -443,6 +444,16 @@
 fi
 AM_CONDITIONAL(WITH_RS, [test "$have_rs" = "yes"])
 
+AX_THRIFT_LIB(cl, [Common Lisp], yes)
+have_cl="no"
+if test "$with_cl" = "yes";  then
+  AC_PATH_PROG([SBCL], [sbcl])
+  if test "x$SBCL" != "x"; then
+    have_cl="yes"
+  fi
+fi
+AM_CONDITIONAL(WITH_CL, [test "$have_cl" = "yes"])
+
 AX_THRIFT_LIB(haxe, [Haxe], yes)
 if test "$with_haxe" = "yes";  then
   AC_PATH_PROG([HAXE], [haxe])
@@ -745,6 +756,7 @@
   compiler/cpp/src/Makefile
   compiler/cpp/test/Makefile
   lib/Makefile
+  lib/cl/Makefile
   lib/cpp/Makefile
   lib/cpp/test/Makefile
   lib/cpp/thrift-nb.pc
@@ -793,6 +805,7 @@
   test/Makefile
   test/features/Makefile
   test/c_glib/Makefile
+  test/cl/Makefile
   test/cpp/Makefile
   test/erl/Makefile
   test/go/Makefile
@@ -809,6 +822,7 @@
   test/rs/Makefile
   tutorial/Makefile
   tutorial/c_glib/Makefile
+  tutorial/cl/Makefile
   tutorial/cpp/Makefile
   tutorial/d/Makefile
   tutorial/go/Makefile
@@ -825,6 +839,7 @@
   tutorial/py.tornado/Makefile
   tutorial/rb/Makefile
   tutorial/rs/Makefile
+  tutorial/swift/Makefile
 ])
 
 if test "$have_cpp" = "yes" ; then MAYBE_CPP="cpp" ; else MAYBE_CPP="" ; fi
@@ -865,6 +880,8 @@
 AC_SUBST([MAYBE_SWIFT])
 if test "$have_netstd" = "yes" ; then MAYBE_NETSTD="netstd" ; else MAYBE_NETSTD="" ; fi
 AC_SUBST([MAYBE_NETSTD])
+if test "$have_cl" = "yes" ; then MAYBE_CL="cl" ; else MAYBE_CL="" ; fi
+AC_SUBST([MAYBE_CL])
 
 AC_OUTPUT
 
@@ -874,6 +891,7 @@
 echo
 echo "Building C (GLib) Library .... : $have_c_glib"
 echo "Building C++ Library ......... : $have_cpp"
+echo "Building Common Lisp Library.. : $have_cl"
 echo "Building D Library ........... : $have_d"
 echo "Building Dart Library ........ : $have_dart"
 echo "Building .NET Standard Library : $have_netstd"
@@ -906,6 +924,12 @@
   echo "   Build TQTcpServer (Qt5) ... : $have_qt5"
   echo "   C++ compiler version ...... : $($CXX --version | head -1)"
 fi
+if test "$have_cl" = "yes" ; then
+  echo
+  echo "Common Lisp Library:"
+  echo "   Using Common Lisp ......... : $SBCL"
+  echo "   Using Common Lisp version . : $($SBCL --version)"
+fi
 if test "$have_d" = "yes" ; then
   echo
   echo "D Library:"
diff --git a/contrib/Rebus/Properties/AssemblyInfo.cs b/contrib/Rebus/Properties/AssemblyInfo.cs
index cc3204a..605eb5c 100644
--- a/contrib/Rebus/Properties/AssemblyInfo.cs
+++ b/contrib/Rebus/Properties/AssemblyInfo.cs
@@ -34,5 +34,5 @@
 
 [assembly: Guid("0af10984-40d3-453d-b1e5-421529e8c7e2")]
 
-[assembly: AssemblyVersion("0.17.0.0")]
-[assembly: AssemblyFileVersion("0.17.0.0")]
+[assembly: AssemblyVersion("0.18.0.0")]
+[assembly: AssemblyFileVersion("0.18.0.0")]
diff --git a/contrib/async-test/aggr.thrift b/contrib/async-test/aggr.thrift
index c016a65..912b2cf 100644
--- a/contrib/async-test/aggr.thrift
+++ b/contrib/async-test/aggr.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 exception Error {
   1: string desc;
 }
diff --git a/contrib/thrift-maven-plugin/pom.xml b/contrib/thrift-maven-plugin/pom.xml
index da8491d..64fe088 100644
--- a/contrib/thrift-maven-plugin/pom.xml
+++ b/contrib/thrift-maven-plugin/pom.xml
@@ -32,7 +32,7 @@
   <artifactId>thrift-maven-plugin</artifactId>
   <packaging>maven-plugin</packaging>
   <name>thrift-maven-plugin</name>
-  <version>0.17.0</version>
+  <version>0.18.0</version>
 
   <properties>
     <maven.compiler.source>1.8</maven.compiler.source>
diff --git a/contrib/thrift.spec b/contrib/thrift.spec
index 92af91e..ecc7fb7 100644
--- a/contrib/thrift.spec
+++ b/contrib/thrift.spec
@@ -28,7 +28,7 @@
 License:        Apache License v2.0
 Group:          Development
 Summary:        RPC and serialization framework
-Version:        0.17.0
+Version:        0.18.0
 Release:        0
 URL:            http://thrift.apache.org
 Packager:       Thrift Developers <dev@thrift.apache.org>
diff --git a/contrib/transport-sample/Sample.thrift b/contrib/transport-sample/Sample.thrift
index 3040e25..464c8ce 100644
--- a/contrib/transport-sample/Sample.thrift
+++ b/contrib/transport-sample/Sample.thrift
@@ -1,4 +1,23 @@
 /*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+/*
  transport-sample thrift IDL file .
  Execute thriftme.bat under Windows to generate the cpp stubs from this IDL.
  */
diff --git a/contrib/zeromq/csharp/AssemblyInfo.cs b/contrib/zeromq/csharp/AssemblyInfo.cs
index 8f46c92..787b00d 100644
--- a/contrib/zeromq/csharp/AssemblyInfo.cs
+++ b/contrib/zeromq/csharp/AssemblyInfo.cs
@@ -36,7 +36,7 @@
 // The form "{Major}.{Minor}.*" will automatically update the build and revision,
 // and "{Major}.{Minor}.{Build}.*" will update just the revision.
 
-[assembly: AssemblyVersion("0.17.0.0")]
+[assembly: AssemblyVersion("0.18.0.0")]
 
 // The following attributes are used to specify the signing key for the assembly,
 // if desired. See the Mono documentation for more information about signing.
diff --git a/contrib/zeromq/storage.thrift b/contrib/zeromq/storage.thrift
index a1ea967..7981258 100644
--- a/contrib/zeromq/storage.thrift
+++ b/contrib/zeromq/storage.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 service Storage {
   oneway void incr(1: i32 amount);
   i32 get();
diff --git a/debian/changelog b/debian/changelog
index c570028..dc02167 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+thrift (0.17.0) stable; urgency=low
+
+  * update to 0.17.0
+
+ -- Apache Thrift Developers <dev@thrift.apache.org>  Tue, 30 Aug 2022 23:00:00 +0200
+
 thrift (0.16.0) stable; urgency=low
 
   * update to 0.16.0
diff --git a/debian/copyright b/debian/copyright
index a7038b1..e39dc74 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -80,6 +80,7 @@
   lib/cpp/test/OptionalRequiredTest.cpp
   test/OptionalRequiredTest.thrift
   test/ThriftTest.thrift
+  test/v0.16/ThriftTest.thrift
 
 --------------------------------------------------
 For the aclocal/ax_boost_base.m4 and contrib/fb303/aclocal/ax_boost_base.m4 components:
diff --git a/doap.rdf b/doap.rdf
index 36c54e6..e69bedc 100644
--- a/doap.rdf
+++ b/doap.rdf
@@ -57,6 +57,11 @@
     <release rdf:parseType="Collection">
       <Version>
         <name>Apache Thrift</name>
+        <created>2022-08-30</created>
+        <revision>0.17.0</revision>
+      </Version>
+      <Version>
+        <name>Apache Thrift</name>
         <created>2022-01-20</created>
         <revision>0.16.0</revision>
       </Version>
diff --git a/doc/install/debian.md b/doc/install/debian.md
index 0792252..4d5a446 100644
--- a/doc/install/debian.md
+++ b/doc/install/debian.md
@@ -18,7 +18,7 @@
 If you would like to build Apache Thrift libraries for other programming languages you may need to install additional packages. The following languages require the specified additional packages:
 
  * Java
-	* packages: gradle (version 7.4.2)
+	* packages: gradle (version 7.5.1)
 	* You will also need Java JDK v1.8 or higher. Type **javac** to see a list of available packages, pick the one you prefer and **apt-get install** it (e.g. default-jdk).
  * Ruby
 	* ruby-full ruby-dev ruby-rspec rake rubygems bundler
diff --git a/doc/specs/idl.md b/doc/specs/idl.md
index 7ae1af8..456b777 100644
--- a/doc/specs/idl.md
+++ b/doc/specs/idl.md
@@ -1,6 +1,6 @@
 ## Thrift interface description language
 
-For Thrift version 0.17.0.
+For Thrift version 0.18.0.
 
 The Thrift interface definition language (IDL) allows for the definition of [Thrift Types](/docs/types). A Thrift IDL file is processed by the Thrift code generator to produce code for the various target languages to support the defined structs and services in the IDL file.
 
@@ -166,7 +166,7 @@
 
     [28] SetType         ::=  'set' CppType? '<' FieldType '>'
 
-    [29] ListType        ::=  'list' '<' FieldType '>' CppType?
+    [29] ListType        ::=  'list' CppType? '<' FieldType '>' 
 
     [30] CppType         ::=  'cpp_type' Literal
 
diff --git a/doc/specs/thrift-parameter-validation-proposal.md b/doc/specs/thrift-parameter-validation-proposal.md
new file mode 100644
index 0000000..42f3084
--- /dev/null
+++ b/doc/specs/thrift-parameter-validation-proposal.md
@@ -0,0 +1,195 @@
+# Thrift Parameter Validation Proposal
+
+> Version 1.1
+>
+> Dec 15, 2021
+>
+> duanyi.aster@bytedance.com, wangtieju@bytedance.com
+
+### 1. Abstract
+***
+This document presents a proposed set of annotations to the Thrift IDL. The new annotations will supports parameter validation using build-in or third-party validators. The goal of this proposal is to define semantics and behavior of validation annotations, rather than to discuss their implementation.
+
+### 2. Background
+***
+Parameter validation is a common need for web service. In the past, we usually write our validating logics after a RPC message deserialized by thrift. This ways works flexibly enough but restrict poorly: It is dangerous that service A and service B using the same IDL have two different validating rule, which often misdirects developers. Even if we extract our validating codes to a single module, simple and repeated work (ex. `if xx.Field1 > 1 then ...`) is really disturbing. If we can use build tool to generating codes for simple and unchangeable restraint, the web service will be more robust and developers will benefits from lighter work.
+Compared to other IDL, the parameter validation gradually gets strong community supports like PGV ([protoc-gen-validate](https://github.com/envoyproxy/protoc-gen-validate)), benefiting from pb's strong plugin mechanism (lacking official plugin mechanism is one reason for we submit this proposal). Take a long-term view, auto-generated parameter validation may be a step towards code-less web service.
+
+### 3. Proposal
+***
+This proposal includes three part: Validate Annotation Semantics, Validate Rule and Validate Feedback. The first declare how to write a validate annotation, the middle explain how every annotation should behave, the last introduces a mechanism of validating feedback.
+
+#### 3.1 Validate Annotation Semantics
+This semantics uses same rule of [Thrift IDL](https://thrift.apache.org/docs/idl). The validate option only works on struct fields, thus we must start from Field semantics part.
+- Field 
+```peg
+Field <- FieldID? FieldReq? FieldType Identifier ('=' ConstValue)? ValidateAnnotations? ListSeparator?
+```
+- ValidateAnnotations
+```peg
+ValidateAnnotations <- '(' ValidateRule+ ListSeparator? ')'
+```
+- ValidateRule
+```peg
+ValidateRule <- ('validate' | 'vt') Validator+ = '"' ValidatingValue? '"'
+```
+- Validator
+
+    Build-in validating logics. See [Supported Validator](#321-supported-validator) part.
+```peg
+Validator <- '.' Identifier
+```
+- ValidatingValue
+```peg
+ValidatingValue <- (ToolFunction '(' )? Arguments ')'?
+```
+- ToolFunction
+
+    Build-in or user-defined tool functions. See [Tool Function](#325-tool-function) part.
+```peg
+ToolFunction <- '@' Identifier
+```
+- Arguments
+```peg
+Arguments <- (DynamicValue ListSeparator?)*
+```
+- DynamicValue
+```peg
+DynamicValue <- ConstValue | FieldReference
+```
+- FieldReference
+  
+    See [Field Reference](#324-field-reference) part.
+```apache
+FieldReference <- '$' ReferPath
+ReferPath <- FieldName? ( ('['IntConstant']') | ('.'Identifier) )?
+```
+- All other semantics keep same with [standard definition](https://thrift.apache.org/docs/idl)
+
+### 3.2 Validate Rule
+The validate rule is works as a Boolean Expression, and Validator is core logic for one validate rule. Every Validator works like an Operator, calculating the Validating Value and Field Value, and then compare. For example, `gt` (greater than) will compare the right Validating Value with value of the field it belongs to, and return `true` if field value is greater than value or `false` if field value is not. We appoint that: Only if the validate rule returns true, the validated parameter is valid. If there are several validate rules defined in annotations of a field, Validator will take the logical relation as "and". Simply put, commas in annotations can be treated as "and".
+
+
+#### 3.2.1 Supported Validator
+Below lists the support validators. Value type means the type of validating value, field type means type of validated field.
+
+| validator    | behavior                              | value type                           | field type             | secondary validator |
+| ------------ | ------------------------------------- | ------------------------------------ | ---------------------- | ------------------- |
+| const        | must be constant                      | string, bool                         | same with value        | -                   |
+| defined_only | must be defined value                 | enum                                 | enum                   | -                   |
+| not_nil      | must not be empty                     | "true"                               | any                    | -                   |
+| skip         | skip validate                         | "true"                               | any                    | -                   |
+| eq           | equals to (`==`)                      | i8, i16, i32, i64, f64, string, bool | same with value        | -                   |
+| ne           | not equals to (`!=`)                  | i8, i16, i32, i64, f64, string, bool | same with value        | -                   |
+| lt           | less than (`<`)                       | i8, i16, i32, i64, f64               | same with value        | -                   |
+| le           | less equal (`<=`)                     | i8, i16, i32, i64, f64               | same with value        | -                   |
+| gt           | greater than (`>`)                    | i8, i16, i32, i64, f64               | same with value        | -                   |
+| ge           | greater equal (`>=`)                  | i8, i16, i32, i64, f64               | same with value        | -                   |
+| in           | within given container                | i8, i16, i32, i64, f64, enum         | same with value        | -                   |
+| not_in       | not within given container            | i8, i16, i32, i64, f64, enum         | same with value        | -                   |
+| elem         | field's element constraint            | any                                  | list, set              | support             |
+| key          | field's element key constraint        | any                                  | map                    | support             |
+| value        | field's element value constraint      | any                                  | map                    | support             |
+| min_size     | minimal length                        | i8, i16, i32, i64                    | string, list, set, map | -                   |
+| max_size     | maximal length                        | i8, i16, i32, i64                    | string, list, set, map | -                   |
+| prefix       | field prefix must be (case-sensitive) | string                               | string                 | -                   |
+| suffix       | suffix must be (case-sensitive)       | string                               | string                 | -                   |
+| contains     | must contain (case-sensitive)         | string                               | string                 | -                   |
+| not_contains | must not contain (case-sensitive)     | string                               | string                 | -                   |
+| pattern      | basic regular expression              | string                               | string                 | -                   |
+
+- Basic Regular Expression (BRE), the syntax of BRE can be found in [manual](https://www.gnu.org/software/sed/manual/html_node/BRE-syntax.html) of GNU sed.
+- Secondary validator (`elem`, `key` and `value`) is a successive validator, usually used at container-type field. See below Set/List/Map examples.
+- Add suffix "_escape" to validators to prevent value of rule conflicting with tool function. For example, you can use `"vt.eq_escape" = "@len(A)"` to match literal `@len(A)`.
+
+#### 3.2.2 IDL example
+- Number
+```
+struct NumericDemo{
+    1: double Value (validator.ge = "1000.1", validator.le = "10000.1")
+    2: i8 Type (validator.in = "[1, 2, 4]")
+}
+```
+- String/Binary
+``` 
+struct StringDemo{
+    1: string Uninitialized (vt.const = "abc")
+    2: string Name (vt.min_size = "6", vt.max_size = "12")
+    3: string SomeStuffs (vt.pattern = "[0-9A-Za-z]+")
+    4: string DebugInfo (vt.prefix = "[Debug]")
+    5: string ErrorMessage (vt.contains = "Error")
+}
+```
+- Bool
+```
+struct BoolDemo {
+    1: bool AMD (vt.const = "true")
+}
+```
+- Enum
+```
+enum Type {
+    Bool
+    I8
+    I16
+    I32
+    I64
+    String
+    Struct
+    List
+    Set
+    Map
+}
+
+struct EnumDemo {
+    1: Type AddressType (vt.in = "[String]")
+    2: Type ValueType (vt.defined_only = "true")
+}
+```
+- Set/List
+```
+struct SetListDemo {
+    1: list<string> Persons (vt.min_size = "5", vt.max_size = "10")
+    2: set<double> HealthPoints (vt.elem.gt = "0")
+}
+```
+- Map
+```
+struct MapDemo {
+    1: map<i32, string> IdName (vt.min_size = "5", vt.max_size = "10")
+    2: map<i32, double> Some (vt.key.gt = "0", vt.value.lt = "1000")
+}
+```
+
+#### 3.2.3 Arguments
+Arguments can by static literals or dynamic variables. If one literal expression contains any Field Reference or Tool Function, it becomes dynamic variables. Every dynamic variables finally get calculated and finally become a Thrift Constant Value.
+
+#### 3.2.4 Field Reference
+Field Reference is used to refer to another field's value in Validating Value, therefore user can compare more than one field. The referenced field must be within same struct. Identifier must be the field name referred.
+- Field Reference Rule
+1. `$x` represents a variable named x, and its scope is within current struct
+2. `$` indicates the current field in which the validator is located
+3. `$x['k']` indicates a reference to the key k of variable x (which must be map)
+4. `$x[i]` indicates a reference to the i + 1 element of variable x (which must be list)
+- Example
+```
+struct FieldReferenceExample {
+    1: string A (vt.eq = "$B") //field A must equal to field B
+    2: list<string> C
+}
+```
+
+#### 3.2.5 Tool Function
+Tool Function is use to enhance the operating of Validating Value. For example, if we want to ensure one field is larger than the length of string field A, we can use `len()` function: `vt.gt = "@len($A)"`. The arguments can be either literals or variables, and no size limit. However, we won't suggest any build-in function here, because the category is too big and always language-related. Instead, we only propose one mechanism for thrift developers to extends their implementation according to used language.
+
+Supported functions:
+| function | behavior                | arguments                           | results  | supported language |
+| -------- | ----------------------- | ----------------------------------- | -------- | ------------------ |
+| len      | the length of the field | 1: string, binary, list, set or map | 1. int64 | go                 |
+
+### 3.3 Feedback
+The generated validating codes should be included in struct's `Validate() TApplicationException` method. If all validate rule declared by one struct get passed, the struct's `Validate() TApplicationException` method returns nil (or just returns without exception, depending on specific language implementation); Otherwise it returns `TApplicationException` and report feedback message indicating failure reason. Due to language function implementations are different, we won't constrain the interface of feedback messages. However, by practice we suggest developers to give below three detail information:
+
+- The position where first validating failure happens.
+- The validator who reports the failure.
+- The red-handed field value and validating value when the failure happens
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 64b9030..3f717f1 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -92,6 +92,10 @@
 SUBDIRS += rs
 endif
 
+if WITH_CL
+SUBDIRS += cl
+endif
+
 if WITH_SWIFT
 SUBDIRS += swift
 endif
diff --git a/lib/c_glib/CMakeLists.txt b/lib/c_glib/CMakeLists.txt
index 218f7dd..3557123 100644
--- a/lib/c_glib/CMakeLists.txt
+++ b/lib/c_glib/CMakeLists.txt
@@ -97,10 +97,16 @@
 
 # If Zlib is not found just ignore the Zlib stuff
 if(WITH_ZLIB)
-    include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
     ADD_LIBRARY_THRIFT(thrift_c_glib_zlib ${thrift_c_glib_zlib_SOURCES})
-    target_link_libraries(thrift_c_glib_zlib ${SYSLIBS} ${ZLIB_LIBRARIES})
-    target_link_libraries(thrift_c_glib_zlib thrift_c_glib)
+    target_link_libraries(thrift_c_glib_zlib PUBLIC ${SYSLIBS})
+    target_link_libraries(thrift_c_glib_zlib PUBLIC thrift_c_glib)
+
+    if(TARGET ZLIB::ZLIB)
+        target_link_libraries(thrift_c_glib_zlib PUBLIC ZLIB::ZLIB)
+    else()
+        include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+        target_link_libraries(thrift_c_glib_zlib PUBLIC ${ZLIB_LIBRARIES})
+    endif()
 endif()
 
 # Install the headers
diff --git a/lib/c_glib/test/CMakeLists.txt b/lib/c_glib/test/CMakeLists.txt
index 85c6dd0..4d3092f 100644
--- a/lib/c_glib/test/CMakeLists.txt
+++ b/lib/c_glib/test/CMakeLists.txt
@@ -197,7 +197,7 @@
     gen-c_glib/t_test_service_for_exception_with_a_map.h
     gen-c_glib/t_test_srv.c
     gen-c_glib/t_test_srv.h
-    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/v0.16/DebugProtoTest.thrift
 )
 
 add_custom_command(OUTPUT
@@ -221,7 +221,7 @@
     gen-c_glib/t_test_second_service.h
     gen-c_glib/t_test_thrift_test.h
     gen-c_glib/t_test_thrift_test_types.h
-    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen c_glib ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
 )
 
 add_custom_command(OUTPUT
@@ -231,7 +231,7 @@
     gen-cpp/ThriftTest.h
     gen-cpp/ThriftTest_constants.h
     gen-cpp/ThriftTest_types.h
-    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
 )
 
 # TODO: Add memory checks using ctest_memcheck or similar
diff --git a/lib/c_glib/test/Makefile.am b/lib/c_glib/test/Makefile.am
index 023165a..f3a0c30 100644
--- a/lib/c_glib/test/Makefile.am
+++ b/lib/c_glib/test/Makefile.am
@@ -323,7 +323,7 @@
 gen-c_glib/t_test_container_test_types.c gen-c_glib/t_test_container_test_types.h gen-c_glib/t_test_container_service.c gen-c_glib/t_test_container_service.h: ContainerTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/DebugProtoTest.thrift $(THRIFT)
+gen-c_glib/t_test_debug_proto_test_types.c gen-c_glib/t_test_debug_proto_test_types.h gen-c_glib/t_test_empty_service.c gen-c_glib/t_test_empty_service.h gen-c_glib/t_test_inherited.c gen-c_glib/t_test_inherited.h gen-c_glib/t_test_reverse_order_service.c gen-c_glib/t_test_reverse_order_service.h gen-c_glib/t_test_service_for_exception_with_a_map.c gen-c_glib/t_test_service_for_exception_with_a_map.h gen-c_glib/t_test_srv.c gen-c_glib/t_test_srv.h: ../../../test/v0.16/DebugProtoTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
 gen-c_glib/t_test_enum_test_types.c gen-c_glib/t_test_enum_test_types.h gen-c_glib/t_test_enum_test_service.c gen-c_glib/t_test_enum_test_service.h : ../../../test/EnumTest.thrift $(THRIFT)
@@ -332,10 +332,10 @@
 gen-c_glib/t_test_optional_required_test_types.c gen-c_glib/t_test_optional_required_test_types.h: ../../../test/OptionalRequiredTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/ThriftTest.thrift $(THRIFT)
+gen-c_glib/t_test_second_service.c gen-c_glib/t_test_thrift_test.c gen-c_glib/t_test_thrift_test_types.c gen-c_glib/t_test_second_service.h gen-c_glib/t_test_thrift_test.h gen-c_glib/t_test_thrift_test_types.h: ../../../test/v0.16/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib $<
 
-gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest_types.cpp: ../../../test/ThriftTest.thrift $(THRIFT)
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest_types.cpp: ../../../test/v0.16/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp $<
 
 TESTS = \
diff --git a/lib/cl/Makefile.am b/lib/cl/Makefile.am
new file mode 100644
index 0000000..34b3886
--- /dev/null
+++ b/lib/cl/Makefile.am
@@ -0,0 +1,40 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+all-local:
+	bash ensure-externals.sh
+
+run-tests: test/make-test-binary.lisp
+	$(SBCL) --script test/make-test-binary.lisp
+
+check-local: run-tests
+	./run-tests
+
+clean-local:
+	$(RM) run-tests quicklisp.lisp backport-update.zip
+	$(RM) -rf lib externals quicklisp
+
+EXTRA_DIST = \
+	README.md \
+	READMES \
+	load-locally.lisp \
+	test \
+	ensure-externals.sh
diff --git a/lib/cl/README.md b/lib/cl/README.md
new file mode 100644
index 0000000..1d6eafb
--- /dev/null
+++ b/lib/cl/README.md
@@ -0,0 +1,253 @@
+Thrift Common Lisp Library
+
+License
+=======
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you 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.
+
+
+
+Using Thrift with Common Lisp
+============================
+
+ Thrift is a protocol and library for language-independent communication between cooperating
+ processes. The communication takes the form of request and response messages, of which the forms
+ are specified in advance throufh a shared interface definition. A Thrift definition file is translated
+ into Lisp source files, which comprise several definitions:
+
+  * Three packages, one for the namespace of the implementation operators, and one each for request and
+  response operators.
+  * Various type definitions as implementations for Thrift typedef and enum definitions.
+  * DEF-STRUCT and DEF-EXCEPTION forms for Thrift struct and exception definitions.
+  * DEF-SERVICE forms for thrift service definitions.
+
+ Each service definition expands in a collection of generic function definitions. For each `op`
+ in the service definition, two functions are defined
+
+  * `op`-request is defined for use by a client. It accepts an additional initial `protocol` argument,
+    to act as the client proxy for the operation and mediate the interaction with a remote process
+    through a Thrift-encoded transport stream.
+  * `op`-response is defined for use by a server. It accepts a single `protocol` argument. A server
+    uses it to decode the request message, invoke the base `op` function with the message arguments,
+    encode and send the the result as a response, and handles exceptions.
+
+ The client interface is one operator
+
+  * `with-client (variable location) . body` : creates a connection in a dynamic context and closes it
+    upon exit. The variable is bound to a client proxy stream/protocol instance, which wraps the
+    base i/o stream - socket, file, etc, with an operators which implement the Thrift protocol
+    and transport mechanisms.
+
+ The server interface combines server and service objects
+
+  * `serve (location service)` : accepts connections on the designated port and responds to
+    requests of the service's operations.
+
+
+Building 
+--------
+
+The Thrift Common Lisp library is packaged as the ASDF[[1]] system `thrift`.
+It depends on the systems
+
+* puri[[2]] : for the thrift uri class
+* closer-mop[[3]] : for class metadata
+* trivial-utf-8[[4]] : for string codecs
+* usocket[[5]] : for the socket transport
+* ieee-floats[[6]] : for conversion between ints and floats
+* trivial-gray-streams[[7]] : an abstraction layer for gray streams
+* alexandria[[8]] : handy utilities
+
+The dependencies are bundled for local builds of tests and tutorial binaries - 
+it is possible to use those bundles to load the library, too.
+
+In order to build it, register those systems with ASDF and evaluate:
+
+    (asdf:load-system :thrift)
+
+This will compile and load the Lisp compiler for Thrift definition files, the
+transport and protocol implementations, and the client and server interface
+functions. In order to use Thrift in an application, one must also author and/or
+load the interface definitions for the remote service.[[9]] If one is implementing a service,
+one must also define the actual functions to which Thrift is to act as the proxy
+interface. The remainder of this document follows the Thrift tutorial to illustrate how
+to perform the steps
+
+  * implement the service
+  * translate the Thrift IDL
+  * load the Lisp service interfaces
+  * run a server for the service
+  * use a client to access the service remotely
+
+Note that, if one is to implement a new service, one will also need to author the
+IDL files, as there is no facility to generate them from a service implementation.
+
+
+Implement the Service
+---------------------
+
+The tutorial comprises serveral functions: `add`, `ping`, `zip`, and `calculate`.
+Each translated IDL file generates three packages for every service. In the case of
+the tutorial file, the relevant packages are:
+
+  * tutorial.calculator
+  * tutorial.calculator-implementation
+  * tutorial.calculator-response
+  
+This is to separate the request (generated), response (generated) and implementation
+(meant to be implemented by the programmer) functions for defined Thrift methods.
+
+It is suggested to work in the `tutorial-implementation` package while implementing
+the services - it imports the `common-lisp` package, while the service-specific ones
+don't (to avoid conflicts between Thrift method names and function names in `common-lisp`).
+
+    ;; define the base operations
+    
+    (in-package :tutorial-implementation)
+    
+    (defun tutorial.calculator-implementation:add (num1 num2)
+      (format t "~&Asked to add ~A and ~A." num1 num2)
+      (+ num1 num2))
+    
+    (defun tutorial.calculator-implementation:ping ()
+      (print :ping))
+    
+    (defun tutorial.calculator-implementation:zip ()
+      (print :zip))
+    
+    (defun tutorial.calculator-implementation:calculate (logid task)
+      (calculate-op (work-op task) (work-num1 task) (work-num2 task)))
+    
+    (defgeneric calculate-op (op arg1 arg2)
+      (:method :around (op arg1 arg2)
+        (let ((result (call-next-method)))
+          (format t "~&Asked to calculate: ~d on  ~A and ~A = ~d." op arg1 arg2 result)
+          result))
+    
+      (:method ((op (eql operation.add)) arg1 arg2)
+        (+ arg1 arg2))
+      (:method ((op (eql operation.subtract)) arg1 arg2)
+        (- arg1 arg2))
+      (:method ((op (eql operation.multiply)) arg1 arg2)
+        (* arg1 arg2))
+      (:method ((op (eql operation.divide)) arg1 arg2)
+        (/ arg1 arg2)))
+    
+    (defun zip () (print 'zip))
+
+
+Translate the Thrift IDL
+------------------------
+
+IDL files employ the file extension `thrift`. In this case, there are two files to translate
+  * `tutorial.thrift`
+  * `shared.thrift`
+As the former includes the latter, one uses it to generate the interfaces:
+
+    $THRIFT/bin/thrift -r --gen cl $THRIFT/tutorial/tutorial.thrift
+    
+`-r` stands for recursion, while `--gen` lets one choose the language to translate to.
+
+
+Load the Lisp translated service interfaces
+-------------------------------------------
+
+The translator generates three files for each IDL file. For example `tutorial-types.lisp`,
+`tutorial-vars.lisp` and an `.asd` file that can be used to load them both and pull in
+other includes (like `shared` within the tutorial) as dependencies.
+
+
+Run a Server for the Service
+----------------------------
+
+The actual service name, as specified in the `def-service` form in `tutorial.lisp`, is `calculator`. 
+Each service definition defines a global variable with the service name and binds it to a
+service instance whch describes the operations.
+
+In order to start a service, specify a location and the service instance. 
+
+    (in-package :tutorial)
+    (serve #u"thrift://127.0.0.1:9091" calculator)
+
+
+Use a Client to Access the Service Remotely
+-------------------------------------------
+
+
+[in some other process] run the client
+
+    (in-package :cl-user)
+
+    (macrolet ((show (form)
+                 `(format *trace-output* "~%~s =>~{ ~s~}"
+                          ',form
+                          (multiple-value-list (ignore-errors ,form)))))
+      (with-client (protocol #u"thrift://127.0.0.1:9091")
+        (show (tutorial.calculator:ping protocol))
+        (show (tutorial.calculator:add protocol 1 2))
+        (show (tutorial.calculator:add protocol 1 4))
+    
+        (let ((task (make-instance 'tutorial:work
+                      :op operation.subtract :num1 15 :num2 10)))
+          (show (tutorial.calculator:calculate protocol 1 task))
+        
+          (setf (tutorial:work-op task) operation.divide
+                (tutorial:work-num1 task) 1
+                (tutorial:work-num2 task) 0)
+          (show (tutorial.calculator:calculate protocol 1 task)))
+        
+        (show (shared.shared-service:get-struct protocol 1))
+    
+        (show (zip protocol))))
+
+Issues
+------
+
+### optional fields 
+ Where the IDL declares a field options, the def-struct form includes no
+ initform for the slot and the encoding operator skips an unbound slot. This leave some ambiguity
+ with bool fields.
+
+### instantiation protocol :
+ struct classes are standard classes and exception classes are
+ whatever the implementation prescribes. decoders apply make-struct to an initargs list.
+ particularly at the service end, there are advantages to resourcing structs and decoding
+ with direct side-effects on slot-values
+
+### maps:
+ Maps are now represented as hash tables. As data through the call/reply interface is all statically
+ typed, it is not necessary for the objects to themselves indicate the coding form. Association lists
+ would be sufficient. As the key type is arbitrary, property lists offer no additional convenience:
+ as `getf` operates with `eq` a new access interface would be necessary and they would not be
+ available for function application.
+
+
+ [1]: www.common-lisp.net/asdf
+ [2]: http://github.com/lisp/com.b9.puri.ppcre
+ [3]: www.common-lisp.net/closer-mop
+ [4]: trivial-utf-8
+ [5]: https://github.com/usocket/usocket
+ [6]: https://github.com/marijnh/ieee-floats
+ [7]: https://github.com/trivial-gray-streams/trivial-gray-streams
+ [8]: https://gitlab.common-lisp.net/alexandria/alexandria
+ [9]: http://wiki.apache.org/thrift/ThriftGeneration
+
+* usocket[[5]] : for the socket transport
+* ieee-floats[[6]] : for conversion between ints and floats
+* trivial-gray-streams[[7]] : an abstraction layer for gray streams
+* alexandria[[8]] : handy utilities
diff --git a/lib/cl/READMES/readme-cassandra.lisp b/lib/cl/READMES/readme-cassandra.lisp
new file mode 100644
index 0000000..72744ea
--- /dev/null
+++ b/lib/cl/READMES/readme-cassandra.lisp
@@ -0,0 +1,64 @@
+(in-package :cl-user)
+
+#+(or ccl sbcl) /development/source/library/
+(load "build-init.lisp")
+
+;;; ! first, select the api version in the cassandra system definition
+;;; as only one should be loaded at a time.
+(asdf:load-system :de.setf.cassandra)
+
+(in-package :de.setf.cassandra)
+
+(defparameter *c-location*
+  ;; remote
+  ;; #u"thrift://ec2-174-129-66-148.compute-1.amazonaws.com:9160"
+  ;; local
+  #u"thrift://127.0.0.1:9160"
+  "A cassandra service location - either the local one or a remote service 
+ - always a 'thrift' uri.")
+
+(defparameter *c* (thrift:client *c-location*))
+
+
+(cassandra:describe-keyspaces *c*)
+;; => ("Keyspace1" "system")
+
+(cassandra:describe-cluster-name *c*)
+;; =>"Test Cluster"
+
+(cassandra:describe-version *c*)
+;; => "2.1.0"
+
+(loop for space in (cassandra:describe-keyspaces *c*)
+      collect (loop for key being each hash-key of (cassandra:describe-keyspace *c* space)
+                    using (hash-value value)
+                    collect (cons key
+                                  (loop for key being each hash-key of value
+                                        using (hash-value value)
+                                        collect (cons key value)))))
+
+
+(close *c*)
+
+(defun describe-cassandra (location &optional (stream *standard-output*))
+  "Print the first-order store metadata for a cassandra LOCATION."
+
+  (thrift:with-client (cassandra location)
+    (let* ((keyspace-names (cassandra:describe-keyspaces cassandra))
+           (cluster (cassandra:describe-cluster-name cassandra))
+           (version (cassandra:describe-version cassandra))
+           (keyspace-descriptions (loop for space in keyspace-names
+                                        collect (cons space
+                                                      (loop for key being each hash-key
+                                                            of (cassandra:describe-keyspace cassandra space)
+                                                            using (hash-value value)
+                                                            collect (cons key
+                                                                          (loop for key being each hash-key of value
+                                                                                using (hash-value value)
+                                                                                collect (cons key value))))))))
+      (format stream "~&connection to : ~a" cassandra)
+      (format stream "~&version : ~a" version)
+      (format stream "~&cluster : ~a" cluster)
+      (format stream "~&keyspaces~{~{~%~%space: ~a~@{~%  ~{~a :~@{~20t~:w~^~%~}~}~}~}~}" keyspace-descriptions))))
+
+;;; (describe-cassandra *c-location*)
diff --git a/lib/cl/ensure-externals.sh b/lib/cl/ensure-externals.sh
new file mode 100755
index 0000000..0495f03
--- /dev/null
+++ b/lib/cl/ensure-externals.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+set -e
+
+if [[ ! -e quicklisp.lisp ]]; then curl -O https://beta.quicklisp.org/quicklisp.lisp; fi
+sbcl --load quicklisp.lisp \
+     --eval "(ignore-errors (quicklisp-quickstart:install :path \"quicklisp/\"))" \
+     --eval "(load \"quicklisp/setup.lisp\")" \
+     --eval "(quicklisp:bundle-systems '(#:puri #:usocket #:closer-mop #:trivial-utf-8 #:ieee-floats #:trivial-gray-streams #:alexandria #:bordeaux-threads #:cl-ppcre #:fiasco #:net.didierverna.clon) :to \"externals/\")" \
+     --eval "(quit)" \
+     --no-userinit
+if [[ ! -e backport-update.zip ]]; then
+    curl -O -L https://github.com/TurtleWarePL/de.setf.thrift/archive/backport-update.zip;
+fi
+mkdir -p lib
+unzip -u backport-update.zip -d lib
diff --git a/lib/cl/load-locally.lisp b/lib/cl/load-locally.lisp
new file mode 100644
index 0000000..d12c704
--- /dev/null
+++ b/lib/cl/load-locally.lisp
@@ -0,0 +1,23 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+;;;; Just a script for loading the library itself, using bundled dependencies.
+;;;; This is here for when we want to build the self-test and cross-test
+;;;; binaries.
+
+(require "asdf")
+
+(load (merge-pathnames "externals/bundle.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "lib/de.setf.thrift-backport-update/thrift.asd" *load-truename*))
+(asdf:load-system :thrift)
diff --git a/lib/cl/test/make-test-binary.lisp b/lib/cl/test/make-test-binary.lisp
new file mode 100644
index 0000000..60de891
--- /dev/null
+++ b/lib/cl/test/make-test-binary.lisp
@@ -0,0 +1,35 @@
+;;;; 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.
+
+;;;; This file is used to build the binary that runs all self-tests. The
+;;;; binary is then meant to be hooked up to Thrift's `make check` facility,
+;;;; but can easily be run on its own as well.
+
+(in-package #:cl-user)
+
+(require "asdf")
+(load (merge-pathnames "../load-locally.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "../lib/de.setf.thrift-backport-update/test/thrift-test.asd" *load-truename*))
+(asdf:load-system :thrift-test)
+
+(require "sb-grovel") ;; necessary for :net.didierverna.clon.termio
+(asdf:load-asd (first (directory (merge-pathnames "../externals/software/clon-*/termio/net.didierverna.clon.termio.asd"
+                                                  *load-truename*))))
+(asdf:load-system :net.didierverna.clon)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  (let ((result (if (fiasco:run-tests 'thrift-test) 0 -1)))
+    (clon:exit result)))
+
+(clon:dump "run-tests" main)
diff --git a/lib/cpp/CMakeLists.txt b/lib/cpp/CMakeLists.txt
index 13b41c5..6a66e5a 100644
--- a/lib/cpp/CMakeLists.txt
+++ b/lib/cpp/CMakeLists.txt
@@ -182,11 +182,17 @@
 
 if(WITH_ZLIB)
     find_package(ZLIB REQUIRED)
-    include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
 
     ADD_LIBRARY_THRIFT(thriftz ${thriftcppz_SOURCES})
     target_link_libraries(thriftz PUBLIC thrift)
-    target_link_libraries(thriftz PUBLIC ${ZLIB_LIBRARIES})
+
+    if(TARGET ZLIB::ZLIB)
+        target_link_libraries(thriftz PUBLIC ZLIB::ZLIB)
+    else()
+        include_directories(SYSTEM ${ZLIB_INCLUDE_DIRS})
+        target_link_libraries(thriftz PUBLIC ${ZLIB_LIBRARIES})
+    endif()
+
     ADD_PKGCONFIG_THRIFT(thrift-z)
 endif()
 
diff --git a/lib/cpp/src/thrift/transport/TBufferTransports.h b/lib/cpp/src/thrift/transport/TBufferTransports.h
index 3ef8d1f..f72d8f6 100644
--- a/lib/cpp/src/thrift/transport/TBufferTransports.h
+++ b/lib/cpp/src/thrift/transport/TBufferTransports.h
@@ -23,7 +23,6 @@
 #include <cstdlib>
 #include <cstring>
 #include <limits>
-#include <boost/scoped_array.hpp>
 
 #include <thrift/transport/TTransport.h>
 #include <thrift/transport/TVirtualTransport.h>
@@ -281,8 +280,8 @@
 
   uint32_t rBufSize_;
   uint32_t wBufSize_;
-  boost::scoped_array<uint8_t> rBuf_;
-  boost::scoped_array<uint8_t> wBuf_;
+  std::unique_ptr<uint8_t[]> rBuf_;
+  std::unique_ptr<uint8_t[]> wBuf_;
 };
 
 /**
@@ -422,8 +421,8 @@
 
   uint32_t rBufSize_;
   uint32_t wBufSize_;
-  boost::scoped_array<uint8_t> rBuf_;
-  boost::scoped_array<uint8_t> wBuf_;
+  std::unique_ptr<uint8_t[]> rBuf_;
+  std::unique_ptr<uint8_t[]> wBuf_;
   uint32_t bufReclaimThresh_;
   uint32_t maxFrameSize_;
 };
diff --git a/lib/cpp/src/thrift/transport/TFileTransport.cpp b/lib/cpp/src/thrift/transport/TFileTransport.cpp
index 08372b3..3a24e3a 100644
--- a/lib/cpp/src/thrift/transport/TFileTransport.cpp
+++ b/lib/cpp/src/thrift/transport/TFileTransport.cpp
@@ -24,8 +24,6 @@
 #include <thrift/transport/PlatformSocket.h>
 #include <thrift/concurrency/FunctionRunner.h>
 
-#include <boost/version.hpp>
-
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else
@@ -427,7 +425,7 @@
 
             auto* zeros = new uint8_t[padding];
             memset(zeros, '\0', padding);
-            boost::scoped_array<uint8_t> array(zeros);
+            std::unique_ptr<uint8_t[]> array(zeros);
             if (-1 == ::THRIFT_WRITE(fd_, zeros, padding)) {
               int errno_copy = THRIFT_ERRNO;
               GlobalOutput.perror("TFileTransport: writerThread() error while padding zeros ",
diff --git a/lib/cpp/src/thrift/transport/THeaderTransport.h b/lib/cpp/src/thrift/transport/THeaderTransport.h
index 63a4ac8..0343fe3 100644
--- a/lib/cpp/src/thrift/transport/THeaderTransport.h
+++ b/lib/cpp/src/thrift/transport/THeaderTransport.h
@@ -33,8 +33,6 @@
 #include <inttypes.h>
 #endif
 
-#include <boost/scoped_array.hpp>
-
 #include <thrift/protocol/TProtocolTypes.h>
 #include <thrift/transport/TBufferTransports.h>
 #include <thrift/transport/TTransport.h>
@@ -223,7 +221,7 @@
 
   // Buffers to use for transform processing
   uint32_t tBufSize_;
-  boost::scoped_array<uint8_t> tBuf_;
+  std::unique_ptr<uint8_t[]> tBuf_;
 
   void readString(uint8_t*& ptr, /* out */ std::string& str, uint8_t const* headerBoundary);
 
diff --git a/lib/cpp/test/CMakeLists.txt b/lib/cpp/test/CMakeLists.txt
index 19854e1..1117cd9 100644
--- a/lib/cpp/test/CMakeLists.txt
+++ b/lib/cpp/test/CMakeLists.txt
@@ -192,8 +192,8 @@
 set(AllProtocolsTest_SOURCES
     AllProtocolTests.cpp
     AllProtocolTests.tcc
-    GenericHelpers
-    )
+    GenericHelpers.h
+)
 
 add_executable(AllProtocolsTest ${AllProtocolsTest_SOURCES})
 target_link_libraries(AllProtocolsTest
@@ -360,7 +360,7 @@
 )
 
 add_custom_command(OUTPUT gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h
-    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/DebugProtoTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/v0.16/DebugProtoTest.thrift
 )
 
 add_custom_command(OUTPUT gen-cpp/EnumTest_types.cpp gen-cpp/EnumTest_types.h
@@ -384,7 +384,7 @@
 )
 
 add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h
-    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen cpp ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
 )
 
 add_custom_command(OUTPUT gen-cpp/OneWayService.cpp gen-cpp/OneWayTest_types.h gen-cpp/OneWayService.h
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index 7f630db..cd401c0 100644
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -386,7 +386,7 @@
 gen-cpp/AnnotationTest_constants.cpp gen-cpp/AnnotationTest_constants.h gen-cpp/AnnotationTest_types.cpp gen-cpp/AnnotationTest_types.h: $(top_srcdir)/test/AnnotationTest.thrift
 	$(THRIFT) --gen cpp $<
 
-gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h: $(top_srcdir)/test/DebugProtoTest.thrift
+gen-cpp/DebugProtoTest_types.cpp gen-cpp/DebugProtoTest_types.h gen-cpp/EmptyService.cpp gen-cpp/EmptyService.h: $(top_srcdir)/test/v0.16/DebugProtoTest.thrift
 	$(THRIFT) --gen cpp $<
 
 gen-cpp/DoubleConstantsTest_constants.cpp gen-cpp/DoubleConstantsTest_constants.h: $(top_srcdir)/test/DoubleConstantsTest.thrift
@@ -408,7 +408,7 @@
 gen-cpp/Service.cpp gen-cpp/StressTest_types.cpp: $(top_srcdir)/test/StressTest.thrift
 	$(THRIFT) --gen cpp $<
 
-gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: $(top_srcdir)/test/ThriftTest.thrift
+gen-cpp/SecondService.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_types.h: $(top_srcdir)/test/v0.16/ThriftTest.thrift
 	$(THRIFT) --gen cpp $<
 
 gen-cpp/OneWayService.cpp gen-cpp/OneWayTest_types.h gen-cpp/OneWayService.h: OneWayTest.thrift
diff --git a/lib/cpp/test/TransportTest.cpp b/lib/cpp/test/TransportTest.cpp
index 085197a..d6d3859 100644
--- a/lib/cpp/test/TransportTest.cpp
+++ b/lib/cpp/test/TransportTest.cpp
@@ -379,7 +379,7 @@
   // Write some data to the transport to hopefully unblock it.
   auto* buf = new uint8_t[info->writeLength];
   memset(buf, 'b', info->writeLength);
-  boost::scoped_array<uint8_t> array(buf);
+  std::unique_ptr<uint8_t[]> array(buf);
   info->transport->write(buf, info->writeLength);
   info->transport->flush();
 
diff --git a/lib/cpp/test/processor/proc.thrift b/lib/cpp/test/processor/proc.thrift
index ac3c5f9..901467c 100644
--- a/lib/cpp/test/processor/proc.thrift
+++ b/lib/cpp/test/processor/proc.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace cpp apache.thrift.test
 
 exception MyError {
diff --git a/lib/d/src/thrift/base.d b/lib/d/src/thrift/base.d
index 56a4f60..ce706be 100644
--- a/lib/d/src/thrift/base.d
+++ b/lib/d/src/thrift/base.d
@@ -50,7 +50,7 @@
 /// The Thrift version string, used for informative purposes.
 // Note: This is currently hardcoded, but will likely be filled in by the build
 // system in future versions.
-enum VERSION = "0.17.0";
+enum VERSION = "0.18.0";
 
 /**
  * Functions used for logging inside Thrift.
diff --git a/lib/d/test/Makefile.am b/lib/d/test/Makefile.am
index 5ec8255..44364f9 100644
--- a/lib/d/test/Makefile.am
+++ b/lib/d/test/Makefile.am
@@ -23,7 +23,7 @@
 
 debug_proto_gen = $(addprefix gen-d/, DebugProtoTest_types.d)
 
-$(debug_proto_gen): $(top_srcdir)/test/DebugProtoTest.thrift
+$(debug_proto_gen): $(top_srcdir)/test/v0.16/DebugProtoTest.thrift
 	$(THRIFT) --gen d -nowarn $<
 
 stress_test_gen = $(addprefix gen-d/thrift/test/stress/, Service.d \
@@ -35,7 +35,7 @@
 thrift_test_gen = $(addprefix gen-d/thrift/test/, SecondService.d \
 	ThriftTest.d ThriftTest_constants.d ThriftTest_types.d)
 
-$(thrift_test_gen): $(top_srcdir)/test/ThriftTest.thrift
+$(thrift_test_gen): $(top_srcdir)/test/v0.16/ThriftTest.thrift
 	$(THRIFT) --gen d $<
 
 
diff --git a/lib/d/test/thrift_test_runner.sh b/lib/d/test/thrift_test_runner.sh
index 51bfe99..6bec30d 100755
--- a/lib/d/test/thrift_test_runner.sh
+++ b/lib/d/test/thrift_test_runner.sh
@@ -36,8 +36,11 @@
 # or terminated.
 trap "kill $(jobs -p) 2>/dev/null" INT TERM
 
+echo "THRIFT-4905 & THRIFT-5608: SSL tests are disabled.  Fix them."
 for protocol in $protocols; do
-  for ssl in "" " --ssl"; do
+  # TODO: fix and enable ssl
+  # for ssl in "" " --ssl"; do
+  for ssl in ""; do
     for transport in $transports; do
       for server in $servers $framed_only_servers; do
         case $framed_only_servers in
diff --git a/lib/dart/pubspec.yaml b/lib/dart/pubspec.yaml
index a2f4b90..006e219 100644
--- a/lib/dart/pubspec.yaml
+++ b/lib/dart/pubspec.yaml
@@ -16,7 +16,7 @@
 # under the License.
 
 name: thrift
-version: 0.17.0
+version: 0.18.0
 description: >
   A Dart library for Apache Thrift
 author: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/lib/delphi/DelphiThrift.groupproj b/lib/delphi/DelphiThrift.groupproj
index 179f680..3a256dd 100644
--- a/lib/delphi/DelphiThrift.groupproj
+++ b/lib/delphi/DelphiThrift.groupproj
@@ -48,6 +48,9 @@
 			<Projects Include="test\skip\skiptest_version2.dproj">
 				<Dependencies/>
 			</Projects>
+			<Projects Include="test\serializer\SerializerData.dproj">
+				<Dependencies/>
+			</Projects>
 			<Projects Include="test\serializer\TestSerializer.dproj">
 				<Dependencies/>
 			</Projects>
@@ -143,6 +146,15 @@
 		<Target Name="skiptest_version2:Make">
 			<MSBuild Projects="test\skip\skiptest_version2.dproj" Targets="Make"/>
 		</Target>
+		<Target Name="SerializerData">
+			<MSBuild Projects="test\serializer\SerializerData.dproj"/>
+		</Target>
+		<Target Name="SerializerData:Clean">
+			<MSBuild Projects="test\serializer\SerializerData.dproj" Targets="Clean"/>
+		</Target>
+		<Target Name="SerializerData:Make">
+			<MSBuild Projects="test\serializer\SerializerData.dproj" Targets="Make"/>
+		</Target>
 		<Target Name="TestSerializer">
 			<MSBuild Projects="test\serializer\TestSerializer.dproj"/>
 		</Target>
@@ -162,13 +174,13 @@
 			<MSBuild Projects="test\typeregistry\TestTypeRegistry.dproj" Targets="Make"/>
 		</Target>
 		<Target Name="Build">
-			<CallTarget Targets="DelphiServer;DelphiClient;ReservedKeywords;client;server;Multiplex_Test_Client;Multiplex_Test_Server;skiptest_version1;skiptest_version2;TestSerializer;TestTypeRegistry"/>
+			<CallTarget Targets="DelphiServer;DelphiClient;ReservedKeywords;client;server;Multiplex_Test_Client;Multiplex_Test_Server;skiptest_version1;skiptest_version2;SerializerData;TestSerializer;TestTypeRegistry"/>
 		</Target>
 		<Target Name="Clean">
-			<CallTarget Targets="DelphiServer:Clean;DelphiClient:Clean;ReservedKeywords:Clean;client:Clean;server:Clean;Multiplex_Test_Client:Clean;Multiplex_Test_Server:Clean;skiptest_version1:Clean;skiptest_version2:Clean;TestSerializer:Clean;TestTypeRegistry:Clean"/>
+			<CallTarget Targets="DelphiServer:Clean;DelphiClient:Clean;ReservedKeywords:Clean;client:Clean;server:Clean;Multiplex_Test_Client:Clean;Multiplex_Test_Server:Clean;skiptest_version1:Clean;skiptest_version2:Clean;SerializerData:Clean;TestSerializer:Clean;TestTypeRegistry:Clean"/>
 		</Target>
 		<Target Name="Make">
-			<CallTarget Targets="DelphiServer:Make;DelphiClient:Make;ReservedKeywords:Make;client:Make;server:Make;Multiplex_Test_Client:Make;Multiplex_Test_Server:Make;skiptest_version1:Make;skiptest_version2:Make;TestSerializer:Make;TestTypeRegistry:Make"/>
+			<CallTarget Targets="DelphiServer:Make;DelphiClient:Make;ReservedKeywords:Make;client:Make;server:Make;Multiplex_Test_Client:Make;Multiplex_Test_Server:Make;skiptest_version1:Make;skiptest_version2:Make;SerializerData:Make;TestSerializer:Make;TestTypeRegistry:Make"/>
 		</Target>
 		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')" Project="$(BDS)\Bin\CodeGear.Group.Targets"/>
 	</Project>
diff --git a/lib/delphi/src/Thrift.Collections.pas b/lib/delphi/src/Thrift.Collections.pas
index ad852ac..36a8d96 100644
--- a/lib/delphi/src/Thrift.Collections.pas
+++ b/lib/delphi/src/Thrift.Collections.pas
@@ -190,7 +190,7 @@
     function ToString : string;  override;
   end;
 
-  IHashSet<TValue> = interface(IThriftContainer)
+  IThriftHashSet<TValue> = interface(IThriftContainer)
     ['{0923A3B5-D4D4-48A8-91AD-40238E2EAD66}']
     function GetEnumerator: TEnumerator<TValue>;
     function GetIsReadOnly: Boolean;
@@ -204,7 +204,15 @@
     function Remove( const item: TValue ): Boolean;
   end;
 
-  THashSetImpl<TValue> = class( TInterfacedObject, IHashSet<TValue>, IThriftContainer, ISupportsToString)
+  // compatibility
+  IHashSet<TValue> = interface( IThriftHashSet<TValue>)
+    ['{C3CF557F-21D9-4524-B899-D3145B0389BB}']
+  end deprecated 'use IThriftHashSet<T>';
+
+
+  {$WARN SYMBOL_DEPRECATED OFF}
+  TThriftHashSetImpl<TValue> = class( TInterfacedObject, IHashSet<TValue>, IThriftHashSet<TValue>, IThriftContainer, ISupportsToString)
+  {$WARN SYMBOL_DEPRECATED DEFAULT}
   strict private
     FDictionary : IThriftDictionary<TValue,Integer>;
     FIsReadOnly: Boolean;
@@ -224,11 +232,15 @@
     function ToString : string;  override;
   end;
 
+  // compatibility
+  THashSetImpl<TValue> = class( TThriftHashSetImpl<TValue>)
+  end deprecated 'use TThriftHashSetImpl<T>';
+
 implementation
 
-{ THashSetImpl<TValue> }
+{ TThriftHashSetImpl<TValue>. }
 
-procedure THashSetImpl<TValue>.Add( const item: TValue);
+procedure TThriftHashSetImpl<TValue>.Add( const item: TValue);
 begin
   if not FDictionary.ContainsKey(item) then
   begin
@@ -236,17 +248,17 @@
   end;
 end;
 
-procedure THashSetImpl<TValue>.Clear;
+procedure TThriftHashSetImpl<TValue>.Clear;
 begin
   FDictionary.Clear;
 end;
 
-function THashSetImpl<TValue>.Contains( const item: TValue): Boolean;
+function TThriftHashSetImpl<TValue>.Contains( const item: TValue): Boolean;
 begin
   Result := FDictionary.ContainsKey(item);
 end;
 
-procedure THashSetImpl<TValue>.CopyTo(var A: TArray<TValue>; arrayIndex: Integer);
+procedure TThriftHashSetImpl<TValue>.CopyTo(var A: TArray<TValue>; arrayIndex: Integer);
 var
   i : Integer;
   Enumlator : TEnumerator<TValue>;
@@ -259,28 +271,28 @@
   end;
 end;
 
-constructor THashSetImpl<TValue>.Create;
+constructor TThriftHashSetImpl<TValue>.Create;
 begin
   inherited;
   FDictionary := TThriftDictionaryImpl<TValue,Integer>.Create;
 end;
 
-function THashSetImpl<TValue>.GetCount: Integer;
+function TThriftHashSetImpl<TValue>.GetCount: Integer;
 begin
   Result := FDictionary.Count;
 end;
 
-function THashSetImpl<TValue>.GetEnumerator: TEnumerator<TValue>;
+function TThriftHashSetImpl<TValue>.GetEnumerator: TEnumerator<TValue>;
 begin
   Result := FDictionary.Keys.GetEnumerator;
 end;
 
-function THashSetImpl<TValue>.GetIsReadOnly: Boolean;
+function TThriftHashSetImpl<TValue>.GetIsReadOnly: Boolean;
 begin
   Result := FIsReadOnly;
 end;
 
-function THashSetImpl<TValue>.Remove( const item: TValue): Boolean;
+function TThriftHashSetImpl<TValue>.Remove( const item: TValue): Boolean;
 begin
   Result := False;
   if FDictionary.ContainsKey( item ) then
@@ -290,7 +302,7 @@
   end;
 end;
 
-function THashSetImpl<TValue>.ToString : string;
+function TThriftHashSetImpl<TValue>.ToString : string;
 var elm : TValue;
     sb : TThriftStringBuilder;
     first : Boolean;
diff --git a/lib/delphi/src/Thrift.Protocol.Compact.pas b/lib/delphi/src/Thrift.Protocol.Compact.pas
index 3a1dbfd..80f1ce5 100644
--- a/lib/delphi/src/Thrift.Protocol.Compact.pas
+++ b/lib/delphi/src/Thrift.Protocol.Compact.pas
@@ -77,7 +77,8 @@
       LIST          = $09,
       SET_          = $0A,
       MAP           = $0B,
-      STRUCT        = $0C
+      STRUCT        = $0C,
+      UUID          = $0D
     );
 
   private type
@@ -100,7 +101,8 @@
       Types.STRUCT,         // Struct  = 12,
       Types.MAP,            // Map     = 13,
       Types.SET_,           // Set_    = 14,
-      Types.LIST            // List    = 15,
+      Types.LIST,           // List    = 15,
+      Types.UUID            // Uuid    = 16
     );
 
     tcompactTypeToType : array[Types] of TType = (
@@ -116,7 +118,8 @@
       TType.List,       // LIST
       TType.Set_,       // SET_
       TType.Map,        // MAP
-      TType.Struct      // STRUCT
+      TType.Struct,     // STRUCT
+      TType.Uuid        // UUID
     );
 
   strict private
@@ -173,6 +176,7 @@
     procedure WriteI64( const i64: Int64); override;
     procedure WriteDouble( const dub: Double); override;
     procedure WriteBinary( const b: TBytes); overload; override;
+    procedure WriteUuid( const uuid: TGuid); override;
 
   private  // unit visible stuff
     class function  DoubleToInt64Bits( const db : Double) : Int64;
@@ -219,6 +223,7 @@
     function  ReadI64: Int64; override;
     function  ReadDouble:Double; override;
     function  ReadBinary: TBytes; overload; override;
+    function  ReadUuid: TGuid; override;
 
   private
     // Internal Reading methods
@@ -537,6 +542,14 @@
   Transport.Write( b);
 end;
 
+procedure TCompactProtocolImpl.WriteUuid( const uuid: TGuid);
+var network : TGuid;  // in network order (Big Endian)
+begin
+  ASSERT( SizeOf(uuid) = 16);
+  network := GuidUtils.SwapByteOrder(uuid);
+  Transport.Write( @network, 0, SizeOf(network));
+end;
+
 procedure TCompactProtocolImpl.WriteMessageEnd;
 begin
   // nothing to do
@@ -850,6 +863,14 @@
   then Transport.ReadAll( result, 0, length);
 end;
 
+function TCompactProtocolImpl.ReadUuid: TGuid;
+var network : TGuid;  // in network order (Big Endian)
+begin
+  ASSERT( SizeOf(result) = 16);
+  FTrans.ReadAll( @network, SizeOf(network), 0, SizeOf(network));
+  result := GuidUtils.SwapByteOrder(network);
+end;
+
 
 procedure TCompactProtocolImpl.ReadMessageEnd;
 begin
@@ -994,6 +1015,7 @@
     TType.Map:     result := SizeOf(Byte);  // element count
     TType.Set_:    result := SizeOf(Byte);  // element count
     TType.List:    result := SizeOf(Byte);  // element count
+    TType.Uuid:    result := SizeOf(TGuid);
   else
     raise TTransportExceptionBadArgs.Create('Unhandled type code');
   end;
diff --git a/lib/delphi/src/Thrift.Protocol.JSON.pas b/lib/delphi/src/Thrift.Protocol.JSON.pas
index 52909b7..2a9682c 100644
--- a/lib/delphi/src/Thrift.Protocol.JSON.pas
+++ b/lib/delphi/src/Thrift.Protocol.JSON.pas
@@ -198,6 +198,7 @@
     procedure WriteDouble( const d: Double); override;
     procedure WriteString( const s: string );   override;
     procedure WriteBinary( const b: TBytes); override;
+    procedure WriteUuid( const uuid: TGuid); override;
     //
     function ReadMessageBegin: TThriftMessage; override;
     procedure ReadMessageEnd(); override;
@@ -219,6 +220,7 @@
     function ReadDouble:Double; override;
     function ReadString : string;  override;
     function ReadBinary: TBytes; override;
+    function ReadUuid: TGuid; override;
 
 
   strict private
@@ -288,6 +290,7 @@
   NAME_MAP    = 'map';
   NAME_LIST   = 'lst';
   NAME_SET    = 'set';
+  NAME_UUID   = 'uid';
 
   INVARIANT_CULTURE : TFormatSettings
                     = ( ThousandSeparator: ',';
@@ -317,6 +320,7 @@
     TType.Map:      result := NAME_MAP;
     TType.Set_:     result := NAME_SET;
     TType.List:     result := NAME_LIST;
+    TType.Uuid:     result := NAME_UUID;
   else
     raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+IntToStr(Ord(typeID))+')');
   end;
@@ -336,6 +340,7 @@
   else if name = NAME_MAP    then result := TType.Map
   else if name = NAME_LIST   then result := TType.List
   else if name = NAME_SET    then result := TType.Set_
+  else if name = NAME_UUID   then result := TType.Uuid
   else raise TProtocolExceptionNotImplemented.Create('Unrecognized type ('+name+')');
 end;
 
@@ -831,6 +836,11 @@
   WriteJSONBase64( b);
 end;
 
+procedure TJSONProtocolImpl.WriteUuid( const uuid: TGuid);
+begin
+  WriteString( Copy( GuidToString(uuid), 2, 36));  // strip off the { braces }
+end;
+
 
 function TJSONProtocolImpl.ReadJSONString( skipContext : Boolean) : TBytes;
 var buffer : TThriftMemoryStream;
@@ -1237,6 +1247,12 @@
 end;
 
 
+function TJSONProtocolImpl.ReadUuid: TGuid;
+begin
+  result := StringToGUID( '{' + ReadString + '}');
+end;
+
+
 function TJSONProtocolImpl.GetMinSerializedSize( const aType : TType) : Integer;
 // Return the minimum number of bytes a type will consume on the wire
 begin
@@ -1254,6 +1270,7 @@
     TType.Map:     result := 2;  // empty map
     TType.Set_:    result := 2;  // empty set
     TType.List:    result := 2;  // empty list
+    TType.Uuid:    result := 36; // "E236974D-F0B0-4E05-8F29-0B455D41B1A1"
   else
     raise TTransportExceptionBadArgs.Create('Unhandled type code');
   end;
diff --git a/lib/delphi/src/Thrift.Protocol.pas b/lib/delphi/src/Thrift.Protocol.pas
index 03cc371..c6b1a00 100644
--- a/lib/delphi/src/Thrift.Protocol.pas
+++ b/lib/delphi/src/Thrift.Protocol.pas
@@ -49,7 +49,8 @@
     Struct = 12,
     Map = 13,
     Set_ = 14,
-    List = 15
+    List = 15,
+    Uuid = 16
   );
 
   TMessageType = (
@@ -62,7 +63,7 @@
 const
   VALID_TTYPES = [
     TType.Stop, TType.Void,
-    TType.Bool_, TType.Byte_, TType.Double_, TType.I16, TType.I32, TType.I64, TType.String_,
+    TType.Bool_, TType.Byte_, TType.Double_, TType.I16, TType.I32, TType.I64, TType.String_, TType.Uuid,
     TType.Struct, TType.Map, TType.Set_, TType.List
   ];
 
@@ -193,8 +194,10 @@
     destructor Destroy; override;
   end;
 
+  IThriftBytes = interface; // forward
+
   IProtocol = interface
-    ['{F0040D99-937F-400D-9932-AF04F665899F}']
+    ['{6067A28E-15BF-4C9D-9A6F-D991BB3DCB85}']
     function GetTransport: ITransport;
     procedure WriteMessageBegin( const msg: TThriftMessage);
     procedure WriteMessageEnd;
@@ -217,7 +220,9 @@
     procedure WriteDouble( const d: Double);
     procedure WriteString( const s: string );
     procedure WriteAnsiString( const s: AnsiString);
-    procedure WriteBinary( const b: TBytes);
+    procedure WriteBinary( const b: TBytes); overload;
+    procedure WriteBinary( const b: IThriftBytes); overload;
+    procedure WriteUuid( const uuid: TGuid);
 
     function ReadMessageBegin: TThriftMessage;
     procedure ReadMessageEnd();
@@ -237,7 +242,9 @@
     function ReadI32: Integer;
     function ReadI64: Int64;
     function ReadDouble:Double;
-    function ReadBinary: TBytes;
+    function ReadBinary: TBytes;  // IMPORTANT: this is NOT safe across module boundaries
+    function ReadBinaryCOM : IThriftBytes;
+    function ReadUuid: TGuid;
     function ReadString: string;
     function ReadAnsiString: AnsiString;
 
@@ -292,7 +299,8 @@
     procedure WriteDouble( const d: Double); virtual; abstract;
     procedure WriteString( const s: string ); virtual;
     procedure WriteAnsiString( const s: AnsiString); virtual;
-    procedure WriteBinary( const b: TBytes); virtual; abstract;
+    procedure WriteBinary( const b: TBytes); overload; virtual; abstract;
+    procedure WriteUuid( const b: TGuid); virtual; abstract;
 
     function ReadMessageBegin: TThriftMessage; virtual; abstract;
     procedure ReadMessageEnd(); virtual; abstract;
@@ -313,9 +321,14 @@
     function ReadI64: Int64; virtual; abstract;
     function ReadDouble:Double; virtual; abstract;
     function ReadBinary: TBytes; virtual; abstract;
+    function ReadUuid: TGuid; virtual; abstract;
     function ReadString: string; virtual;
     function ReadAnsiString: AnsiString; virtual;
 
+    // provide generic implementation for all derived classes
+    procedure WriteBinary( const bytes : IThriftBytes); overload; virtual;
+    function ReadBinaryCOM : IThriftBytes;  virtual;
+
     property  Transport: ITransport read GetTransport;
 
   public
@@ -324,8 +337,38 @@
 
   IBase = interface( ISupportsToString)
     ['{AFF6CECA-5200-4540-950E-9B89E0C1C00C}']
-    procedure Read( const iprot: IProtocol);
-    procedure Write( const iprot: IProtocol);
+    procedure Read( const prot: IProtocol);
+    procedure Write( const prot: IProtocol);
+  end;
+
+
+  IThriftBytes = interface( ISupportsToString)
+    ['{CDBEF7E8-BEF2-4A0A-983A-F334E3FF0016}']
+    function  GetCount : Integer;
+    procedure SetCount(const value : Integer);
+
+    // WARNING: This returns a direct pointer to the underlying data structure
+    function  QueryRawDataPtr : Pointer;
+
+    property Count : Integer read GetCount write SetCount;
+  end;
+
+
+  TThriftBytesImpl = class( TInterfacedObject, IThriftBytes, ISupportsToString)
+  strict private
+    FData : TBytes;
+
+  strict protected
+    function  GetCount : Integer;
+    procedure SetCount(const value : Integer);
+    function  QueryRawDataPtr : Pointer;
+
+  public
+    constructor Create; overload;
+    constructor Create( const bytes : TBytes); overload;
+    constructor Create( var bytes : TBytes; const aTakeOwnership : Boolean = FALSE); overload;
+
+    function ToString : string; override;
   end;
 
 
@@ -377,6 +420,7 @@
     procedure WriteI64( const i64: Int64); override;
     procedure WriteDouble( const d: Double); override;
     procedure WriteBinary( const b: TBytes); override;
+    procedure WriteUuid( const uuid: TGuid); override;
 
     function ReadMessageBegin: TThriftMessage; override;
     procedure ReadMessageEnd(); override;
@@ -397,6 +441,7 @@
     function ReadI64: Int64; override;
     function ReadDouble:Double; override;
     function ReadBinary: TBytes; override;
+    function ReadUuid: TGuid; override;
 
   end;
 
@@ -441,6 +486,7 @@
     procedure WriteString( const s: string ); override;
     procedure WriteAnsiString( const s: AnsiString); override;
     procedure WriteBinary( const b: TBytes); override;
+    procedure WriteUuid( const uuid: TGuid); override;
 
     function ReadMessageBegin: TThriftMessage; override;
     procedure ReadMessageEnd(); override;
@@ -461,6 +507,7 @@
     function ReadI64: Int64; override;
     function ReadDouble:Double; override;
     function ReadBinary: TBytes; override;
+    function ReadUuid: TGuid; override;
     function ReadString: string; override;
     function ReadAnsiString: AnsiString; override;
   end;
@@ -653,6 +700,95 @@
   FTrans.CheckReadBytesAvailable( value.Count * nPairSize);
 end;
 
+
+procedure TProtocolImpl.WriteBinary( const bytes : IThriftBytes);
+var tmp : TBytes;
+begin
+  SetLength( tmp, bytes.Count);
+  if Length(tmp) > 0
+  then Move( bytes.QueryRawDataPtr^, tmp[0], Length(tmp));
+  WriteBinary( tmp);
+end;
+
+
+function TProtocolImpl.ReadBinaryCOM : IThriftBytes;
+var bytes : TBytes;
+begin
+  bytes := ReadBinary;
+  result := TThriftBytesImpl.Create(bytes,TRUE);
+end;
+
+
+{ TThriftBytesImpl }
+
+constructor TThriftBytesImpl.Create;
+begin
+  inherited Create;
+  ASSERT( Length(FData) = 0);
+end;
+
+
+constructor TThriftBytesImpl.Create( const bytes : TBytes);
+begin
+  FData := bytes; // copies the data
+end;
+
+
+constructor TThriftBytesImpl.Create( var bytes : TBytes; const aTakeOwnership : Boolean);
+
+  procedure SwapPointer( var one, two);
+  var
+    pOne : Pointer absolute one;
+    pTwo : Pointer absolute two;
+    pTmp : Pointer;
+  begin
+    pTmp := pOne;
+    pOne := pTwo;
+    pTwo := pTmp;
+  end;
+
+begin
+  inherited Create;
+  ASSERT( Length(FData) = 0);
+
+  if aTakeOwnership
+  then SwapPointer( FData, bytes)
+  else FData := bytes; // copies the data
+end;
+
+
+function TThriftBytesImpl.ToString : string;
+var sb : TThriftStringBuilder;
+begin
+  sb := TThriftStringBuilder.Create();
+  try
+    sb.Append('Bin: ');
+    sb.Append( FData);
+
+    result := sb.ToString;
+  finally
+    sb.Free;
+  end;
+end;
+
+
+function TThriftBytesImpl.GetCount : Integer;
+begin
+  result := Length(FData);
+end;
+
+
+procedure TThriftBytesImpl.SetCount(const value : Integer);
+begin
+  SetLength( FData, value);
+end;
+
+
+function TThriftBytesImpl.QueryRawDataPtr : Pointer;
+begin
+  result := FData;
+end;
+
 { TProtocolUtil }
 
 class procedure TProtocolUtil.Skip( prot: IProtocol; type_: TType);
@@ -673,6 +809,7 @@
     TType.I64     :  prot.ReadI64();
     TType.Double_ :  prot.ReadDouble();
     TType.String_ :  prot.ReadBinary();// Don't try to decode the string, just skip it.
+    TType.Uuid    :  prot.ReadUuid();
 
     // structured types
     TType.Struct :  begin
@@ -747,6 +884,14 @@
   Result := buf;
 end;
 
+function TBinaryProtocolImpl.ReadUuid : TGuid;
+var network : TGuid;  // in network order (Big Endian)
+begin
+  ASSERT( SizeOf(result) = 16);
+  FTrans.ReadAll( @network, SizeOf(network), 0, SizeOf(network));
+  result := GuidUtils.SwapByteOrder(network);
+end;
+
 function TBinaryProtocolImpl.ReadBool: Boolean;
 begin
   Result := (ReadByte = 1);
@@ -915,6 +1060,14 @@
   if iLen > 0 then FTrans.Write(b, 0, iLen);
 end;
 
+procedure TBinaryProtocolImpl.WriteUuid( const uuid: TGuid);
+var network : TGuid;  // in network order (Big Endian)
+begin
+  ASSERT( SizeOf(uuid) = 16);
+  network := GuidUtils.SwapByteOrder(uuid);
+  Transport.Write( @network, 0, SizeOf(network));
+end;
+
 procedure TBinaryProtocolImpl.WriteBool(b: Boolean);
 begin
   if b then begin
@@ -1064,6 +1217,7 @@
     TType.Map:     result := SizeOf(Int32);  // element count
     TType.Set_:    result := SizeOf(Int32);  // element count
     TType.List:    result := SizeOf(Int32);  // element count
+    TType.Uuid:    result := SizeOf(TGuid);
   else
     raise TTransportExceptionBadArgs.Create('Unhandled type code');
   end;
@@ -1310,6 +1464,12 @@
 end;
 
 
+procedure TProtocolDecorator.WriteUuid( const uuid: TGuid);
+begin
+  FWrappedProtocol.WriteUuid( uuid);
+end;
+
+
 function TProtocolDecorator.ReadMessageBegin: TThriftMessage;
 begin
   result := FWrappedProtocol.ReadMessageBegin;
@@ -1424,6 +1584,12 @@
 end;
 
 
+function TProtocolDecorator.ReadUuid: TGuid;
+begin
+  result := FWrappedProtocol.ReadUuid;
+end;
+
+
 function TProtocolDecorator.ReadString: string;
 begin
   result := FWrappedProtocol.ReadString;
diff --git a/lib/delphi/src/Thrift.Transport.pas b/lib/delphi/src/Thrift.Transport.pas
index 3f22b09..fd08837 100644
--- a/lib/delphi/src/Thrift.Transport.pas
+++ b/lib/delphi/src/Thrift.Transport.pas
@@ -596,7 +596,7 @@
 procedure TEndpointTransportBase.CheckReadBytesAvailable( const numBytes : Int64);
 // Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data
 begin
-  if RemainingMessageSize < numBytes
+  if (RemainingMessageSize < numBytes) or (numBytes < 0)
   then raise TTransportExceptionEndOfFile.Create('MaxMessageSize reached');
 end;
 
@@ -604,7 +604,7 @@
 procedure TEndpointTransportBase.CountConsumedMessageBytes( const numBytes : Int64);
 // Consumes numBytes from the RemainingMessageSize.
 begin
-  if (RemainingMessageSize >= numBytes)
+  if (RemainingMessageSize >= numBytes) and (numBytes >= 0)
   then Dec( FRemainingMessageSize, numBytes)
   else begin
     FRemainingMessageSize := 0;
diff --git a/lib/delphi/src/Thrift.Utils.pas b/lib/delphi/src/Thrift.Utils.pas
index 4a75af8..fff6b86 100644
--- a/lib/delphi/src/Thrift.Utils.pas
+++ b/lib/delphi/src/Thrift.Utils.pas
@@ -84,11 +84,37 @@
     class function IsHtmlDoctype( const fourBytes : Integer) : Boolean; static;
   end;
 
+
+  IntegerUtils = class sealed
+  strict private
+    class procedure SwapBytes( var one, two : Byte); static; inline;
+    class procedure Swap2( const pValue : Pointer); static;
+    class procedure Swap4( const pValue : Pointer); static;
+    class procedure Swap8( const pValue : Pointer); static;
+  public
+    class procedure SwapByteOrder( const pValue : Pointer; const size : Integer); overload; static;
+  end;
+
+
+  // problem: inheritance possible for class helpers ONLY but not with record helpers
+  // workaround: use static class method instead of record helper :-(
+  GuidUtils = class sealed
+  public
+    // new stuff
+    class function SwapByteOrder( const aGuid : TGuid) : TGuid; static;
+
+    {$IFDEF Debug}
+    class procedure SelfTest; static;
+    {$ENDIF}
+  end;
+
+
   EnumUtils<T> = class sealed
   public
     class function ToString(const value : Integer) : string;  reintroduce; static; inline;
   end;
 
+
   StringUtils<T> = class sealed
   public
     class function ToString(const value : T) : string;  reintroduce; static; inline;
@@ -283,6 +309,100 @@
   result := (UpCase(pc^) = HTML_BEGIN[3]);
 end;
 
+{ IntegerUtils }
+
+
+class procedure IntegerUtils.SwapBytes( var one, two : Byte);
+var tmp : Byte;
+begin
+  tmp := one;
+  one := two;
+  two := tmp;
+end;
+
+
+class procedure IntegerUtils.Swap2( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+  SwapBytes( pData^[0], pData^[1]);
+end;
+
+
+class procedure IntegerUtils.Swap4( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+  SwapBytes( pData^[0], pData^[3]);
+  SwapBytes( pData^[1], pData^[2]);
+end;
+
+
+class procedure IntegerUtils.Swap8( const pValue : Pointer);
+var pData : PByteArray absolute pValue;
+begin
+  SwapBytes( pData^[0], pData^[7]);
+  SwapBytes( pData^[1], pData^[6]);
+  SwapBytes( pData^[2], pData^[5]);
+  SwapBytes( pData^[3], pData^[4]);
+end;
+
+
+class procedure IntegerUtils.SwapByteOrder( const pValue : Pointer; const size : Integer);
+begin
+  case size of
+    2 : Swap2( pValue);
+    4 : Swap4( pValue);
+    8 : Swap8( pValue);
+  else
+    raise EArgumentException.Create('Unexpected size');
+  end;
+end;
+
+
+{ GuidUtils }
+
+
+class function GuidUtils.SwapByteOrder( const aGuid : TGuid) : TGuid;
+// convert to/from network byte order
+// - https://www.ietf.org/rfc/rfc4122.txt
+// - https://stackoverflow.com/questions/10850075/guid-uuid-compatibility-issue-between-net-and-linux
+// - https://lists.gnu.org/archive/html/bug-parted/2002-01/msg00099.html
+begin
+  result := aGuid;
+
+  IntegerUtils.SwapByteOrder( @result.D1, SizeOf(result.D1));
+  IntegerUtils.SwapByteOrder( @result.D2, SizeOf(result.D2));
+  IntegerUtils.SwapByteOrder( @result.D3, SizeOf(result.D3));
+  //result.D4 = array of byte -> implicitly correct
+end;
+
+
+{$IFDEF Debug}
+class procedure GuidUtils.SelfTest;
+var guid   : TGuid;
+    pBytes : PByteArray;
+    i, expected : Integer;
+const TEST_GUID : TGuid = '{00112233-4455-6677-8899-aabbccddeeff}';
+begin
+  // host to network
+  guid := TEST_GUID;
+  guid := GuidUtils.SwapByteOrder(guid);
+
+  // validate network order
+  pBytes := @guid;
+  for i := 0 to $F do begin
+    expected := i * $11;
+    ASSERT( pBytes^[i] = expected);
+  end;
+
+  // network to host and final validation
+  guid := GuidUtils.SwapByteOrder(guid);
+  ASSERT( IsEqualGuid( guid, TEST_GUID));
+
+  // prevent collisions with SysUtils.TGuidHelper
+  guid := TGuid.NewGuid;
+end;
+{$ENDIF}
+
 
 
 {$IFDEF Win64}
@@ -378,4 +498,8 @@
 end;
 
 
+begin
+  {$IFDEF Debug}
+  GuidUtils.SelfTest;
+  {$ENDIF}
 end.
diff --git a/lib/delphi/src/Thrift.pas b/lib/delphi/src/Thrift.pas
index f8841f3..6fcc65d 100644
--- a/lib/delphi/src/Thrift.pas
+++ b/lib/delphi/src/Thrift.pas
@@ -28,7 +28,7 @@
   Thrift.Protocol;
 
 const
-  Version = '0.17.0';
+  Version = '0.18.0';
 
 type
   TException = Thrift.Exception.TException; // compatibility alias
diff --git a/lib/delphi/test/ConsoleHelper.pas b/lib/delphi/test/ConsoleHelper.pas
index 0a8ddcf..23c6adc 100644
--- a/lib/delphi/test/ConsoleHelper.pas
+++ b/lib/delphi/test/ConsoleHelper.pas
@@ -21,31 +21,43 @@
 
 interface
 
-uses Classes;
+uses Classes, SysUtils, SyncObjs;
 
 type
   TThriftConsole = class
+  strict private
+    FLock : TCriticalSection;
+  strict protected
+    procedure Lock;
+    procedure UnLock;
   public
+    constructor Create;
+    destructor Destroy; override;
+
     procedure Write( const S: string); virtual;
     procedure WriteLine( const S: string); virtual;
   end;
 
+
   TGUIConsole = class( TThriftConsole )
-  private
+  strict private
     FLineBreak : Boolean;
     FMemo : TStrings;
 
     procedure InternalWrite( const S: string; bWriteLine: Boolean);
   public
+    constructor Create( AMemo: TStrings);
+
     procedure Write( const S: string); override;
     procedure WriteLine( const S: string); override;
-    constructor Create( AMemo: TStrings);
   end;
 
+
 function Console: TThriftConsole;
 procedure ChangeConsole( AConsole: TThriftConsole );
 procedure RestoreConsoleToDefault;
 
+
 implementation
 
 var
@@ -59,14 +71,46 @@
 
 { TThriftConsole }
 
+constructor TThriftConsole.Create;
+begin
+  inherited Create;
+  FLock := TCriticalSection.Create;
+end;
+
+destructor TThriftConsole.Destroy;
+begin
+  FreeAndNil( FLock);
+  inherited Destroy;
+end;
+
+procedure TThriftConsole.Lock;
+begin
+  FLock.Enter;
+end;
+
+procedure TThriftConsole.UnLock;
+begin
+  FLock.Leave;
+end;
+
 procedure TThriftConsole.Write(const S: string);
 begin
-  System.Write( S );
+  Lock;
+  try
+    System.Write( S );
+  finally
+    Unlock;
+  end;
 end;
 
 procedure TThriftConsole.WriteLine(const S: string);
 begin
-  System.Writeln( S );
+  Lock;
+  try
+    System.Writeln( S );
+  finally
+    Unlock;
+  end;
 end;
 
 procedure ChangeConsole( AConsole: TThriftConsole );
@@ -89,21 +133,25 @@
 end;
 
 procedure TGUIConsole.InternalWrite(const S: string; bWriteLine: Boolean);
-var
-  idx : Integer;
+var idx : Integer;
 begin
-  if FLineBreak then
-  begin
-    FMemo.Add( S );
-  end else
-  begin
-    idx := FMemo.Count - 1;
-    if idx < 0 then
+  Lock;
+  try
+
+    if FLineBreak then begin
       FMemo.Add( S )
-    else
-      FMemo[idx] := FMemo[idx] + S;
+    end
+    else begin
+      idx := FMemo.Count - 1;
+      if idx < 0
+      then FMemo.Add( S )
+      else FMemo[idx] := FMemo[idx] + S;
+    end;
+    FLineBreak := bWriteLine;
+
+  finally
+    Unlock;
   end;
-  FLineBreak := bWriteLine;
 end;
 
 procedure TGUIConsole.Write(const S: string);
@@ -117,15 +165,12 @@
 end;
 
 initialization
-begin
   FDefaultConsole := TThriftConsole.Create;
   FConsole := FDefaultConsole;
-end;
 
 finalization
-begin
   FDefaultConsole.Free;
-end;
+  FDefaultConsole := nil;
 
 end.
 
diff --git a/lib/delphi/test/Performance/DataFactory.pas b/lib/delphi/test/Performance/DataFactory.pas
index e131822..e6d70d9 100644
--- a/lib/delphi/test/Performance/DataFactory.pas
+++ b/lib/delphi/test/Performance/DataFactory.pas
@@ -26,17 +26,17 @@
 type
   TestDataFactory = class
   strict protected
-    class function CreateSetField(const count : Integer) : IHashSet< IInsanity>;  static;
+    class function CreateSetField(const count : Integer) : IThriftHashSet< IInsanity>;  static;
     class function CreateInsanity(const count : Integer) : IInsanity; static;
     class function CreateBytesArray(const count : Integer) : TBytes; static;
     class function CreateXtructs(const count : Integer) : IThriftList< IXtruct>; static;
     class function CreateXtruct(const count : Integer) : IXtruct; static;
-    class function CreateListField(const count : Integer) : IThriftList< IThriftDictionary< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>; static;
+    class function CreateListField(const count : Integer) : IThriftList< IThriftDictionary< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>; static;
     class function CreateUserMap(const count : Integer) : IThriftDictionary< TNumberz, Int64>; static;
-    class function CreateListFieldData(const count : Integer) : IThriftDictionary< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>; static;
-    class function CreateIntHashSet(const count : Integer) : IHashSet< Integer>; static;
-    class function CreateListFieldDataDict(const count : Integer) : IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>; static;
-    class function CreateListFieldDataDictValue(const count : Integer) :  IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>; static;
+    class function CreateListFieldData(const count : Integer) : IThriftDictionary< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>; static;
+    class function CreateIntHashSet(const count : Integer) : IThriftHashSet< Integer>; static;
+    class function CreateListFieldDataDict(const count : Integer) : IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>; static;
+    class function CreateListFieldDataDictValue(const count : Integer) :  IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>; static;
     class function CreateListFieldDataDictValueList(const count : Integer) : IThriftList< IThriftDictionary< IInsanity, string>>; static;
     class function CreateListFieldDataDictValueListDict(const count : Integer) : IThriftDictionary< IInsanity, string>; static;
   public
@@ -58,10 +58,10 @@
   result.String_field := Format('data level %d', [count]);
 end;
 
-class function TestDataFactory.CreateSetField(const count : Integer) : IHashSet< IInsanity>;
+class function TestDataFactory.CreateSetField(const count : Integer) : IThriftHashSet< IInsanity>;
 var i : Integer;
 begin
-  result := THashSetImpl< IInsanity>.Create;
+  result := TThriftHashSetImpl< IInsanity>.Create;
   for i := 0 to count-1 do begin
     result.Add(CreateInsanity(count));
   end;
@@ -103,46 +103,46 @@
   result.Add(TNumberz.EIGHT, count);
 end;
 
-class function TestDataFactory.CreateListField(const count : Integer) : IThriftList< IThriftDictionary< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>;
+class function TestDataFactory.CreateListField(const count : Integer) : IThriftList< IThriftDictionary< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>;
 var i : Integer;
 begin
-  result := TThriftListImpl< IThriftDictionary< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>.Create;
+  result := TThriftListImpl< IThriftDictionary< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>>.Create;
   for i := 0 to count-1 do begin
     result.Add(CreateListFieldData(count));
   end;
 end;
 
-class function TestDataFactory.CreateListFieldData(const count : Integer) : IThriftDictionary< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>;
+class function TestDataFactory.CreateListFieldData(const count : Integer) : IThriftDictionary< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>;
 var i : Integer;
 begin
-  result := TThriftDictionaryImpl< IHashSet< Integer>, IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>.Create;
+  result := TThriftDictionaryImpl< IThriftHashSet< Integer>, IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>>.Create;
   for i := 0 to count-1 do begin
     result.Add( CreateIntHashSet(count), CreateListFieldDataDict(count));
   end;
 end;
 
-class function TestDataFactory.CreateIntHashSet(const count : Integer) : IHashSet< Integer>;
+class function TestDataFactory.CreateIntHashSet(const count : Integer) : IThriftHashSet< Integer>;
 var i : Integer;
 begin
-  result := THashSetImpl< Integer>.Create;
+  result := TThriftHashSetImpl< Integer>.Create;
   for i := 0 to count-1 do begin
     result.Add(i);
   end;
 end;
 
-class function TestDataFactory.CreateListFieldDataDict(const count : Integer) : IThriftDictionary< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>;
+class function TestDataFactory.CreateListFieldDataDict(const count : Integer) : IThriftDictionary< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>;
 var i : Integer;
 begin
-  result := TThriftDictionaryImpl< Integer, IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>.Create;
+  result := TThriftDictionaryImpl< Integer, IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>>.Create;
   for i := 0 to count-1 do begin
     result.Add(i, CreateListFieldDataDictValue(count));
   end;
 end;
 
-class function TestDataFactory.CreateListFieldDataDictValue(const count : Integer) :  IHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>;
+class function TestDataFactory.CreateListFieldDataDictValue(const count : Integer) :  IThriftHashSet< IThriftList< IThriftDictionary< IInsanity, string>>>;
 var i : Integer;
 begin
-  result := THashSetImpl< IThriftList< IThriftDictionary< IInsanity, string>>>.Create;
+  result := TThriftHashSetImpl< IThriftList< IThriftDictionary< IInsanity, string>>>.Create;
   for i := 0 to count-1 do begin
     result.Add( CreateListFieldDataDictValueList(count));
   end;
diff --git a/lib/delphi/test/TestClient.pas b/lib/delphi/test/TestClient.pas
index df0b4c5..d541e18 100644
--- a/lib/delphi/test/TestClient.pas
+++ b/lib/delphi/test/TestClient.pas
@@ -34,7 +34,7 @@
 interface
 
 uses
-  Windows, SysUtils, Classes, Math, ComObj, ActiveX,
+  Classes, Windows, SysUtils, Math, ActiveX, ComObj,
   {$IFDEF SupportsAsync} System.Threading, {$ENDIF}
   DateUtils,
   Generics.Collections,
@@ -57,13 +57,17 @@
   Thrift.Collections;
 
 type
-  TThreadConsole = class
-  private
-    FThread : TThread;
+  TClientThread = class;
+
+  TThreadConsole = class(TThriftConsole)
+  strict private
+    FThread : TClientThread;
+    FLogThreadID : Boolean;
   public
-    procedure Write( const S : string);
-    procedure WriteLine( const S : string);
-    constructor Create( AThread: TThread);
+    constructor Create( const aThread: TClientThread; const aLogThreadID : Boolean);
+
+    procedure Write( const S: string); override;
+    procedure WriteLine( const S: string); override;
   end;
 
   TTestSetup = record
@@ -97,11 +101,13 @@
       FifteenMB        // quite a bit of data, but still below the default max frame size
     );
 
-  private
+  strict private
     FSetup : TTestSetup;
     FTransport : ITransport;
     FProtocol : IProtocol;
-    FNumIteration : Integer;
+    FNumIterations : Integer;
+
+    FThreadNo : Integer;
     FConsole : TThreadConsole;
 
     // test reporting, will be refactored out into separate class later
@@ -133,18 +139,23 @@
     {$IFDEF Win64}
     procedure UseInterlockedExchangeAdd64;
     {$ENDIF}
-  protected
+
+  strict protected
     procedure Execute; override;
+    property Console : TThreadConsole read FConsole;
+
   public
-    constructor Create( const aSetup : TTestSetup; const aNumIteration: Integer);
+    constructor Create( const aSetup : TTestSetup; const aNumIteration, aThreadNo: Integer; const aLogThreadID : Boolean);
     destructor Destroy; override;
+
+    property ThreadNo : Integer read FThreadNo;
   end;
 
   TTestClient = class
   private
     class var
-      FNumIteration : Integer;
-      FNumThread : Integer;
+      FNumIterations : Integer;
+      FNumThreads : Integer;
 
     class procedure PrintCmdLineHelp;
     class procedure InvalidArgs;
@@ -314,15 +325,15 @@
       end
       else if IsSwitch( sArg, '-n', sValue) or IsSwitch( sArg, '--testloops', sValue) then begin
         // -n [ --testloops ] arg (=1) Number of Tests
-        FNumIteration := StrToIntDef( sValue, 0);
-        if FNumIteration <= 0
+        FNumIterations := StrToIntDef( sValue, 0);
+        if FNumIterations <= 0
         then InvalidArgs;
 
       end
       else if IsSwitch( sArg, '-t', sValue) or IsSwitch( sArg, '--threads', sValue) then begin
         // -t [ --threads ] arg (=1)   Number of Test threads
-        FNumThread := StrToIntDef( sValue, 0);
-        if FNumThread <= 0
+        FNumThreads := StrToIntDef( sValue, 0);
+        if FNumThreads <= 0
         then InvalidArgs;
       end
       else if IsSwitch( sArg, '--performance', sValue) then begin
@@ -342,7 +353,7 @@
                         'Thrift TestClient (Delphi)',
                         MB_OK or MB_ICONEXCLAMATION);
 
-    SetLength( threads, FNumThread);
+    SetLength( threads, FNumThreads);
     dtStart := Now;
 
     // layered transports are not really meant to be stacked upon each other
@@ -355,14 +366,20 @@
 
     Console.WriteLine(THRIFT_PROTOCOLS[setup.protType]+' protocol');
 
-    for test := 0 to FNumThread - 1 do begin
-      thread := TClientThread.Create( setup, FNumIteration);
+    if FNumThreads <> 1
+    then Console.WriteLine(IntToStr(FNumThreads)+' client threads');
+
+    if FNumIterations <> 1
+    then Console.WriteLine(IntToStr(FNumIterations)+' iterations');
+
+    for test := 0 to FNumThreads - 1 do begin
+      thread := TClientThread.Create( setup, FNumIterations, test, FNumThreads<>1);
       threads[test] := thread;
       thread.Start;
     end;
 
     result := 0;
-    for test := 0 to FNumThread - 1 do begin
+    for test := 0 to FNumThreads - 1 do begin
       threadExitCode := threads[test].WaitFor;
       result := result or threadExitCode;
       threads[test].Free;
@@ -393,6 +410,7 @@
   i32 : Integer;
   i64 : Int64;
   binOut,binIn : TBytes;
+  guidIn, guidOut : TGuid;
   dub : Double;
   o : IXtruct;
   o2 : IXtruct2;
@@ -408,8 +426,8 @@
   strkey : string;
   listout : IThriftList<Integer>;
   listin : IThriftList<Integer>;
-  setout : IHashSet<Integer>;
-  setin : IHashSet<Integer>;
+  setout : IThriftHashSet<Integer>;
+  setin : IThriftHashSet<Integer>;
   ret : TNumberz;
   uid : Int64;
   mm : IThriftDictionary<Integer, IThriftDictionary<Integer, Integer>>;
@@ -543,6 +561,16 @@
   i64 := client.testI64(-34359738368);
   Expect( i64 = -34359738368, 'testI64(-34359738368) = ' + IntToStr( i64));
 
+  guidOut := StringToGUID('{00112233-4455-6677-8899-AABBCCDDEEFF}');
+  Console.WriteLine('testUuid('+GUIDToString(guidOut)+')');
+  try
+    guidIn := client.testUuid(guidOut);
+    Expect( IsEqualGUID(guidIn, guidOut), 'testUuid('+GUIDToString(guidOut)+') = '+GUIDToString(guidIn));
+  except
+    on e:TApplicationException do Console.WriteLine('testUuid(): '+e.Message);
+    on e:Exception do Expect( FALSE, 'testUuid(): Unexpected exception "'+e.ClassName+'": '+e.Message);
+  end;
+
   // random binary small
   for testsize := Low(TTestSize) to High(TTestSize) do begin
     binOut := PrepareBinaryData( TRUE, testsize);
@@ -672,7 +700,7 @@
   // Translates to an STL set, Java HashSet, set in Python, etc.
   // Note: PHP does not support sets, so it is treated similar to a List
   StartTestGroup( 'testSet', test_Containers);
-  setout := THashSetImpl<Integer>.Create;
+  setout := TThriftHashSetImpl<Integer>.Create;
   for j := -2 to 2 do
   begin
     setout.Add( j );
@@ -1283,12 +1311,13 @@
 end;
 
 
-constructor TClientThread.Create( const aSetup : TTestSetup; const aNumIteration: Integer);
+constructor TClientThread.Create( const aSetup : TTestSetup; const aNumIteration, aThreadNo: Integer; const aLogThreadID : Boolean);
 begin
   FSetup := aSetup;
-  FNumIteration := ANumIteration;
+  FThreadNo := aThreadNo;
+  FNumIterations := aNumIteration;
 
-  FConsole := TThreadConsole.Create( Self );
+  FConsole := TThreadConsole.Create( Self, aLogThreadID);
   FCurrentTest := test_Unknown;
 
   // error list: keep correct order, allow for duplicates
@@ -1320,7 +1349,7 @@
     // must be run in the context of the thread
     InitializeProtocolTransportStack;
     try
-      for i := 0 to FNumIteration - 1 do begin
+      for i := 0 to FNumIterations - 1 do begin
         ClientTest;
         {$IFDEF SupportsAsync}
         ClientAsyncTest;
@@ -1473,38 +1502,30 @@
 
 { TThreadConsole }
 
-constructor TThreadConsole.Create(AThread: TThread);
+constructor TThreadConsole.Create( const aThread: TClientThread; const aLogThreadID : Boolean);
 begin
   inherited Create;
   FThread := AThread;
+  FLogThreadID := aLogThreadID;
 end;
 
 procedure TThreadConsole.Write(const S: string);
-var
-  proc : TThreadProcedure;
 begin
-  proc := procedure
-  begin
-    Console.Write( S );
-  end;
-  TThread.Synchronize( FThread, proc);
+  if FLogThreadID
+  then ConsoleHelper.Console.Write( IntToStr(FThread.ThreadNo)+'> '+S)
+  else ConsoleHelper.Console.Write( S);
 end;
 
 procedure TThreadConsole.WriteLine(const S: string);
-var
-  proc : TThreadProcedure;
 begin
-  proc := procedure
-  begin
-    Console.WriteLine( S );
-  end;
-  TThread.Synchronize( FThread, proc);
+  if FLogThreadID
+  then ConsoleHelper.Console.WriteLine( IntToStr(FThread.ThreadNo)+'> '+S)
+  else ConsoleHelper.Console.WriteLine( S);
 end;
 
+
 initialization
-begin
-  TTestClient.FNumIteration := 1;
-  TTestClient.FNumThread := 1;
-end;
+  TTestClient.FNumIterations := 1;
+  TTestClient.FNumThreads := 1;
 
 end.
diff --git a/lib/delphi/test/TestServer.pas b/lib/delphi/test/TestServer.pas
index 8aaf9f3..3ae82a1 100644
--- a/lib/delphi/test/TestServer.pas
+++ b/lib/delphi/test/TestServer.pas
@@ -67,11 +67,12 @@
         function testI64(const thing: Int64): Int64;
         function testDouble(const thing: Double): Double;
         function testBinary(const thing: TBytes): TBytes;
+        function testUuid(const thing: System.TGuid): System.TGuid;
         function testStruct(const thing: IXtruct): IXtruct;
         function testNest(const thing: IXtruct2): IXtruct2;
         function testMap(const thing: IThriftDictionary<Integer, Integer>): IThriftDictionary<Integer, Integer>;
         function testStringMap(const thing: IThriftDictionary<string, string>): IThriftDictionary<string, string>;
-        function testSet(const thing: IHashSet<Integer>): IHashSet<Integer>;
+        function testSet(const thing: IThriftHashSet<Integer>): IThriftHashSet<Integer>;
         function testList(const thing: IThriftList<Integer>): IThriftList<Integer>;
         function testEnum(thing: TNumberz): TNumberz;
         function testTypedef(const thing: Int64): Int64;
@@ -150,6 +151,12 @@
   Result := thing;
 end;
 
+function TTestServer.TTestHandlerImpl.testUuid(const thing: System.TGuid): System.TGuid;
+begin
+  Console.WriteLine('testUuid('+GUIDToString(thing)+')');
+  Result := thing;
+end;
+
 function TTestServer.TTestHandlerImpl.testEnum(thing: TNumberz): TNumberz;
 begin
   Console.WriteLine('testEnum(' + EnumUtils<TNumberz>.ToString(Ord(thing)) + ')');
@@ -320,7 +327,7 @@
   Console.WriteLine('testOneway finished');
 end;
 
-function TTestServer.TTestHandlerImpl.testSet( const thing: IHashSet<Integer>):IHashSet<Integer>;
+function TTestServer.TTestHandlerImpl.testSet( const thing: IThriftHashSet<Integer>):IThriftHashSet<Integer>;
 begin
   Console.Write('testSet(');
   if thing <> nil then Console.Write(thing.ToString);
diff --git a/lib/delphi/test/client.dproj b/lib/delphi/test/client.dproj
index c57424d..ae6683d 100644
--- a/lib/delphi/test/client.dproj
+++ b/lib/delphi/test/client.dproj
@@ -1,22 +1,4 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you 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.
--->
-	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 		<PropertyGroup>
 			<ProjectGuid>{F262F488-F81C-4B6E-8694-518C54CBB8F3}</ProjectGuid>
 			<MainSource>client.dpr</MainSource>
@@ -142,7 +124,9 @@
 						<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="Comments"/>
 					</VersionInfoKeys>
-					<Parameters/>
+					<Parameters>
+						<Parameters Name="RunParams">--protocol=compact  </Parameters>
+					</Parameters>
 				</Delphi.Personality>
 				<Platforms>
 					<Platform value="Win32">True</Platform>
diff --git a/lib/delphi/test/serializer/SerializerData.dpr b/lib/delphi/test/serializer/SerializerData.dpr
new file mode 100644
index 0000000..92ed00b
--- /dev/null
+++ b/lib/delphi/test/serializer/SerializerData.dpr
@@ -0,0 +1,82 @@
+library SerializerData;
+(*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *)
+
+uses
+  Classes,
+  Windows,
+  SysUtils,
+  Generics.Collections,
+  Thrift in '..\..\src\Thrift.pas',
+  Thrift.Exception in '..\..\src\Thrift.Exception.pas',
+  Thrift.Socket in '..\..\src\Thrift.Socket.pas',
+  Thrift.Transport in '..\..\src\Thrift.Transport.pas',
+  Thrift.Protocol in '..\..\src\Thrift.Protocol.pas',
+  Thrift.Protocol.JSON in '..\..\src\Thrift.Protocol.JSON.pas',
+  Thrift.Protocol.Compact in '..\..\src\Thrift.Protocol.Compact.pas',
+  Thrift.Collections in '..\..\src\Thrift.Collections.pas',
+  Thrift.Configuration in '..\..\src\Thrift.Configuration.pas',
+  Thrift.Server in '..\..\src\Thrift.Server.pas',
+  Thrift.Utils in '..\..\src\Thrift.Utils.pas',
+  Thrift.Serializer in '..\..\src\Thrift.Serializer.pas',
+  Thrift.Stream in '..\..\src\Thrift.Stream.pas',
+  Thrift.WinHTTP in '..\..\src\Thrift.WinHTTP.pas',
+  Thrift.TypeRegistry in '..\..\src\Thrift.TypeRegistry.pas',
+  System_ in 'gen-delphi\System_.pas',
+  SysUtils_ in 'gen-delphi\SysUtils_.pas',
+  DebugProtoTest in 'gen-delphi\DebugProtoTest.pas',
+  TestSerializer.Data in 'TestSerializer.Data.pas';
+
+{$R *.res}
+
+function CreateOneOfEach : IOneOfEach; stdcall;
+begin
+  result := Fixtures.CreateOneOfEach;
+end;
+
+
+function CreateNesting : INesting; stdcall;
+begin
+  result := Fixtures.CreateNesting;
+end;
+
+
+function CreateHolyMoley : IHolyMoley; stdcall;
+begin
+  result := Fixtures.CreateHolyMoley;
+end;
+
+
+function CreateCompactProtoTestStruct : ICompactProtoTestStruct; stdcall;
+begin
+  result := Fixtures.CreateCompactProtoTestStruct;
+end;
+
+
+exports
+  CreateOneOfEach,
+  CreateNesting,
+  CreateHolyMoley,
+  CreateCompactProtoTestStruct;
+
+begin
+  IsMultiThread := TRUE;
+  ASSERT( cDebugProtoTest_Option_COM_types);
+  ASSERT( cSystem__Option_COM_types);
+end.
diff --git a/lib/delphi/test/serializer/SerializerData.dproj b/lib/delphi/test/serializer/SerializerData.dproj
new file mode 100644
index 0000000..cfc27f8
--- /dev/null
+++ b/lib/delphi/test/serializer/SerializerData.dproj
@@ -0,0 +1,150 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you 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.
+-->
+	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+		<PropertyGroup>
+			<ProjectGuid>{B523D1D7-2C9A-4B39-A6CF-69EF536D5079}</ProjectGuid>
+			<MainSource>SerializerData.dpr</MainSource>
+			<ProjectVersion>12.3</ProjectVersion>
+			<Basis>True</Basis>
+			<Config Condition="'$(Config)'==''">Debug</Config>
+			<Platform>Win32</Platform>
+			<AppType>Library</AppType>
+			<FrameworkType>None</FrameworkType>
+			<DCC_DCCCompiler>DCC32</DCC_DCCCompiler>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Basis' or '$(Base)'!=''">
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
+			<Cfg_1>true</Cfg_1>
+			<CfgParent>Base</CfgParent>
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
+			<Cfg_2>true</Cfg_2>
+			<CfgParent>Base</CfgParent>
+			<Base>true</Base>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Base)'!=''">
+			<DCC_DcuOutput>.\$(Config)\$(Platform)</DCC_DcuOutput>
+			<DCC_E>false</DCC_E>
+			<DCC_ImageBase>00400000</DCC_ImageBase>
+			<DCC_UnitAlias>WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;$(DCC_UnitAlias)</DCC_UnitAlias>
+			<DCC_ExeOutput>bin\$(Config)\$(Platform)</DCC_ExeOutput>
+			<DCC_S>false</DCC_S>
+			<GenDll>true</GenDll>
+			<DCC_N>false</DCC_N>
+			<DCC_F>false</DCC_F>
+			<DCC_K>false</DCC_K>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Cfg_1)'!=''">
+			<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
+			<DCC_Optimize>false</DCC_Optimize>
+			<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
+		</PropertyGroup>
+		<PropertyGroup Condition="'$(Cfg_2)'!=''">
+			<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
+			<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
+			<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
+			<DCC_DebugInformation>false</DCC_DebugInformation>
+		</PropertyGroup>
+		<ItemGroup>
+			<DelphiCompile Include="SerializerData.dpr">
+				<MainSource>MainSource</MainSource>
+			</DelphiCompile>
+			<DCCReference Include="..\..\src\Thrift.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Exception.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Socket.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Transport.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Protocol.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Protocol.JSON.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Protocol.Compact.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Collections.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Configuration.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Server.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Utils.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Serializer.pas"/>
+			<DCCReference Include="..\..\src\Thrift.Stream.pas"/>
+			<DCCReference Include="..\..\src\Thrift.WinHTTP.pas"/>
+			<DCCReference Include="..\..\src\Thrift.TypeRegistry.pas"/>
+			<DCCReference Include="gen-delphi\System_.pas"/>
+			<DCCReference Include="gen-delphi\SysUtils_.pas"/>
+			<DCCReference Include="gen-delphi\DebugProtoTest.pas"/>
+			<DCCReference Include="TestSerializer.Data.pas"/>
+			<BuildConfiguration Include="Release">
+				<Key>Cfg_2</Key>
+				<CfgParent>Base</CfgParent>
+			</BuildConfiguration>
+			<BuildConfiguration Include="Basis">
+				<Key>Base</Key>
+			</BuildConfiguration>
+			<BuildConfiguration Include="Debug">
+				<Key>Cfg_1</Key>
+				<CfgParent>Base</CfgParent>
+			</BuildConfiguration>
+		</ItemGroup>
+		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
+		<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
+		<PropertyGroup>
+			<PreBuildEvent><![CDATA[thrift.exe -r -gen delphi:com_types ..\keywords\ReservedKeywords.thrift
+thrift.exe -r -gen delphi:com_types ..\..\..\..\test\DebugProtoTest.thrift]]></PreBuildEvent>
+		</PropertyGroup>
+		<ProjectExtensions>
+			<Borland.Personality>Delphi.Personality.12</Borland.Personality>
+			<Borland.ProjectType/>
+			<BorlandProject>
+				<Delphi.Personality>
+					<VersionInfo>
+						<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
+						<VersionInfo Name="AutoIncBuild">False</VersionInfo>
+						<VersionInfo Name="MajorVer">1</VersionInfo>
+						<VersionInfo Name="MinorVer">0</VersionInfo>
+						<VersionInfo Name="Release">0</VersionInfo>
+						<VersionInfo Name="Build">0</VersionInfo>
+						<VersionInfo Name="Debug">False</VersionInfo>
+						<VersionInfo Name="PreRelease">False</VersionInfo>
+						<VersionInfo Name="Special">False</VersionInfo>
+						<VersionInfo Name="Private">False</VersionInfo>
+						<VersionInfo Name="DLL">False</VersionInfo>
+						<VersionInfo Name="Locale">1031</VersionInfo>
+						<VersionInfo Name="CodePage">1252</VersionInfo>
+					</VersionInfo>
+					<VersionInfoKeys>
+						<VersionInfoKeys Name="CompanyName"/>
+						<VersionInfoKeys Name="FileDescription"/>
+						<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="InternalName"/>
+						<VersionInfoKeys Name="LegalCopyright"/>
+						<VersionInfoKeys Name="LegalTrademarks"/>
+						<VersionInfoKeys Name="OriginalFilename"/>
+						<VersionInfoKeys Name="ProductName"/>
+						<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="Comments"/>
+					</VersionInfoKeys>
+					<Source>
+						<Source Name="MainSource">SerializerData.dpr</Source>
+					</Source>
+				</Delphi.Personality>
+				<Platforms>
+					<Platform value="Win32">True</Platform>
+				</Platforms>
+			</BorlandProject>
+			<ProjectFileVersion>12</ProjectFileVersion>
+		</ProjectExtensions>
+	</Project>
diff --git a/lib/delphi/test/serializer/SerializerData.res b/lib/delphi/test/serializer/SerializerData.res
new file mode 100644
index 0000000..231eb70
--- /dev/null
+++ b/lib/delphi/test/serializer/SerializerData.res
Binary files differ
diff --git a/lib/delphi/test/serializer/TestSerializer.Data.pas b/lib/delphi/test/serializer/TestSerializer.Data.pas
index a90d650..269e307 100644
--- a/lib/delphi/test/serializer/TestSerializer.Data.pas
+++ b/lib/delphi/test/serializer/TestSerializer.Data.pas
@@ -23,6 +23,9 @@
 
 uses
   SysUtils,
+  ActiveX,
+  ComObj,
+  Thrift.Protocol,
   Thrift.Collections,
   DebugProtoTest;
 
@@ -192,8 +195,12 @@
   // !!
   result.setZomg_unicode( UnicodeString( us));
 
+  result.Rfc4122_uuid := TGuid.Create('{00112233-4455-6677-8899-aabbccddeeff}');
+
   {$IF cDebugProtoTest_Option_AnsiStr_Binary}
   result.SetBase64('base64');
+  {$ELSEIF cDebugProtoTest_Option_COM_Types}
+  result.SetBase64( TThriftBytesImpl.Create( TEncoding.UTF8.GetBytes('base64')));
   {$ELSE}
   result.SetBase64( TEncoding.UTF8.GetBytes('base64'));
   {$IFEND}
@@ -216,8 +223,10 @@
 
 
 class function Fixtures.CreateHolyMoley : IHolyMoley;
+type
+  TStringType = {$IF cDebugProtoTest_Option_COM_Types} WideString {$ELSE} String {$IFEND};
 var big : IThriftList<IOneOfEach>;
-    stage1 : IThriftList<String>;
+    stage1 : IThriftList<TStringType>;
     stage2 : IThriftList<IBonk>;
     b      : IBonk;
 begin
@@ -230,23 +239,23 @@
   result.Big[0].setA_bite( $22);
   result.Big[0].setA_bite( $23);
 
-  result.Contain := THashSetImpl< IThriftList<string>>.Create;
-  stage1 := TThriftListImpl<String>.Create;
+  result.Contain := TThriftHashSetImpl< IThriftList<TStringType>>.Create;
+  stage1 := TThriftListImpl<TStringType>.Create;
   stage1.add( 'and a one');
   stage1.add( 'and a two');
   result.Contain.add( stage1);
 
-  stage1 := TThriftListImpl<String>.Create;
+  stage1 := TThriftListImpl<TStringType>.Create;
   stage1.add( 'then a one, two');
   stage1.add( 'three!');
   stage1.add( 'FOUR!!');
   result.Contain.add( stage1);
 
-  stage1 := TThriftListImpl<String>.Create;
+  stage1 := TThriftListImpl<TStringType>.Create;
   result.Contain.add( stage1);
 
   stage2 := TThriftListImpl<IBonk>.Create;
-  result.Bonks := TThriftDictionaryImpl< String, IThriftList< IBonk>>.Create;
+  result.Bonks := TThriftDictionaryImpl< TStringType, IThriftList< IBonk>>.Create;
   // one empty
   result.Bonks.Add( 'zero', stage2);
 
@@ -342,6 +351,8 @@
 
   {$IF cDebugProtoTest_Option_AnsiStr_Binary}
   result.A_binary := AnsiString( #0#1#2#3#4#5#6#7#8);
+  {$ELSEIF cDebugProtoTest_Option_COM_Types}
+  result.A_binary := TThriftBytesImpl.Create( TEncoding.UTF8.GetBytes( #0#1#2#3#4#5#6#7#8));
   {$ELSE}
   result.A_binary := TEncoding.UTF8.GetBytes( #0#1#2#3#4#5#6#7#8);
   {$IFEND}
diff --git a/lib/delphi/test/serializer/TestSerializer.Tests.pas b/lib/delphi/test/serializer/TestSerializer.Tests.pas
index 83d67b1..6ed1a48 100644
--- a/lib/delphi/test/serializer/TestSerializer.Tests.pas
+++ b/lib/delphi/test/serializer/TestSerializer.Tests.pas
@@ -41,9 +41,9 @@
   Thrift.WinHTTP,
   Thrift.TypeRegistry,
   System_,
-  DebugProtoTest,
-  TestSerializer.Data;
+  DebugProtoTest;
 
+{$TYPEINFO ON}
 
 type
   TFactoryPair = record
@@ -58,7 +58,7 @@
       mt_Stream
     );
 
-  private
+  strict private
     FProtocols : TList< TFactoryPair>;
     procedure AddFactoryCombination( const aProto : IProtocolFactory; const aTrans : ITransportFactory);
     class function UserFriendlyName( const factory : TFactoryPair) : string;  overload;
@@ -73,7 +73,14 @@
     class procedure ValidateReadToEnd( const input : TBytes; const serial : TDeserializer);  overload;
     class procedure ValidateReadToEnd( const input : TStream; const serial : TDeserializer);  overload;
 
+    class function LengthOf( const bytes : TBytes) : Integer; overload; inline;
+    class function LengthOf( const bytes : IThriftBytes) : Integer; overload; inline;
+
+    class function DataPtrOf( const bytes : TBytes) : Pointer; overload; inline;
+    class function DataPtrOf( const bytes : IThriftBytes) : Pointer; overload; inline;
+
     procedure Test_Serializer_Deserializer;
+    procedure Test_COM_Types;
     procedure Test_OneOfEach(     const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
     procedure Test_CompactStruct( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
 
@@ -87,6 +94,12 @@
 
 implementation
 
+const SERIALIZERDATA_DLL = 'SerializerData.dll';
+function CreateOneOfEach : IOneOfEach; stdcall; external SERIALIZERDATA_DLL;
+function CreateNesting : INesting; stdcall; external SERIALIZERDATA_DLL;
+function CreateHolyMoley : IHolyMoley; stdcall; external SERIALIZERDATA_DLL;
+function CreateCompactProtoTestStruct : ICompactProtoTestStruct; stdcall; external SERIALIZERDATA_DLL;
+
 
 { TTestSerializer }
 
@@ -128,13 +141,41 @@
 end;
 
 
+class function TTestSerializer.LengthOf( const bytes : TBytes) : Integer;
+begin
+  result := Length(bytes);
+end;
+
+
+class function TTestSerializer.LengthOf( const bytes : IThriftBytes) : Integer;
+begin
+  if bytes <> nil
+  then result := bytes.Count
+  else result := 0;
+end;
+
+
+class function TTestSerializer.DataPtrOf( const bytes : TBytes) : Pointer;
+begin
+  result := bytes;
+end;
+
+
+class function TTestSerializer.DataPtrOf( const bytes : IThriftBytes) : Pointer;
+begin
+  if bytes <> nil
+  then result := bytes.QueryRawDataPtr
+  else result := nil;
+end;
+
+
 procedure TTestSerializer.Test_OneOfEach( const method : TMethod; const factory : TFactoryPair; const stream : TFileStream);
 var tested, correct : IOneOfEach;
     bytes   : TBytes;
     i : Integer;
 begin
   // write
-  tested := Fixtures.CreateOneOfEach;
+  tested := CreateOneOfEach;
   case method of
     mt_Bytes:  bytes := Serialize( tested, factory);
     mt_Stream: begin
@@ -158,7 +199,7 @@
   end;
 
   // check
-  correct := Fixtures.CreateOneOfEach;
+  correct := CreateOneOfEach;
   ASSERT( tested.Im_true = correct.Im_true);
   ASSERT( tested.Im_false = correct.Im_false);
   ASSERT( tested.A_bite = correct.A_bite);
@@ -168,10 +209,11 @@
   ASSERT( Abs( tested.Double_precision - correct.Double_precision) < 1E-12);
   ASSERT( tested.Some_characters = correct.Some_characters);
   ASSERT( tested.Zomg_unicode = correct.Zomg_unicode);
+  ASSERT( tested.Rfc4122_uuid = correct.Rfc4122_uuid);
   ASSERT( tested.What_who = correct.What_who);
 
-  ASSERT( Length(tested.Base64) = Length(correct.Base64));
-  ASSERT( CompareMem( @tested.Base64[0], @correct.Base64[0], Length(correct.Base64)));
+  ASSERT( LengthOf(tested.Base64) = LengthOf(correct.Base64));
+  ASSERT( CompareMem( DataPtrOf(tested.Base64), DataPtrOf(correct.Base64), LengthOf(correct.Base64)));
 
   ASSERT( tested.Byte_list.Count = correct.Byte_list.Count);
   for i := 0 to tested.Byte_list.Count-1
@@ -192,7 +234,7 @@
     bytes   : TBytes;
 begin
   // write
-  tested := Fixtures.CreateCompactProtoTestStruct;
+  tested := CreateCompactProtoTestStruct;
   case method of
     mt_Bytes:  bytes := Serialize( tested, factory);
     mt_Stream: begin
@@ -216,7 +258,7 @@
   end;
 
   // check
-  correct := Fixtures.CreateCompactProtoTestStruct;
+  correct := CreateCompactProtoTestStruct;
   ASSERT( correct.Field500  = tested.Field500);
   ASSERT( correct.Field5000  = tested.Field5000);
   ASSERT( correct.Field20000 = tested.Field20000);
@@ -263,9 +305,23 @@
 
 
 class function TTestSerializer.UserFriendlyName( const method : TMethod) : string;
+const NAMES : array[TMethod] of string = ('TBytes','Stream');
 begin
-  result := EnumUtils<TMethod>.ToString(Ord(method));
-  result := StringReplace( result, 'mt_', '', [rfReplaceAll]);
+  result := NAMES[method];
+end;
+
+
+procedure TTestSerializer.Test_COM_Types;
+var tested : IOneOfEach;
+begin
+  {$IF cDebugProtoTest_Option_COM_types}
+  ASSERT( SizeOf(TSomeEnum) = SizeOf(Int32));  // -> MINENUMSIZE 4
+
+  // try to set values that allocate memory
+  tested := CreateOneOfEach;
+  tested.Zomg_unicode := 'This is a test';
+  tested.Base64 := TThriftBytesImpl.Create( TEncoding.UTF8.GetBytes('abc'));
+  {$IFEND}
 end;
 
 
@@ -273,6 +329,7 @@
 begin
   try
     Test_Serializer_Deserializer;
+    Test_COM_Types;
   except
     on e:Exception do begin
       Writeln( e.ClassName+': '+ e.Message);
@@ -287,7 +344,7 @@
     config : IThriftConfiguration;
 begin
   config := TThriftConfigurationImpl.Create;
-  config.MaxMessageSize := 0;   // we don't read anything here
+  //config.MaxMessageSize := 0;   // we don't read anything here
 
   serial := TSerializer.Create( factory.prot, factory.trans, config);
   try
@@ -303,7 +360,7 @@
     config : IThriftConfiguration;
 begin
   config := TThriftConfigurationImpl.Create;
-  config.MaxMessageSize := 0;   // we don't read anything here
+  //config.MaxMessageSize := 0;   // we don't read anything here
 
   serial := TSerializer.Create( factory.prot, factory.trans, config);
   try
diff --git a/lib/delphi/test/serializer/TestSerializer.dpr b/lib/delphi/test/serializer/TestSerializer.dpr
index 971401e..b78c0db 100644
--- a/lib/delphi/test/serializer/TestSerializer.dpr
+++ b/lib/delphi/test/serializer/TestSerializer.dpr
@@ -44,8 +44,7 @@
   System_ in 'gen-delphi\System_.pas',
   SysUtils_ in 'gen-delphi\SysUtils_.pas',
   DebugProtoTest in 'gen-delphi\DebugProtoTest.pas',
-  TestSerializer.Tests in 'TestSerializer.Tests.pas',
-  TestSerializer.Data in 'TestSerializer.Data.pas';
+  TestSerializer.Tests in 'TestSerializer.Tests.pas';
 
 
 var test : TTestSerializer;
diff --git a/lib/delphi/test/serializer/TestSerializer.dproj b/lib/delphi/test/serializer/TestSerializer.dproj
index 5f26264..1d98d3a 100644
--- a/lib/delphi/test/serializer/TestSerializer.dproj
+++ b/lib/delphi/test/serializer/TestSerializer.dproj
@@ -86,7 +86,6 @@
 			<DCCReference Include="gen-delphi\SysUtils_.pas"/>
 			<DCCReference Include="gen-delphi\DebugProtoTest.pas"/>
 			<DCCReference Include="TestSerializer.Tests.pas"/>
-			<DCCReference Include="TestSerializer.Data.pas"/>
 			<BuildConfiguration Include="Debug">
 				<Key>Cfg_2</Key>
 				<CfgParent>Base</CfgParent>
@@ -102,8 +101,8 @@
 		<Import Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')" Project="$(BDS)\Bin\CodeGear.Delphi.Targets"/>
 		<Import Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')" Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj"/>
 		<PropertyGroup>
-			<PreBuildEvent><![CDATA[thrift.exe -r -gen delphi ..\keywords\ReservedKeywords.thrift
-thrift.exe -r -gen delphi ..\..\..\..\test\DebugProtoTest.thrift]]></PreBuildEvent>
+			<PreBuildEvent><![CDATA[thrift.exe -r -gen delphi:com_types ..\keywords\ReservedKeywords.thrift
+thrift.exe -r -gen delphi:com_types ..\..\..\..\test\DebugProtoTest.thrift]]></PreBuildEvent>
 		</PropertyGroup>
 		<ProjectExtensions>
 			<Borland.Personality>Delphi.Personality.12</Borland.Personality>
diff --git a/lib/delphi/test/server.dproj b/lib/delphi/test/server.dproj
index 9f7e5c6..151f7ee 100644
--- a/lib/delphi/test/server.dproj
+++ b/lib/delphi/test/server.dproj
@@ -1,22 +1,4 @@
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you 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.
--->
-	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+	<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 		<PropertyGroup>
 			<ProjectGuid>{07CEDA3D-0963-40FE-B3C2-0ED4E24DE067}</ProjectGuid>
 			<MainSource>server.dpr</MainSource>
@@ -140,6 +122,9 @@
 						<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="Comments"/>
 					</VersionInfoKeys>
+					<Parameters>
+						<Parameters Name="RunParams">--protocol=compact  </Parameters>
+					</Parameters>
 				</Delphi.Personality>
 				<Platforms>
 					<Platform value="Win32">True</Platform>
diff --git a/lib/delphi/test/skip/skiptest_version2.dpr b/lib/delphi/test/skip/skiptest_version2.dpr
index b3a270d..e1c5f83 100644
--- a/lib/delphi/test/skip/skiptest_version2.dpr
+++ b/lib/delphi/test/skip/skiptest_version2.dpr
@@ -46,7 +46,7 @@
 
 function CreatePing : IPing;
 var list : IThriftList<IPong>;
-    set_ : IHashSet<string>;
+    set_ : IThriftHashSet<string>;
 begin
   result := TPingImpl.Create;
   result.Version1  := TConstants.SKIPTESTSERVICE_VERSION;
@@ -69,13 +69,13 @@
   list.Add( result.StructVal);
   list.Add( result.StructVal);
 
-  set_ := THashSetImpl<string>.Create;
+  set_ := TThriftHashSetImpl<string>.Create;
   set_.Add( 'one');
   set_.Add( 'uno');
   set_.Add( 'eins');
   set_.Add( 'een');
 
-  result.MapVal := TThriftDictionaryImpl< IThriftList<IPong>, IHashSet<string>>.Create;
+  result.MapVal := TThriftDictionaryImpl< IThriftList<IPong>, IThriftHashSet<string>>.Create;
   result.MapVal.Add( list, set_);
 end;
 
diff --git a/lib/erl/Makefile.am b/lib/erl/Makefile.am
index bf7abd5..23ebb77 100644
--- a/lib/erl/Makefile.am
+++ b/lib/erl/Makefile.am
@@ -21,10 +21,10 @@
 THRIFT_OMIT_FILE = test/Thrift_omit_without.thrift
 THRIFT_FILES = $(wildcard test/*.thrift) \
 		  $(THRIFT_OMIT_FILE) \
-		  ../../test/ConstantsDemo.thrift \
-		  ../../test/NameConflictTest.thrift \
+		  ../../test/v0.16/ConstantsDemo.thrift \
+		  ../../test/v0.16/NameConflictTest.thrift \
 		  ../../test/DoubleConstantsTest.thrift \
-		  ../../test/ThriftTest.thrift
+		  ../../test/v0.16/ThriftTest.thrift
 
 ERL_FLAG = erl
 ERL_FLAG_LEGACY = erl:legacynames
diff --git a/lib/erl/src/thrift.app.src b/lib/erl/src/thrift.app.src
index 9c30c8a..180f389 100644
--- a/lib/erl/src/thrift.app.src
+++ b/lib/erl/src/thrift.app.src
@@ -22,7 +22,7 @@
   {description, "Thrift bindings"},
 
   % The version of the applicaton
-  {vsn, "0.17.0"},
+  {vsn, "0.18.0"},
 
   % All modules used by the application.
   {modules, [
diff --git a/lib/erl/test/Thrift1151.thrift b/lib/erl/test/Thrift1151.thrift
index 6f934a7..ce6d858 100644
--- a/lib/erl/test/Thrift1151.thrift
+++ b/lib/erl/test/Thrift1151.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct StructA { 1: i16 x; }
 struct StructB { 1: i32 x; }
 struct StructC { 1: StructA x; }
diff --git a/lib/erl/test/Thrift1475.thrift b/lib/erl/test/Thrift1475.thrift
index 7adeb7e..4371643 100644
--- a/lib/erl/test/Thrift1475.thrift
+++ b/lib/erl/test/Thrift1475.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct StructB
 {
   1: string x
diff --git a/lib/erl/test/Thrift_omit_with.thrift b/lib/erl/test/Thrift_omit_with.thrift
index 8bffc7c..a4395c5 100644
--- a/lib/erl/test/Thrift_omit_with.thrift
+++ b/lib/erl/test/Thrift_omit_with.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct test1 {
   1: i32 one
   2: i32 two                    // omit
diff --git a/lib/erl/test/flags/LegacyNames.thrift b/lib/erl/test/flags/LegacyNames.thrift
index 38f2729..2eb85e6 100644
--- a/lib/erl/test/flags/LegacyNames.thrift
+++ b/lib/erl/test/flags/LegacyNames.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 enum Numberz
 {
   ONE = 1,
diff --git a/lib/erl/test/multiplexing.thrift b/lib/erl/test/multiplexing.thrift
index 7c7994b..52c1661 100644
--- a/lib/erl/test/multiplexing.thrift
+++ b/lib/erl/test/multiplexing.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 service Multiplexing_Calculator {
     i32 add(1: i32 x, 2: i32 y)
 }
diff --git a/lib/go/test/DuplicateImportsTest.thrift b/lib/go/test/DuplicateImportsTest.thrift
index ffe1caf..de390e1 100644
--- a/lib/go/test/DuplicateImportsTest.thrift
+++ b/lib/go/test/DuplicateImportsTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "common/a.thrift"
 include "common/b.thrift"
 
diff --git a/lib/go/test/Makefile.am b/lib/go/test/Makefile.am
index d938449..b9c00d9 100644
--- a/lib/go/test/Makefile.am
+++ b/lib/go/test/Makefile.am
@@ -26,7 +26,7 @@
 THRIFT_GO_ARGS_BASE = thrift_import=github.com/apache/thrift/lib/go/thrift,package_prefix=github.com/apache/thrift/lib/go/test/gopath/src/
 
 THRIFTARGS = -out gopath/src/ --gen go:$(THRIFT_GO_ARGS_BASE)$(COMPILER_EXTRAFLAG)
-THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+THRIFTTEST = $(top_srcdir)/test/v0.16/ThriftTest.thrift
 
 THRIFTARGS_SKIP_REMOTE = -out gopath/src/ --gen go:skip_remote,$(THRIFT_GO_ARGS_BASE)$(COMPILER_EXTRAFLAG)
 
@@ -64,7 +64,8 @@
 				ConstOptionalFieldImport.thrift \
 				ConstOptionalField.thrift \
 				ProcessorMiddlewareTest.thrift \
-				ClientMiddlewareExceptionTest.thrift
+				ClientMiddlewareExceptionTest.thrift \
+				ValidateTest.thrift
 	mkdir -p gopath/src
 	grep -v list.*map.*list.*map $(THRIFTTEST) | grep -v 'set<Insanity>' > ThriftTest.thrift
 	$(THRIFT) $(THRIFTARGS) -r IncludesTest.thrift
@@ -98,6 +99,7 @@
 	$(THRIFT) $(THRIFTARGS) -r ConstOptionalField.thrift
 	$(THRIFT) $(THRIFTARGS_SKIP_REMOTE) ProcessorMiddlewareTest.thrift
 	$(THRIFT) $(THRIFTARGS) ClientMiddlewareExceptionTest.thrift
+	$(THRIFT) $(THRIFTARGS) ValidateTest.thrift
 	ln -nfs ../../tests gopath/src/tests
 	cp -r ./dontexportrwtest gopath/src
 	touch gopath
@@ -122,7 +124,8 @@
 				./gopath/src/equalstest \
 				./gopath/src/conflictargnamestest \
 				./gopath/src/processormiddlewaretest \
-				./gopath/src/clientmiddlewareexceptiontest
+				./gopath/src/clientmiddlewareexceptiontest \
+				./gopath/src/validatetest
 	$(GO) test -mod=mod github.com/apache/thrift/lib/go/thrift
 	$(GO) test -mod=mod ./gopath/src/tests ./gopath/src/dontexportrwtest
 
@@ -168,4 +171,5 @@
 	ServicesTest.thrift \
 	TypedefFieldTest.thrift \
 	UnionBinaryTest.thrift \
-	UnionDefaultValueTest.thrift
+	UnionDefaultValueTest.thrift \
+	ValidateTest.thrift
diff --git a/lib/go/test/RequiredFieldTest.thrift b/lib/go/test/RequiredFieldTest.thrift
index 4a2dcae..4f06727 100644
--- a/lib/go/test/RequiredFieldTest.thrift
+++ b/lib/go/test/RequiredFieldTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct RequiredField {
   1: required string name
 }
diff --git a/lib/go/test/ValidateTest.thrift b/lib/go/test/ValidateTest.thrift
new file mode 100644
index 0000000..c02bfa8
--- /dev/null
+++ b/lib/go/test/ValidateTest.thrift
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+namespace go validatetest
+
+enum EnumFoo {
+  e1
+  e2
+}
+
+struct Foo {
+        1: bool Bool
+}
+
+struct BasicTest {
+        1: bool Bool0 = true (vt.const = "true")
+        2: optional bool Bool1 (vt.const = "true")
+        3: i8 Byte0 = 1 (vt.lt = "2", vt.le = "2", vt.gt = "0", vt.ge = "0", vt.in = "[0, 1, 2]", vt.not_in = "[3, 4, 5]")
+        4: optional i8 Byte1 (vt.lt = "1", vt.le = "1", vt.gt = "-1", vt.ge = "-1", vt.in = "[-1, 0, 1]", vt.not_in = "[1, 2, 3]")
+        5: double Double0 = 1.0 (vt.lt = "2.0", vt.le = "2.0", vt.gt = "0", vt.ge = "0", vt.in = "[0, 1.0, 2.0]", vt.not_in = "[3.0, 4.0, 5.0]")
+        6: optional double Double1 (vt.lt = "2.0", vt.le = "2.0", vt.gt = "0", vt.ge = "0", vt.in = "[0, 1.0, 2.0]", vt.not_in = "[3.0, 4.0, 5.0]")
+        7: string String0 = "my const string" (vt.const = "my const string", vt.min_size = "0", vt.max_size = "100", vt.pattern = ".*", vt.prefix = "my", vt.suffix = "string", vt.contains = "const", vt.not_contains = "oh")
+        8: optional string String1 (vt.const = "my const string", vt.min_size = "0", vt.max_size = "100", vt.pattern = ".*", vt.prefix = "my", vt.suffix = "string", vt.contains = "const", vt.not_contains = "oh")
+        9: binary Binary0 = "my const string" (vt.const = "my const string", vt.min_size = "0", vt.max_size = "100", vt.pattern = ".*", vt.prefix = "my", vt.suffix = "string", vt.contains = "const", vt.not_contains = "oh")
+        10: optional binary Binary1 = "my const string" (vt.const = "my const string", vt.min_size = "0", vt.max_size = "100", vt.pattern = ".*", vt.prefix = "my", vt.suffix = "string", vt.contains = "const", vt.not_contains = "oh")
+        11: map<string, string> Map0 (vt.min_size = "0", vt.max_size = "10", vt.key.min_size = "0", vt.key.max_size = "10", vt.value.min_size = "0", vt.value.max_size = "10")
+        12: optional map<string, string> Map1 (vt.min_size = "0", vt.max_size = "10", vt.key.min_size = "0", vt.key.max_size = "10", vt.value.min_size = "0", vt.value.max_size = "10")
+        13: set<string> Set0 (vt.min_size = "0", vt.max_size = "10", vt.elem.min_size = "5")
+        14: optional set<string> Set1 (vt.min_size = "0", vt.max_size = "10", vt.elem.min_size = "5")
+        15: EnumFoo Enum0 = EnumFoo.e2 (vt.in = "[EnumFoo.e2]", vt.defined_only = "true")
+        16: optional EnumFoo Enum1 (vt.in = "[EnumFoo.e1]", vt.defined_only = "true")
+        17: Foo Struct0 (vt.skip = "true")
+        18: optional Foo Struct1 (vt.skip = "true")
+        19: i8 Byte2 = 1 (vt.in = "1", vt.not_in = "2")
+        20: double Double2 = 3.0 (vt.in = "3.0", vt.not_in = "4.0")
+        21: EnumFoo Enum2 = EnumFoo.e2 (vt.in = "EnumFoo.e2", vt.not_in = "EnumFoo.e1")
+}
+
+struct FieldReferenceTest {
+        1: bool Bool0 (vt.const = "$Bool2")
+        2: optional bool Bool1 (vt.const = "$Bool2")
+        3: i8 Byte0 = 10 (vt.lt = "$Byte4", vt.le = "$Byte4", vt.gt = "$Byte2", vt.ge = "$Byte2", vt.in = "[$Byte2, $Byte3, $Byte4]", vt.not_in = "[$Byte2, $Byte4]")
+        4: optional i8 Byte1 (vt.lt = "$Byte4", vt.le = "$Byte4", vt.gt = "$Byte2", vt.ge = "$Byte2", vt.in = "[$Byte2, $Byte3, $Byte4]", vt.not_in = "[$Byte2, $Byte4]")
+        5: double Double0 = 10.0 (vt.lt = "$Double4", vt.le = "$Double4", vt.gt = "$Double2", vt.ge = "$Double2", vt.in = "[$Double2, $Double3, $Double4]", vt.not_in = "[$Double2, $Double4]")
+        6: optional double Double1 (vt.lt = "$Double4", vt.le = "$Double4", vt.gt = "$Double2", vt.ge = "$Double2", vt.in = "[$Double2, $Double3, $Double4]", vt.not_in = "[$Double2, $Double4]")
+        7: string String0 = "my string" (vt.const = "$String2", vt.min_size = "$Byte2", vt.max_size = "$Byte3", vt.pattern = "$String4", vt.prefix = "$String2", vt.suffix = "$String2", vt.contains = "$String2", vt.not_contains = "$String3")
+        8: optional string String1 (vt.const = "$String2", vt.min_size = "$Byte2", vt.max_size = "$Byte3", vt.pattern = "$String4", vt.prefix = "$String2", vt.suffix = "$String2", vt.contains = "$String2", vt.not_contains = "$String3")
+        9: binary Binary0 = "my binary" (vt.const = "$Binary2", vt.min_size = "$Byte2", vt.max_size = "$Byte3", vt.pattern = "$Binary4", vt.prefix = "$Binary2", vt.suffix = "$Binary2", vt.contains = "$Binary2", vt.not_contains = "$Binary3")
+        10: optional binary Binary1 = "my binary" (vt.const = "$Binary2", vt.min_size = "$Byte2", vt.max_size = "$Byte3", vt.pattern = "$Binary4", vt.prefix = "$Binary2", vt.suffix = "$Binary2", vt.contains = "$Binary2", vt.not_contains = "$Binary3")
+        11: map<string, string> Map0 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.key.min_size = "$Byte2", vt.key.max_size = "$MaxSize", vt.value.min_size = "$Byte2", vt.value.max_size = "$MaxSize")
+        12: optional map<string, string> Map1 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.key.min_size = "$Byte2", vt.key.max_size = "$MaxSize", vt.value.min_size = "$Byte2", vt.value.max_size = "$MaxSize")
+        13: list<string> List0 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.elem.min_size = "$Byte2", vt.elem.max_size = "$MaxSize")
+        14: optional list<string> List1 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.elem.min_size = "$Byte2", vt.elem.max_size = "$MaxSize")
+        15: set<string> Set0 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.elem.min_size = "$Byte2", vt.elem.max_size = "$MaxSize")
+        16: optional set<string> Set1 (vt.min_size = "$Byte2", vt.max_size = "$MaxSize", vt.elem.min_size = "$Byte2", vt.elem.max_size = "$MaxSize")
+        17: bool Bool2 = false
+        18: i8 Byte2 = 0
+        19: i8 Byte3 = 10
+        20: i8 Byte4 = 20
+        21: double Double2 = 0
+        22: double Double3 = 10.0
+        23: double Double4 = 20.0
+        24: string String2 = "my string"
+        25: string String3 = "other string"
+        26: string String4 = ".*"
+        27: binary Binary2 = "my binary"
+        28: binary Binary3 = "other binary"
+        29: binary Binary4 = ".*"
+        30: i64 MaxSize = 10
+}
+
+struct ValidationFunctionTest {
+        1: string StringFoo
+        2: i64 StringLength (vt.in = "[@len($StringFoo)]")
+}
+
+struct AnnotationCompatibleTest {
+        1: bool Bool0 = true (vt.const = "true", go.tag = 'json:"bool1"')
+        2: i8 Byte0 = 1 (vt.lt = "2", go.tag = 'json:"byte1"')
+        3: double Double0 = 1.0 (vt.lt = "2.0", go.tag = 'json:"double1"')
+        4: string String0 = "my const string" (vt.const = "my const string", go.tag = 'json:"string1"')
+        5: binary Binary0 = "my const string" (vt.const = "my const string", go.tag = 'json:"binary1"')
+        6: map<string, string> Map0 (vt.max_size = "2", go.tag = 'json:"map1"')
+        7: set<string> Set0 (vt.max_size = "2", go.tag = 'json:"set1"')
+        8: list<string> List0 (vt.max_size = "2", go.tag = 'json:"list1"')
+        9: EnumFoo Enum0 = EnumFoo.e2 (vt.in = "[EnumFoo.e2]", go.tag = 'json:"enum1"')
+        10: Foo Struct0 (vt.skip = "true", go.tag = 'json:"struct1"')
+}
diff --git a/lib/go/test/common/a.thrift b/lib/go/test/common/a.thrift
index 37e0e1c..f0c4723 100644
--- a/lib/go/test/common/a.thrift
+++ b/lib/go/test/common/a.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace go common
 
 struct A {
diff --git a/lib/go/test/common/b.thrift b/lib/go/test/common/b.thrift
index 19930e7..17b9b08 100644
--- a/lib/go/test/common/b.thrift
+++ b/lib/go/test/common/b.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace go common
 
 struct B {
diff --git a/lib/go/test/tests/validate_test.go b/lib/go/test/tests/validate_test.go
new file mode 100644
index 0000000..957a8df
--- /dev/null
+++ b/lib/go/test/tests/validate_test.go
@@ -0,0 +1,494 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package tests
+
+import (
+	"encoding/json"
+	"errors"
+	"strconv"
+	"testing"
+
+	"github.com/apache/thrift/lib/go/test/gopath/src/validatetest"
+	thrift "github.com/apache/thrift/lib/go/thrift"
+)
+
+func TestBasicValidator(t *testing.T) {
+	bt := validatetest.NewBasicTest()
+	if err := bt.Validate(); err != nil {
+		t.Error(err)
+	}
+	var ve *thrift.ValidationError
+	bt = validatetest.NewBasicTest()
+	bt.Bool1 = thrift.BoolPtr(false)
+	if err := bt.Validate(); err == nil {
+		t.Error("Expected vt.const error for Bool1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Bool1" {
+			t.Errorf("Expected error for Bool1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.Byte1 = thrift.Int8Ptr(3)
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Byte1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Byte1" {
+			t.Errorf("Expected error for Byte1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.Double1 = thrift.Float64Ptr(3.0)
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Double1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Double1" {
+			t.Errorf("Expected error for Double1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.String1 = thrift.StringPtr("other string")
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for String1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "String1" {
+			t.Errorf("Expected error for String1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.Binary1 = []byte("other binary")
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for Binary1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Binary1" {
+			t.Errorf("Expected error for Binary1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.Map1 = make(map[string]string)
+	for i := 0; i < 11; i++ {
+		bt.Map1[strconv.Itoa(i)] = strconv.Itoa(i)
+	}
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Map1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Map1" {
+			t.Errorf("Expected error for Map1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt.Map1 = map[string]string{"012345678910": "0"}
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Map1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Map1" {
+			t.Errorf("Expected error for Map1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt.Map1 = map[string]string{"0": "012345678910"}
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Map1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Map1" {
+			t.Errorf("Expected error for Map1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	for i := 0; i < 11; i++ {
+		bt.Set1 = append(bt.Set1, "0")
+	}
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Set1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Set1" {
+			t.Errorf("Expected error for Set1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt.Set1 = []string{"0"}
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.min_size error for Set1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.min_size" {
+			t.Errorf("Expected vt.min_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Set1" {
+			t.Errorf("Expected error for Set1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	bt = validatetest.NewBasicTest()
+	bt.Enum1 = (*validatetest.EnumFoo)(thrift.Int64Ptr(int64(validatetest.EnumFoo_e2)))
+	if err := bt.Validate(); err == nil {
+		t.Errorf("Expected vt.in error for Enum1")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.in" {
+			t.Errorf("Expected vt.in check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Enum1" {
+			t.Errorf("Expected error for Enum1, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+}
+
+func TestFieldReference(t *testing.T) {
+	frt := validatetest.NewFieldReferenceTest()
+	if err := frt.Validate(); err != nil {
+		t.Error(err)
+	}
+	var ve *thrift.ValidationError
+	frt = validatetest.NewFieldReferenceTest()
+	frt.Bool2 = true
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for Bool0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Bool0" {
+			t.Errorf("Expected error for Bool0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.Byte4 = 9
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Byte0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Byte0" {
+			t.Errorf("Expected error for Byte0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.Double4 = 9
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Double0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Double0" {
+			t.Errorf("Expected error for Double0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.String2 = "other string"
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for String0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "String0" {
+			t.Errorf("Expected error for String0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.Binary2 = []byte("other string")
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for Binary0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Binary0" {
+			t.Errorf("Expected error for Binary0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.MaxSize = 8
+	frt.Map0 = make(map[string]string)
+	for i := 0; i < 9; i++ {
+		frt.Map0[strconv.Itoa(i)] = strconv.Itoa(i)
+	}
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Map0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Map0" {
+			t.Errorf("Expected error for Map0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.MaxSize = 8
+	for i := 0; i < 9; i++ {
+		frt.List0 = append(frt.List0, "0")
+	}
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for List0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "List0" {
+			t.Errorf("Expected error for List0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	frt = validatetest.NewFieldReferenceTest()
+	frt.MaxSize = 8
+	for i := 0; i < 9; i++ {
+		frt.Set0 = append(frt.Set0, "0")
+	}
+	if err := frt.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Set0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Set0" {
+			t.Errorf("Expected error for Set0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+}
+
+func TestValidationFunction(t *testing.T) {
+	vft := validatetest.NewValidationFunctionTest()
+	if err := vft.Validate(); err != nil {
+		t.Error(err)
+	}
+	var ve *thrift.ValidationError
+	vft = validatetest.NewValidationFunctionTest()
+	vft.StringFoo = "some string"
+	if err := vft.Validate(); err == nil {
+		t.Errorf("Expected vt.in error for StringLength")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.in" {
+			t.Errorf("Expected vt.in check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "StringLength" {
+			t.Errorf("Expected error for StringLength, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+}
+
+func TestAnnotationCompatibleTest(t *testing.T) {
+	act := validatetest.NewAnnotationCompatibleTest()
+	if err := act.Validate(); err != nil {
+		t.Error(err)
+	}
+	var ve *thrift.ValidationError
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Bool0 = false
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for Bool0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Bool0" {
+			t.Errorf("Expected error for Bool0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Byte0 = 3
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Byte0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Byte0" {
+			t.Errorf("Expected error for Byte0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Double0 = 3
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.lt error for Double0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.lt" {
+			t.Errorf("Expected vt.lt check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Double0" {
+			t.Errorf("Expected error for Double0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.String0 = "other string"
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for String0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "String0" {
+			t.Errorf("Expected error for String0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Binary0 = []byte("other string")
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.const error for Binary0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.const" {
+			t.Errorf("Expected vt.const check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Binary0" {
+			t.Errorf("Expected error for Binary0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Map0 = map[string]string{"0": "0", "1": "1", "2": "2"}
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Map0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Map0" {
+			t.Errorf("Expected error for Map0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Set0 = []string{"0", "1", "2"}
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for Set0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Set0" {
+			t.Errorf("Expected error for Set0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.List0 = []string{"0", "1", "2"}
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.max_size error for List0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.max_size" {
+			t.Errorf("Expected vt.max_size check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "List0" {
+			t.Errorf("Expected error for List0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	act = validatetest.NewAnnotationCompatibleTest()
+	act.Enum0 = validatetest.EnumFoo_e1
+	if err := act.Validate(); err == nil {
+		t.Errorf("Expected vt.in error for Enum0")
+	} else if errors.As(err, &ve) {
+		if ve.Check() != "vt.in" {
+			t.Errorf("Expected vt.in check error, but got %v", ve.Check())
+		}
+		if ve.Field() != "Enum0" {
+			t.Errorf("Expected error for Enum0, but got %v", ve.Field())
+		}
+	} else {
+		t.Errorf("Error cannot be unwrapped into *ValidationError: %v", err)
+	}
+	fields := []string{"bool1", "byte1", "double1", "string1", "binary1", "enum1", "struct1", "list1", "set1", "map1"}
+	b, err := json.Marshal(act)
+	if err != nil {
+		t.Error(err)
+	}
+	jsonMap := make(map[string]interface{})
+	if err = json.Unmarshal(b, &jsonMap); err != nil {
+		t.Error(err)
+	}
+	for _, field := range fields {
+		if _, ok := jsonMap[field]; !ok {
+			t.Errorf("Expected field %s in JSON, but not found", field)
+		}
+	}
+}
diff --git a/lib/go/thrift/application_exception.go b/lib/go/thrift/application_exception.go
index ed85a64..8b8137a 100644
--- a/lib/go/thrift/application_exception.go
+++ b/lib/go/thrift/application_exception.go
@@ -21,6 +21,7 @@
 
 import (
 	"context"
+	"strings"
 )
 
 const (
@@ -35,6 +36,7 @@
 	INVALID_TRANSFORM              = 8
 	INVALID_PROTOCOL               = 9
 	UNSUPPORTED_CLIENT_TYPE        = 10
+	VALIDATION_FAILED              = 11
 )
 
 var defaultApplicationExceptionMessage = map[int32]string{
@@ -49,6 +51,7 @@
 	INVALID_TRANSFORM:              "Invalid transform",
 	INVALID_PROTOCOL:               "Invalid protocol",
 	UNSUPPORTED_CLIENT_TYPE:        "Unsupported client type",
+	VALIDATION_FAILED:              "validation failed",
 }
 
 // Application level Thrift exception
@@ -59,9 +62,39 @@
 	Write(ctx context.Context, oprot TProtocol) error
 }
 
+type ValidationError struct {
+	message     string
+	check       string
+	fieldSymbol string
+}
+
+func (e *ValidationError) Check() string {
+	return e.check
+}
+
+func (e *ValidationError) TypeName() string {
+	return strings.Split(e.fieldSymbol, ".")[0]
+}
+
+func (e *ValidationError) Field() string {
+	if fs := strings.Split(e.fieldSymbol, "."); len(fs) > 1 {
+		return fs[1]
+	}
+	return e.fieldSymbol
+}
+
+func (e *ValidationError) FieldSymbol() string {
+	return e.fieldSymbol
+}
+
+func (e ValidationError) Error() string {
+	return e.message
+}
+
 type tApplicationException struct {
 	message string
 	type_   int32
+	err     error
 }
 
 var _ TApplicationException = (*tApplicationException)(nil)
@@ -77,8 +110,20 @@
 	return defaultApplicationExceptionMessage[e.type_]
 }
 
+func (e tApplicationException) Unwrap() error {
+	return e.err
+}
+
 func NewTApplicationException(type_ int32, message string) TApplicationException {
-	return &tApplicationException{message, type_}
+	return &tApplicationException{message, type_, nil}
+}
+
+func NewValidationException(type_ int32, check string, field string, message string) TApplicationException {
+	return &tApplicationException{
+		type_:   type_,
+		message: message,
+		err:     &ValidationError{message: message, check: check, fieldSymbol: field},
+	}
 }
 
 func (p *tApplicationException) TypeId() int32 {
diff --git a/lib/haxe/haxelib.json b/lib/haxe/haxelib.json
index 5448e5f..4775ac4 100644
--- a/lib/haxe/haxelib.json
+++ b/lib/haxe/haxelib.json
@@ -10,11 +10,12 @@
 		"framework"
 	],
 	"description": "Haxe bindings for the Apache Thrift RPC and serialization framework",
-	"version": "0.17.0",
+	"version": "0.18.0",
 	"releasenote": "Licensed under Apache License, Version 2.0. The Apache Thrift compiler needs to be installed separately.",
 	"contributors": ["ApacheThrift"],
 	"dependencies": { 
-		"crypto": ""
+		"crypto": "",
+		"uuid": ""
 	},
 	"classPath": "src"
 }
diff --git a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
index a8e735f..fc5cc0b 100644
--- a/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
+++ b/lib/haxe/src/org/apache/thrift/helper/Int64Map.hx
@@ -27,7 +27,7 @@
 // Int64Map allows mapping of Int64 keys to arbitrary values.
 // ObjectMap<> cannot be used, since we want to compare by value, not address
 
-class Int64Map<T> implements IMap< Int64, T> {
+class Int64Map<T> implements haxe.Constraints.IMap< Int64, T> {
 
     private var SubMaps : IntMap< IntMap< T>>;  // Hi -> Lo -> Value
 
@@ -141,7 +141,7 @@
 		SubMaps.clear();
     }
 
-    public function copy() : IMap< Int64, T> {
+    public function copy() : haxe.Constraints.IMap< Int64, T> {
 		var retval = new Int64Map<T>();
 		for( key in this.keys())
 			retval.set( key, this.get(key));
diff --git a/lib/haxe/src/org/apache/thrift/helper/UuidHelper.hx b/lib/haxe/src/org/apache/thrift/helper/UuidHelper.hx
new file mode 100644
index 0000000..082a9d3
--- /dev/null
+++ b/lib/haxe/src/org/apache/thrift/helper/UuidHelper.hx
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+package org.apache.thrift.helper;
+
+import haxe.io.Bytes;
+import uuid.Uuid;
+
+class UuidHelper {
+	
+	public static function CanonicalUuid( uuid : String) : String {
+		uuid = StringTools.replace( uuid, "{", "");
+		uuid = StringTools.replace( uuid, "}", "");
+		uuid = Uuid.stringify( Uuid.parse( uuid));
+		return uuid;
+	}
+	
+	#if debug
+	
+	public static function UnitTest() : Void 
+	{
+		var guid : String = CanonicalUuid("{00112233-4455-6677-8899-AABBCCDDEEFF}");
+		if ( guid.length != 36)
+			throw 'UuidHelper Test: CanonicalUuid() failed';
+	}
+
+	#end
+	
+}
+
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
index 736a7dc..48b8d1e 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TBinaryProtocol.hx
@@ -25,8 +25,11 @@
 import haxe.io.BytesBuffer;
 import haxe.Int64;
 
+import uuid.Uuid;
+
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.helper.UuidHelper;
 
 /**
 * Binary protocol implementation for thrift.
@@ -164,6 +167,12 @@
         Transport.write(bin, 0, bin.length);
     }
 
+    public function writeUuid(uuid : String) : Void {		
+        var bytes : Bytes = Uuid.parse(UuidHelper.CanonicalUuid(uuid));
+        Transport.write(bytes, 0, bytes.length);
+    }
+
+
     /**
      * Reading methods.
      */
@@ -300,6 +309,13 @@
         return buffer.getBytes();
     }
 
+    public function readUuid() : String {
+        var buffer = new BytesBuffer();
+        Transport.readAll( buffer, 0, 16);
+        var bytes : Bytes = buffer.getBytes();
+        return Uuid.stringify( bytes);
+    }
+
 	// Return the minimum number of bytes a type will consume on the wire
 	public override function GetMinSerializedSize(type : TType) : Int
 	{
@@ -318,6 +334,7 @@
 			case TType.MAP: return 4;  // element count
 			case TType.SET: return 4;  // element count
 			case TType.LIST: return 4;  // element count
+			case TType.UUID: return 16;  // uuid bytes
 			default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
 		}
 	}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
index bf7b886..d3577f1 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactProtocol.hx
@@ -28,11 +28,13 @@
 import haxe.Int32;
 import haxe.Int64;
 
+import uuid.Uuid;
+
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.helper.ZigZag;
 import org.apache.thrift.helper.BitConverter;
-
+import org.apache.thrift.helper.UuidHelper;
 
 /**
 * Compact protocol implementation for thrift.
@@ -62,7 +64,8 @@
         TType.STRUCT  => TCompactTypes.STRUCT,
         TType.MAP     => TCompactTypes.MAP,
         TType.SET     => TCompactTypes.SET,
-        TType.LIST    => TCompactTypes.LIST
+        TType.LIST    => TCompactTypes.LIST,
+        TType.UUID    => TCompactTypes.UUID
     ];
 
     private static var tcompactTypeToType = [
@@ -78,7 +81,8 @@
         TCompactTypes.LIST          => TType.LIST,
         TCompactTypes.SET           => TType.SET,
         TCompactTypes.MAP           => TType.MAP,
-        TCompactTypes.STRUCT        => TType.STRUCT
+        TCompactTypes.STRUCT        => TType.STRUCT,
+        TCompactTypes.UUID          => TType.UUID
     ];
 
 
@@ -337,6 +341,10 @@
         Transport.write( bin, 0, bin.length);
     }
 
+    public function writeUuid(uuid : String) : Void {
+        var bytes : Bytes = Uuid.parse(UuidHelper.CanonicalUuid(uuid));
+        Transport.write(bytes, 0, bytes.length);
+    }
 
     // These methods are called by structs, but don't actually have any wire
     // output or purpose.
@@ -616,6 +624,13 @@
     }
 
 
+    public function readUuid() : String {
+        var buffer = new BytesBuffer();
+        Transport.readAll( buffer, 0, 16);
+        var bytes : Bytes = buffer.getBytes();
+        return Uuid.stringify( bytes);
+    }
+
     // These methods are here for the struct to call, but don't have any wire
     // encoding.
     public function readMessageEnd() : Void { }
@@ -723,6 +738,7 @@
 			case TType.MAP:     return 1;  // element count
 			case TType.SET:    return 1;  // element count
 			case TType.LIST:    return 1;  // element count
+			case TType.UUID: return 16;  // uuid bytes
 			default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
 		}
 	}
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx b/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx
index cdd3d87..a3a7aac 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TCompactTypes.hx
@@ -37,5 +37,6 @@
     public static inline var SET           = 0x0A;
     public static inline var MAP           = 0x0B;
     public static inline var STRUCT        = 0x0C;
+    public static inline var UUID          = 0x0D;
 }
 
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
index 2385ca8..a47479d 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TJSONProtocol.hx
@@ -28,6 +28,8 @@
 import haxe.crypto.Base64;
 import haxe.Int64;
 
+import uuid.Uuid;
+
 import org.apache.thrift.TException;
 import org.apache.thrift.protocol.TMessage;
 import org.apache.thrift.protocol.TField;
@@ -35,6 +37,7 @@
 import org.apache.thrift.protocol.TSet;
 import org.apache.thrift.protocol.TList;
 import org.apache.thrift.transport.TTransport;
+import org.apache.thrift.helper.UuidHelper;
 
 
 
@@ -164,6 +167,10 @@
         WriteJSONBase64(bin);
     }
 
+    public function writeUuid(uuid : String) : Void {
+		writeString( UuidHelper.CanonicalUuid(uuid)); 
+    }
+
     public function readMessageBegin():TMessage {
         var message : TMessage = new TMessage();
         ReadJSONArrayStart();
@@ -289,6 +296,10 @@
         return ReadJSONBase64();
     }
 
+    public function readUuid() : String {
+        return UuidHelper.CanonicalUuid( readString()); 
+    }
+
     // Push a new JSON context onto the stack.
     private function  PushContext(c : JSONBaseContext) : Void {
         contextStack.add(context);
@@ -794,6 +805,7 @@
 			case TType.MAP: return 2;  // empty map
 			case TType.SET: return 2;  // empty set
 			case TType.LIST: return 2;  // empty list
+			case TType.UUID: return 36;  // "E236974D-F0B0-4E05-8F29-0B455D41B1A1"
 			default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
 		}
 	}
@@ -892,6 +904,7 @@
     public static var NAME_MAP    = 'map';
     public static var NAME_LIST   = 'lst';
     public static var NAME_SET    = 'set';
+	public static var NAME_UUID   = 'uid';
 
     public static function GetTypeNameForTypeID(typeID : Int) : String {
         switch (typeID)
@@ -907,6 +920,7 @@
             case TType.MAP:         return NAME_MAP;
             case TType.SET:         return NAME_SET;
             case TType.LIST:     return NAME_LIST;
+            case TType.UUID:     return NAME_UUID;
         }
         throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized type");
     }
@@ -922,7 +936,8 @@
         NAME_STRUCT => TType.STRUCT,
         NAME_MAP    => TType.MAP,
         NAME_SET    => TType.SET,
-        NAME_LIST   => TType.LIST
+        NAME_LIST   => TType.LIST,
+		NAME_UUID   => TType.UUID
     ];
 
     public static function GetTypeIDForTypeName(name : String) : Int
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
index 316067a..6ce5999 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TProtocol.hx
@@ -20,7 +20,6 @@
 package org.apache.thrift.protocol;
 
 import haxe.io.Bytes;
-import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 
 /**
@@ -54,6 +53,7 @@
     function writeDouble(dub : Float) : Void;
     function writeString(str : String) : Void;
     function writeBinary(bin : Bytes) : Void;
+	function writeUuid(uuid : String) : Void;
 
     /**
      * Reading methods.
@@ -78,6 +78,7 @@
     function readDouble() : Float;
     function readString() : String;
     function readBinary() : Bytes;
+	function readUuid() : String;
 
     // recursion tracking
     function IncrementRecursionDepth() : Void;
diff --git a/lib/haxe/src/org/apache/thrift/protocol/TType.hx b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
index 964b26e..8e21ed7 100644
--- a/lib/haxe/src/org/apache/thrift/protocol/TType.hx
+++ b/lib/haxe/src/org/apache/thrift/protocol/TType.hx
@@ -34,4 +34,5 @@
     public static inline var MAP : Int    = 13;
     public static inline var SET : Int    = 14;
     public static inline var LIST : Int   = 15;
+	public static inline var UUID : Int   = 16;
 }
diff --git a/lib/haxe/test/cpp.hxml b/lib/haxe/test/cpp.hxml
index 28e1a01..04a2543 100644
--- a/lib/haxe/test/cpp.hxml
+++ b/lib/haxe/test/cpp.hxml
@@ -36,11 +36,11 @@
 #To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
 #-D HXCPP_M64
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/csharp.hxml b/lib/haxe/test/csharp.hxml
index 6ddfd07..e406ce6 100644
--- a/lib/haxe/test/csharp.hxml
+++ b/lib/haxe/test/csharp.hxml
@@ -33,11 +33,11 @@
 #CSHARP target
 -cs bin/Test.exe
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/flash.hxml b/lib/haxe/test/flash.hxml
index 130ab78..6df1f61 100644
--- a/lib/haxe/test/flash.hxml
+++ b/lib/haxe/test/flash.hxml
@@ -33,11 +33,11 @@
 #Flash target
 -swf bin/Test.swf
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/java.hxml b/lib/haxe/test/java.hxml
index b72d99f..0b214d7 100644
--- a/lib/haxe/test/java.hxml
+++ b/lib/haxe/test/java.hxml
@@ -33,11 +33,11 @@
 #Java target
 -java bin/Test.jar
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/javascript.hxml b/lib/haxe/test/javascript.hxml
index 496e780..ad21d16 100644
--- a/lib/haxe/test/javascript.hxml
+++ b/lib/haxe/test/javascript.hxml
@@ -39,11 +39,11 @@
 #you modify your .hx files.
 -D source-map-content
 
+# libs
+-lib uuid
+
 #Generate source map and add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/neko.hxml b/lib/haxe/test/neko.hxml
index eed22bd..51de778 100644
--- a/lib/haxe/test/neko.hxml
+++ b/lib/haxe/test/neko.hxml
@@ -33,11 +33,11 @@
 #neko target
 -neko bin/Test.n
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/php.hxml b/lib/haxe/test/php.hxml
index 3af54da..f94e641 100644
--- a/lib/haxe/test/php.hxml
+++ b/lib/haxe/test/php.hxml
@@ -34,11 +34,11 @@
 -php bin/php/
 #--php-front Main-debug.php
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
diff --git a/lib/haxe/test/python.hxml b/lib/haxe/test/python.hxml
index 58eb3cb..dbb48e2 100644
--- a/lib/haxe/test/python.hxml
+++ b/lib/haxe/test/python.hxml
@@ -33,11 +33,11 @@
 #Python target
 -python bin/Test.py
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/lib/haxe/test/src/Main.hx b/lib/haxe/test/src/Main.hx
index e04af78..5976bb0 100644
--- a/lib/haxe/test/src/Main.hx
+++ b/lib/haxe/test/src/Main.hx
@@ -76,9 +76,13 @@
 
             switch( tests) {
                 case Normal:
+                    #if sys
                     StreamTest.Run(server);
+                    #end
                 case Multiplex:
+                    #if ! (flash || html5 || js)
                     MultiplexTest.Run(server);
+                    #end
                 case Constants:
                     ConstantsTest.Run(server);
                 default:
diff --git a/lib/haxe/test/src/MultiplexTest.hx b/lib/haxe/test/src/MultiplexTest.hx
index 74fa357..a17bf15 100644
--- a/lib/haxe/test/src/MultiplexTest.hx
+++ b/lib/haxe/test/src/MultiplexTest.hx
@@ -19,6 +19,8 @@
 
 package;
 
+#if ! (flash || html5 || js)
+
 import haxe.Int64;
 import haxe.Int32;
 
@@ -42,7 +44,6 @@
 import BenchmarkServiceProcessor;
 import Error;
 
-
 class BenchmarkServiceHandler implements BenchmarkService_service
 {
     public function new() {
@@ -221,4 +222,5 @@
 
 }
 
+#end
 
diff --git a/lib/haxe/test/src/StreamTest.hx b/lib/haxe/test/src/StreamTest.hx
index 4744272..3e70ada 100644
--- a/lib/haxe/test/src/StreamTest.hx
+++ b/lib/haxe/test/src/StreamTest.hx
@@ -18,6 +18,7 @@
  */
 
 package;
+#if sys
 
 import haxe.Int64;
 import sys.FileSystem;
@@ -95,3 +96,4 @@
 }
 
 
+#end
diff --git a/lib/java/README.md b/lib/java/README.md
index d60dbb7..cd12932 100644
--- a/lib/java/README.md
+++ b/lib/java/README.md
@@ -42,7 +42,7 @@
 the Gradle build system, which tends to be predominant amongst Java
 developers.
 
-Currently we use gradle 7.4.2 to build the Thrift Java source. The usual way to setup gradle
+Currently we use gradle 7.5.1 to build the Thrift Java source. The usual way to setup gradle
 project is to include the gradle-wrapper.jar in the project and then run the gradle wrapper to
 bootstrap setting up gradle binaries. However to avoid putting binary files into the source tree we
 have ignored the gradle wrapper files. You are expected to install it manually, as described in
@@ -50,13 +50,13 @@
 following this step (which is also done in the travis CI docker images):
 
 ```bash
-export GRADLE_VERSION="7.4.2"
+export GRADLE_VERSION="7.5.1"
 # install dependencies
 apt-get install -y --no-install-recommends openjdk-11-jdk-headless wget unzip
 # download gradle distribution
 wget https://services.gradle.org/distributions/gradle-$GRADLE_VERSION-bin.zip -q -O /tmp/gradle-$GRADLE_VERSION-bin.zip
 # check binary integrity
-echo "29e49b10984e585d8118b7d0bc452f944e386458df27371b49b4ac1dec4b7fda  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -
+echo "f6b8596b10cce501591e92f229816aa4046424f3b24d771751b06779d58c8ec4  /tmp/gradle-$GRADLE_VERSION-bin.zip" | sha256sum -c -
 # unzip and install
 unzip -d /tmp /tmp/gradle-$GRADLE_VERSION-bin.zip
 mv /tmp/gradle-$GRADLE_VERSION /usr/local/gradle
diff --git a/lib/java/gradle.properties b/lib/java/gradle.properties
index b375fad..3ef6a5f 100644
--- a/lib/java/gradle.properties
+++ b/lib/java/gradle.properties
@@ -1,7 +1,7 @@
 # This file is shared currently between this Gradle build and the
 # Ant builds for fd303 and JavaScript. Keep the dotted notation for
 # the properties to minimize the changes in the dependencies.
-thrift.version=0.17.0
+thrift.version=0.18.0
 thrift.groupid=org.apache.thrift
 release=false
 
@@ -34,3 +34,9 @@
 mockito.version=1.10.19
 javax.annotation.version=1.3.2
 commons-lang3.version=3.12.0
+
+org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
+  --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
diff --git a/lib/java/src/crossTest/java/org/apache/thrift/test/TestClient.java b/lib/java/src/crossTest/java/org/apache/thrift/test/TestClient.java
index 3c54988..2807a43 100644
--- a/lib/java/src/crossTest/java/org/apache/thrift/test/TestClient.java
+++ b/lib/java/src/crossTest/java/org/apache/thrift/test/TestClient.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.stream.IntStream;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.thrift.TApplicationException;
@@ -251,6 +252,15 @@
           System.out.println("*** FAILURE ***\n");
         }
 
+        /** UUID TEST */
+        System.out.println("testUuid(\"00112233-4455-6677-8899-aabbccddeeff\")");
+        UUID uuid = testClient.testUuid(UUID.fromString("00112233-4455-6677-8899-aabbccddeeff"));
+        System.out.print(" = \"" + uuid + "\"\n");
+        if (!uuid.equals(UUID.fromString("00112233-4455-6677-8899-aabbccddeeff"))) {
+          returnCode |= ERR_BASETYPES;
+          System.out.println("*** FAILURE ***\n");
+        }
+
         /** Multiplexed test */
         if (protocol_type.startsWith("multi")) {
           SecondService.Client secondClient = new SecondService.Client(tProtocol2);
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
index 34e7517..263a818 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TBinaryProtocol.java
@@ -21,6 +21,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.UUID;
 import org.apache.thrift.TException;
 import org.apache.thrift.partial.TFieldData;
 import org.apache.thrift.transport.TTransport;
@@ -49,7 +50,7 @@
   protected boolean strictRead_;
   protected boolean strictWrite_;
 
-  private final byte[] inoutTemp = new byte[8];
+  private final byte[] inoutTemp = new byte[16];
 
   /** Factory */
   public static class Factory implements TProtocolFactory {
@@ -219,6 +220,33 @@
   }
 
   @Override
+  public void writeUuid(UUID uuid) throws TException {
+    {
+      long lsb = uuid.getLeastSignificantBits();
+      inoutTemp[0] = (byte) (0xff & (lsb >> 56));
+      inoutTemp[1] = (byte) (0xff & (lsb >> 48));
+      inoutTemp[2] = (byte) (0xff & (lsb >> 40));
+      inoutTemp[3] = (byte) (0xff & (lsb >> 32));
+      inoutTemp[4] = (byte) (0xff & (lsb >> 24));
+      inoutTemp[5] = (byte) (0xff & (lsb >> 16));
+      inoutTemp[6] = (byte) (0xff & (lsb >> 8));
+      inoutTemp[7] = (byte) (0xff & (lsb));
+    }
+    {
+      long msb = uuid.getMostSignificantBits();
+      inoutTemp[8] = (byte) (0xff & (msb >> 56));
+      inoutTemp[1 + 8] = (byte) (0xff & (msb >> 48));
+      inoutTemp[2 + 8] = (byte) (0xff & (msb >> 40));
+      inoutTemp[3 + 8] = (byte) (0xff & (msb >> 32));
+      inoutTemp[4 + 8] = (byte) (0xff & (msb >> 24));
+      inoutTemp[5 + 8] = (byte) (0xff & (msb >> 16));
+      inoutTemp[6 + 8] = (byte) (0xff & (msb >> 8));
+      inoutTemp[7 + 8] = (byte) (0xff & (msb));
+    }
+    trans_.write(inoutTemp, 0, 16);
+  }
+
+  @Override
   public void writeDouble(double dub) throws TException {
     writeI64(Double.doubleToLongBits(dub));
   }
@@ -388,6 +416,40 @@
   }
 
   @Override
+  public UUID readUuid() throws TException {
+    byte[] buf = inoutTemp;
+    int off = 0;
+
+    if (trans_.getBytesRemainingInBuffer() >= 16) {
+      buf = trans_.getBuffer();
+      off = trans_.getBufferPosition();
+      trans_.consumeBuffer(16);
+    } else {
+      readAll(inoutTemp, 0, 16);
+    }
+    long lsb =
+        ((long) (buf[off] & 0xff) << 56)
+            | ((long) (buf[off + 1] & 0xff) << 48)
+            | ((long) (buf[off + 2] & 0xff) << 40)
+            | ((long) (buf[off + 3] & 0xff) << 32)
+            | ((long) (buf[off + 4] & 0xff) << 24)
+            | ((long) (buf[off + 5] & 0xff) << 16)
+            | ((long) (buf[off + 6] & 0xff) << 8)
+            | ((long) (buf[off + 7] & 0xff));
+
+    long msb =
+        ((long) (buf[off + 8] & 0xff) << 56)
+            | ((long) (buf[off + 8 + 1] & 0xff) << 48)
+            | ((long) (buf[off + 8 + 2] & 0xff) << 40)
+            | ((long) (buf[off + 8 + 3] & 0xff) << 32)
+            | ((long) (buf[off + 8 + 4] & 0xff) << 24)
+            | ((long) (buf[off + 8 + 5] & 0xff) << 16)
+            | ((long) (buf[off + 8 + 6] & 0xff) << 8)
+            | ((long) (buf[off + 8 + 7] & 0xff));
+    return new UUID(msb, lsb);
+  }
+
+  @Override
   public double readDouble() throws TException {
     return Double.longBitsToDouble(readI64());
   }
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
index fffd687..b522956 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TCompactProtocol.java
@@ -21,6 +21,7 @@
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
+import java.util.UUID;
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportException;
@@ -42,7 +43,7 @@
   private static final TStruct ANONYMOUS_STRUCT = new TStruct("");
   private static final TField TSTOP = new TField("", TType.STOP, (short) 0);
 
-  private static final byte[] ttypeToCompactType = new byte[16];
+  private static final byte[] ttypeToCompactType = new byte[18];
 
   static {
     ttypeToCompactType[TType.STOP] = TType.STOP;
@@ -57,6 +58,7 @@
     ttypeToCompactType[TType.SET] = Types.SET;
     ttypeToCompactType[TType.MAP] = Types.MAP;
     ttypeToCompactType[TType.STRUCT] = Types.STRUCT;
+    ttypeToCompactType[TType.UUID] = Types.UUID;
   }
 
   /** TProtocolFactory that produces TCompactProtocols. */
@@ -104,6 +106,7 @@
     public static final byte SET = 0x0A;
     public static final byte MAP = 0x0B;
     public static final byte STRUCT = 0x0C;
+    public static final byte UUID = 0x0D;
   }
 
   /**
@@ -141,7 +144,7 @@
   /**
    * Temporary buffer used for various operations that would otherwise require a small allocation.
    */
-  private final byte[] temp = new byte[10];
+  private final byte[] temp = new byte[16];
 
   /**
    * Create a TCompactProtocol.
@@ -338,6 +341,13 @@
     trans_.write(temp, 0, 8);
   }
 
+  @Override
+  public void writeUuid(UUID uuid) throws TException {
+    fixedLongToBytes(uuid.getLeastSignificantBits(), temp, 0);
+    fixedLongToBytes(uuid.getMostSignificantBits(), temp, 8);
+    trans_.write(temp, 0, 16);
+  }
+
   /** Write a string to the wire with a varint size preceding. */
   @Override
   public void writeString(String str) throws TException {
@@ -650,6 +660,14 @@
     return Double.longBitsToDouble(bytesToLong(temp));
   }
 
+  @Override
+  public UUID readUuid() throws TException {
+    trans_.readAll(temp, 0, 16);
+    long mostSigBits = bytesToLong(temp, 8);
+    long leastSigBits = bytesToLong(temp, 0);
+    return new UUID(mostSigBits, leastSigBits);
+  }
+
   /** Reads a byte[] (via readBinary), and then UTF-8 decodes it. */
   @Override
   public String readString() throws TException {
@@ -825,14 +843,18 @@
    * ints, and when you shift an int left 56 bits, you just get a messed up int.
    */
   private long bytesToLong(byte[] bytes) {
-    return ((bytes[7] & 0xffL) << 56)
-        | ((bytes[6] & 0xffL) << 48)
-        | ((bytes[5] & 0xffL) << 40)
-        | ((bytes[4] & 0xffL) << 32)
-        | ((bytes[3] & 0xffL) << 24)
-        | ((bytes[2] & 0xffL) << 16)
-        | ((bytes[1] & 0xffL) << 8)
-        | ((bytes[0] & 0xffL));
+    return bytesToLong(bytes, 0);
+  }
+
+  private long bytesToLong(byte[] bytes, int offset) {
+    return ((bytes[offset + 7] & 0xffL) << 56)
+        | ((bytes[offset + 6] & 0xffL) << 48)
+        | ((bytes[offset + 5] & 0xffL) << 40)
+        | ((bytes[offset + 4] & 0xffL) << 32)
+        | ((bytes[offset + 3] & 0xffL) << 24)
+        | ((bytes[offset + 2] & 0xffL) << 16)
+        | ((bytes[offset + 1] & 0xffL) << 8)
+        | ((bytes[offset + 0] & 0xffL));
   }
 
   //
@@ -860,6 +882,8 @@
         return TType.I32;
       case Types.I64:
         return TType.I64;
+      case Types.UUID:
+        return TType.UUID;
       case Types.DOUBLE:
         return TType.DOUBLE;
       case Types.BINARY:
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
index dd24ca4..a2f0eac 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TJSONProtocol.java
@@ -24,6 +24,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Stack;
+import java.util.UUID;
 import org.apache.thrift.TByteArrayOutputStream;
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
@@ -87,6 +88,7 @@
   private static final byte[] NAME_I16 = new byte[] {'i', '1', '6'};
   private static final byte[] NAME_I32 = new byte[] {'i', '3', '2'};
   private static final byte[] NAME_I64 = new byte[] {'i', '6', '4'};
+  private static final byte[] NAME_UUID = new byte[] {'u', 'i', 'd'};
   private static final byte[] NAME_DOUBLE = new byte[] {'d', 'b', 'l'};
   private static final byte[] NAME_STRUCT = new byte[] {'r', 'e', 'c'};
   private static final byte[] NAME_STRING = new byte[] {'s', 't', 'r'};
@@ -96,7 +98,7 @@
 
   private static final TStruct ANONYMOUS_STRUCT = new TStruct();
 
-  private static final byte[] getTypeNameForTypeID(byte typeID) throws TException {
+  private static byte[] getTypeNameForTypeID(byte typeID) throws TException {
     switch (typeID) {
       case TType.BOOL:
         return NAME_BOOL;
@@ -108,6 +110,8 @@
         return NAME_I32;
       case TType.I64:
         return NAME_I64;
+      case TType.UUID:
+        return NAME_UUID;
       case TType.DOUBLE:
         return NAME_DOUBLE;
       case TType.STRING:
@@ -125,7 +129,7 @@
     }
   }
 
-  private static final byte getTypeIDForTypeName(byte[] name) throws TException {
+  private static byte getTypeIDForTypeName(byte[] name) throws TException {
     byte result = TType.STOP;
     if (name.length > 1) {
       switch (name[0]) {
@@ -164,6 +168,9 @@
             result = TType.SET;
           }
           break;
+        case 'u':
+          result = TType.UUID;
+          break;
         case 't':
           result = TType.BOOL;
           break;
@@ -591,6 +598,11 @@
   }
 
   @Override
+  public void writeUuid(UUID uuid) throws TException {
+    writeJSONString(uuid.toString().getBytes(StandardCharsets.UTF_8));
+  }
+
+  @Override
   public void writeDouble(double dub) throws TException {
     writeJSONDouble(dub);
   }
@@ -937,6 +949,11 @@
   }
 
   @Override
+  public UUID readUuid() throws TException {
+    return UUID.fromString(readString());
+  }
+
+  @Override
   public double readDouble() throws TException {
     return readJSONDouble();
   }
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolDecorator.java b/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolDecorator.java
index 668ebce..c237ce4 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolDecorator.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolDecorator.java
@@ -20,6 +20,7 @@
 package org.apache.thrift.protocol;
 
 import java.nio.ByteBuffer;
+import java.util.UUID;
 import org.apache.thrift.TException;
 
 /**
@@ -62,6 +63,16 @@
   }
 
   @Override
+  public UUID readUuid() throws TException {
+    return concreteProtocol.readUuid();
+  }
+
+  @Override
+  public void writeUuid(UUID uuid) throws TException {
+    concreteProtocol.writeUuid(uuid);
+  }
+
+  @Override
   public void writeStructEnd() throws TException {
     concreteProtocol.writeStructEnd();
   }
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolUtil.java b/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolUtil.java
index a9f566e..7b44b10 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolUtil.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TProtocolUtil.java
@@ -86,6 +86,10 @@
         prot.readI64();
         break;
 
+      case TType.UUID:
+        prot.readUuid();
+        break;
+
       case TType.DOUBLE:
         prot.readDouble();
         break;
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TReadProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TReadProtocol.java
index d21c9a0..b15737a 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TReadProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TReadProtocol.java
@@ -1,6 +1,7 @@
 package org.apache.thrift.protocol;
 
 import java.nio.ByteBuffer;
+import java.util.UUID;
 import org.apache.thrift.TException;
 
 public interface TReadProtocol {
@@ -39,6 +40,8 @@
 
   long readI64() throws TException;
 
+  UUID readUuid() throws TException;
+
   double readDouble() throws TException;
 
   String readString() throws TException;
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
index 0b94887..1b69032 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TSimpleJSONProtocol.java
@@ -22,6 +22,7 @@
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
 import java.util.Stack;
+import java.util.UUID;
 import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TTransportException;
@@ -277,6 +278,11 @@
   }
 
   @Override
+  public void writeUuid(UUID uuid) throws TException {
+    writeString(uuid.toString());
+  }
+
+  @Override
   public void writeDouble(double dub) throws TException {
     if (writeContext_.isMapKey()) {
       writeString(Double.toString(dub));
@@ -443,6 +449,11 @@
   }
 
   @Override
+  public UUID readUuid() throws TException {
+    throw new TException("Not implemented");
+  }
+
+  @Override
   public double readDouble() throws TException {
     throw new TException("Not implemented");
   }
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TType.java b/lib/java/src/main/java/org/apache/thrift/protocol/TType.java
index 4b70bb2..5a64e42 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TType.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TType.java
@@ -35,4 +35,5 @@
   public static final byte SET = 14;
   public static final byte LIST = 15;
   public static final byte ENUM = 16;
+  public static final byte UUID = 17;
 }
diff --git a/lib/java/src/main/java/org/apache/thrift/protocol/TWriteProtocol.java b/lib/java/src/main/java/org/apache/thrift/protocol/TWriteProtocol.java
index 339a6b8..e44ac8e 100644
--- a/lib/java/src/main/java/org/apache/thrift/protocol/TWriteProtocol.java
+++ b/lib/java/src/main/java/org/apache/thrift/protocol/TWriteProtocol.java
@@ -1,6 +1,7 @@
 package org.apache.thrift.protocol;
 
 import java.nio.ByteBuffer;
+import java.util.UUID;
 import org.apache.thrift.TException;
 
 public interface TWriteProtocol {
@@ -41,6 +42,8 @@
 
   void writeI64(long i64) throws TException;
 
+  void writeUuid(UUID uuid) throws TException;
+
   void writeDouble(double dub) throws TException;
 
   void writeString(String str) throws TException;
diff --git a/lib/java/src/test/java/org/apache/thrift/TestStruct.java b/lib/java/src/test/java/org/apache/thrift/TestStruct.java
index 17a00f1..aa283f4 100644
--- a/lib/java/src/test/java/org/apache/thrift/TestStruct.java
+++ b/lib/java/src/test/java/org/apache/thrift/TestStruct.java
@@ -210,17 +210,19 @@
     Map<CrazyNesting._Fields, FieldMetaData> mdMap = CrazyNesting.metaDataMap;
 
     // Check for struct fields existence
-    assertEquals(4, mdMap.size());
+    assertEquals(5, mdMap.size());
     assertTrue(mdMap.containsKey(CrazyNesting._Fields.SET_FIELD));
     assertTrue(mdMap.containsKey(CrazyNesting._Fields.LIST_FIELD));
     assertTrue(mdMap.containsKey(CrazyNesting._Fields.STRING_FIELD));
     assertTrue(mdMap.containsKey(CrazyNesting._Fields.BINARY_FIELD));
+    assertTrue(mdMap.containsKey(CrazyNesting._Fields.UUID_FIELD));
 
     // Check for struct fields contents
     assertEquals("string_field", mdMap.get(CrazyNesting._Fields.STRING_FIELD).fieldName);
     assertEquals("list_field", mdMap.get(CrazyNesting._Fields.LIST_FIELD).fieldName);
     assertEquals("set_field", mdMap.get(CrazyNesting._Fields.SET_FIELD).fieldName);
     assertEquals("binary_field", mdMap.get(CrazyNesting._Fields.BINARY_FIELD).fieldName);
+    assertEquals("uuid_field", mdMap.get(CrazyNesting._Fields.UUID_FIELD).fieldName);
 
     assertEquals(
         TFieldRequirementType.DEFAULT,
@@ -235,6 +237,7 @@
     assertEquals(TType.LIST, mdMap.get(CrazyNesting._Fields.LIST_FIELD).valueMetaData.type);
     assertEquals(TType.SET, mdMap.get(CrazyNesting._Fields.SET_FIELD).valueMetaData.type);
     assertEquals(TType.STRING, mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.type);
+    assertEquals(TType.UUID, mdMap.get(CrazyNesting._Fields.UUID_FIELD).valueMetaData.type);
     assertTrue(mdMap.get(CrazyNesting._Fields.BINARY_FIELD).valueMetaData.isBinary());
 
     // Check nested structures
diff --git a/lib/java/src/test/java/org/apache/thrift/protocol/ProtocolTestBase.java b/lib/java/src/test/java/org/apache/thrift/protocol/ProtocolTestBase.java
index a111292..0dd48a4 100644
--- a/lib/java/src/test/java/org/apache/thrift/protocol/ProtocolTestBase.java
+++ b/lib/java/src/test/java/org/apache/thrift/protocol/ProtocolTestBase.java
@@ -27,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.thrift.Fixtures;
@@ -126,6 +127,15 @@
   }
 
   @Test
+  public void testUuid() throws Exception {
+    UUID uuid = UUID.fromString("00112233-4455-6677-8899-aabbccddeeff");
+    if (canBeUsedNaked()) {
+      internalTestNakedUuid(uuid);
+    }
+    internalTestUuidField(uuid);
+  }
+
+  @Test
   public void testLong() throws Exception {
     if (canBeUsedNaked()) {
       internalTestNakedI64(0);
@@ -215,6 +225,28 @@
         });
   }
 
+  private void internalTestNakedUuid(UUID uuid) throws TException {
+    TMemoryBuffer buf = new TMemoryBuffer(0);
+    TProtocol protocol = getFactory().getProtocol(buf);
+    protocol.writeUuid(uuid);
+    assertEquals(uuid, protocol.readUuid());
+  }
+
+  private void internalTestUuidField(UUID uuid) throws Exception {
+    internalTestStructField(
+        new StructFieldTestCase(TType.UUID, (short) 17) {
+          @Override
+          public void writeMethod(TProtocol proto) throws TException {
+            proto.writeUuid(uuid);
+          }
+
+          @Override
+          public void readMethod(TProtocol proto) throws TException {
+            assertEquals(uuid, proto.readUuid());
+          }
+        });
+  }
+
   private void internalTestNakedI32(int n) throws Exception {
     TMemoryBuffer buf = new TMemoryBuffer(0);
     TProtocol proto = getFactory().getProtocol(buf);
diff --git a/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java b/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
index a1e19eb..8d0c7aa 100644
--- a/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
+++ b/lib/java/src/test/java/org/apache/thrift/server/ServerTestBase.java
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.UUID;
 import org.apache.thrift.TException;
 import org.apache.thrift.TProcessor;
 import org.apache.thrift.async.AsyncMethodCallback;
@@ -115,6 +116,12 @@
     }
 
     @Override
+    public UUID testUuid(UUID thing) throws TException {
+      System.out.println("testUuid(" + thing + ")");
+      return thing;
+    }
+
+    @Override
     public Xtruct testStruct(Xtruct thing) {
       System.out.print(
           "testStruct({"
@@ -675,6 +682,11 @@
     }
 
     @Override
+    public void testUuid(UUID thing, AsyncMethodCallback<UUID> resultHandler) throws TException {
+      resultHandler.onComplete(handler.testUuid(thing));
+    }
+
+    @Override
     public void testStruct(Xtruct thing, AsyncMethodCallback<Xtruct> resultHandler)
         throws TException {
       resultHandler.onComplete(handler.testStruct(thing));
diff --git a/lib/java/src/test/resources/JavaDeepCopyTest.thrift b/lib/java/src/test/resources/JavaDeepCopyTest.thrift
index fc974ae..097ed69 100644
--- a/lib/java/src/test/resources/JavaDeepCopyTest.thrift
+++ b/lib/java/src/test/resources/JavaDeepCopyTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 "JavaTypes.thrift"
 
 namespace java thrift.test
diff --git a/lib/java/src/test/resources/JavaStructOrderA.thrift b/lib/java/src/test/resources/JavaStructOrderA.thrift
index bac5209..f00a710 100644
--- a/lib/java/src/test/resources/JavaStructOrderA.thrift
+++ b/lib/java/src/test/resources/JavaStructOrderA.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 // Define Parent, then Child. No forward declarations.
 struct Parent {
     1: required string Name
diff --git a/lib/java/src/test/resources/JavaStructOrderB.thrift b/lib/java/src/test/resources/JavaStructOrderB.thrift
index aa2afea..4682668 100644
--- a/lib/java/src/test/resources/JavaStructOrderB.thrift
+++ b/lib/java/src/test/resources/JavaStructOrderB.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 // Define Child, then Parent. Parent is a forward declaration and was problematic for our Java compiler before
 // fixing THRIFT-4086: Java compiler generates different meta data depending on order of structures in file
 struct Child {
diff --git a/lib/java/src/test/resources/JavaTypes.thrift b/lib/java/src/test/resources/JavaTypes.thrift
index 5553340..6afb6f9 100644
--- a/lib/java/src/test/resources/JavaTypes.thrift
+++ b/lib/java/src/test/resources/JavaTypes.thrift
@@ -51,6 +51,10 @@
   1: double val
 }
 
+struct Uuid {
+  1: uuid val
+}
+
 struct List {
   1: list<string> vals
 }
diff --git a/lib/js/Gruntfile.js b/lib/js/Gruntfile.js
index 4421f0c..9771314 100644
--- a/lib/js/Gruntfile.js
+++ b/lib/js/Gruntfile.js
@@ -49,16 +49,16 @@
       },
       ThriftGen: {
         command: [
-          '"../../compiler/cpp/thrift" -gen js --out test/gen-js ../../test/ThriftTest.thrift',
+          '"../../compiler/cpp/thrift" -gen js --out test/gen-js ../../test/v0.16/ThriftTest.thrift',
           '"../../compiler/cpp/thrift" -gen js --out test/gen-js ../../test/JsDeepConstructorTest.thrift',
-          '"../../compiler/cpp/thrift" -gen js:jquery --out test/gen-js-jquery ../../test/ThriftTest.thrift',
-          '"../../compiler/cpp/thrift" -gen js:node --out test/gen-nodejs ../../test/ThriftTest.thrift',
-          '"../../compiler/cpp/thrift" -gen js:es6 --out test/gen-js-es6 ../../test/ThriftTest.thrift',
-          '"../../compiler/cpp/thrift" -gen js:node,es6 --out ./test/gen-nodejs-es6 ../../test/ThriftTest.thrift',
+          '"../../compiler/cpp/thrift" -gen js:jquery --out test/gen-js-jquery ../../test/v0.16/ThriftTest.thrift',
+          '"../../compiler/cpp/thrift" -gen js:node --out test/gen-nodejs ../../test/v0.16/ThriftTest.thrift',
+          '"../../compiler/cpp/thrift" -gen js:es6 --out test/gen-js-es6 ../../test/v0.16/ThriftTest.thrift',
+          '"../../compiler/cpp/thrift" -gen js:node,es6 --out ./test/gen-nodejs-es6 ../../test/v0.16/ThriftTest.thrift',
         ].join(' && ')
       },
       ThriftGenJQ: {
-        command: '../../compiler/cpp/thrift -gen js:jquery -gen js:node -o test ../../test/ThriftTest.thrift'
+        command: '../../compiler/cpp/thrift -gen js:jquery -gen js:node -o test ../../test/v0.16/ThriftTest.thrift'
       },
       ThriftGenDeepConstructor: {
         command: '../../compiler/cpp/thrift -gen js -o test ../../test/JsDeepConstructorTest.thrift'
diff --git a/lib/js/package-lock.json b/lib/js/package-lock.json
index 20f2813..c7c29d0 100644
--- a/lib/js/package-lock.json
+++ b/lib/js/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/lib/js/package.json b/lib/js/package.json
index ff57bf7..b2420bd 100644
--- a/lib/js/package.json
+++ b/lib/js/package.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "description": "Thrift is a software framework for scalable cross-language services development.",
   "main": "./src/thrift",
   "author": {
diff --git a/lib/js/src/thrift.js b/lib/js/src/thrift.js
index 17eb302..3ea1797 100644
--- a/lib/js/src/thrift.js
+++ b/lib/js/src/thrift.js
@@ -46,7 +46,7 @@
      * @const {string} Version
      * @memberof Thrift
      */
-    Version: '0.17.0',
+    Version: '0.18.0',
 
     /**
      * Thrift IDL type string to Id mapping.
diff --git a/lib/js/test/build.xml b/lib/js/test/build.xml
index db85012..e02c154 100644
--- a/lib/js/test/build.xml
+++ b/lib/js/test/build.xml
@@ -162,10 +162,10 @@
 
   <target name="generate">
     <exec executable="${thrift.compiler}" failonerror="true">
-      <arg line="--gen java ${thrift.dir}/test/ThriftTest.thrift" />
+      <arg line="--gen java ${thrift.dir}/test/v0.16/ThriftTest.thrift" />
     </exec>
     <exec executable="${thrift.compiler}" failonerror="true">
-      <arg line="--gen js:jquery ${thrift.dir}/test/ThriftTest.thrift" />
+      <arg line="--gen js:jquery ${thrift.dir}/test/v0.16/ThriftTest.thrift" />
     </exec>
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen js:jquery ${thrift.dir}/test/DoubleConstantsTest.thrift" />
diff --git a/lib/json/schema.json b/lib/json/schema.json
index d058a7c..90bb7a5 100644
--- a/lib/json/schema.json
+++ b/lib/json/schema.json
@@ -22,7 +22,8 @@
         "map",
         "union",
         "struct",
-        "binary"
+        "binary",
+        "uuid"
       ]
     },
     "base-type": {
@@ -30,7 +31,7 @@
       "type": "object",
       "properties": {
         "typeId": {
-          "enum": ["void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "binary" ]
+          "enum": ["void", "string", "bool", "byte", "i8", "i16", "i32", "i64", "double", "binary", "uuid" ]
         }
       },
       "required": [ "typeId" ]
diff --git a/lib/json/test/build.xml b/lib/json/test/build.xml
index eb39c4f..a1f41f1 100644
--- a/lib/json/test/build.xml
+++ b/lib/json/test/build.xml
@@ -70,7 +70,7 @@
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen json"/>
       <arg line="-out ${gen.json.dir}"/>
-      <arg line="${thrift.test.dir}/ThriftTest.thrift"/>
+      <arg line="${thrift.test.dir}/v0.16/ThriftTest.thrift"/>
     </exec>
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen json:merge"/>
diff --git a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
index 4967345..ab415b0 100644
--- a/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
+++ b/lib/kotlin/cross-test-server/src/main/kotlin/org/apache/thrift/test/TestHandler.kt
@@ -19,6 +19,8 @@
 package org.apache.thrift.test
 
 import java.nio.ByteBuffer
+import java.util.*
+import kotlin.collections.HashMap
 import kotlinx.coroutines.delay
 import org.apache.thrift.TException
 import org.slf4j.Logger
@@ -87,6 +89,11 @@
         return buffer.array()
     }
 
+    override suspend fun testUuid(thing: UUID): UUID {
+        logger.info("testUuid($thing)\n")
+        return thing
+    }
+
     override suspend fun testStruct(thing: Xtruct): Xtruct {
         logger.info(
             """testStruct({"${thing.string_thing}", ${thing.byte_thing}, ${thing.i32_thing}, ${thing.i64_thing}})"""
diff --git a/lib/kotlin/src/test/resources/AnnotationTest.thrift b/lib/kotlin/src/test/resources/AnnotationTest.thrift
index 0c4bca2..5ac76e1 100644
--- a/lib/kotlin/src/test/resources/AnnotationTest.thrift
+++ b/lib/kotlin/src/test/resources/AnnotationTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace java org.apache.thrift.kotlin.annotation.test
 
 struct Person {
diff --git a/lib/lua/Thrift.lua b/lib/lua/Thrift.lua
index 252cded..064399c 100644
--- a/lib/lua/Thrift.lua
+++ b/lib/lua/Thrift.lua
@@ -48,7 +48,7 @@
   return count
 end
 
-version = '0.17.0'
+version = '0.18.0'
 
 TType = {
   STOP   = 0,
diff --git a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
index 8c1b6a9..f21aa8b 100644
--- a/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
+++ b/lib/netstd/Tests/Thrift.IntegrationTests/Thrift.IntegrationTests.csproj
@@ -22,7 +22,7 @@
     <TargetFramework>net6.0</TargetFramework>
     <AssemblyName>Thrift.IntegrationTests</AssemblyName>
     <PackageId>Thrift.IntegrationTests</PackageId>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <OutputType>Exe</OutputType>
     <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
     <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift
index 26cb380..a2ed9b7 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/CassandraTest.thrift
@@ -1,11 +1,11 @@
 #!/usr/local/bin/thrift --java --php --py
 # Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
+# or more contributor license agreements. See the NOTICE file
 # distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
+# regarding copyright ownership. The ASF licenses this file
 # to you 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
+# with the License. You may obtain a copy of the License at
 #
 #     http://www.apache.org/licenses/LICENSE-2.0
 #
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
index 42a139c..54970b7 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift.PublicInterfaces.Compile.Tests.csproj
@@ -19,7 +19,7 @@
   -->
 
   <PropertyGroup>
-    <ThriftVersion>0.17.0</ThriftVersion>
+    <ThriftVersion>0.18.0</ThriftVersion>
     <ThriftVersionOutput>Thrift version $(ThriftVersion)</ThriftVersionOutput>
     <TargetFramework>net6.0</TargetFramework>
     <Version>$(ThriftVersion).0</Version>
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5253.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5253.thrift
index 224ac85..9c72137 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5253.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5253.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5253 using Result in result name generates wrong IAsync interface
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.enum.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.enum.thrift
index d4392d6..b97635d 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.enum.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.enum.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.exception.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.exception.thrift
index b6b8cda..37421c0 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.exception.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.exception.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.struct.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.struct.thrift
index 771c487..bae3aa6 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.struct.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.struct.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.thrift
index f677973..3aa06fe 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5320.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5320 Usage of "Task" as IDL identifier generates uncompileable code
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.objs.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.objs.thrift
index 095d7bd..7c0975e 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.objs.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.objs.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5382 Netstd default list/set enums values are generated incorrectly
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.thrift
index db53dfa..0271e00 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/Thrift5382.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5382 Netstd default list/set enums values are generated incorrectly
 
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.enum.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.enum.thrift
index c3ca127..158f469 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.enum.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.enum.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcases for 
 // - THRIFT-5091 Netstd generator produces uncompileable code for struct names ending with "_result" or "_args"
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.thrift
index 959dc3a..03a8d38 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/name_conflicts.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcases for 
 // - THRIFT-5091 Netstd generator produces uncompileable code for struct names ending with "_result" or "_args"
diff --git a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift
index 4a38205..e9e360d 100644
--- a/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift
+++ b/lib/netstd/Tests/Thrift.PublicInterfaces.Compile.Tests/optional_required_default.thrift
@@ -1,18 +1,21 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you 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.
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
 
 // Testcase for THRIFT-5216 generate DeepCopy methods 
 
@@ -36,57 +39,63 @@
     2: optional double             opt_two
     3: optional i16                opt_three
     4: optional string             opt_four
-    5: optional binary             opt_five
+    5: optional uuid               opt_five
     6: optional list<i32>          opt_six
     7: optional set<i64>           opt_seven
     8: optional map<i8,i16>        opt_eight
+	9: optional binary             opt_nine
 
     11: required Distance          req_one
     12: required double            req_two
     13: required i16               req_three
     14: required string            req_four
-    15: required binary            req_five
+    15: required uuid              req_five
     16: required list<i32>         req_six
     17: required set<i64>          req_seven
     18: required map<i8,i16>       req_eight
+    19: required binary            req_nine
     
     21:          Distance          def_one
     22:          double            def_two
     23:          i16               def_three
     24:          string            def_four
-    25:          binary            def_five
+    25:          uuid              def_five
     26:          list<i32>         def_six
     27:          set<i64>          def_seven
     28:          map<i8,i16>       def_eight
-
+	29:          binary            def_nine
+    
     // having default values
     
     31: optional Distance          opt_one_with_value   = Distance.bar
     32: optional double            opt_two_with_value   = 2.22
     33: optional i16               opt_three_with_value = 3
     34: optional string            opt_four_with_value  = "four"
-    35: optional binary            opt_five_with_value  = "five\t"
+    35: optional uuid              opt_five_with_value  = "55555555-5555-5555-5555-000000000000"
     36: optional list<i32>         opt_six_with_value   = [6]
     37: optional set<i64>          opt_seven_with_value = [7]
     38: optional map<i8,i16>       opt_eight_with_value = { 8 : 8 }
-
+	39: optional binary            opt_nine_with_value  = "nine\t"
+    
     41: required Distance          req_one_with_value     = Distance.bar
     42: required double            req_two_with_value     = 2.22
     43: required i16               req_three_with_value = 3
     44: required string            req_four_with_value     = "four"
-    45: required binary            req_five_with_value     = "five"
+    45: required uuid              req_five_with_value  = "55555555-5555-5555-5555-000000000000"
     46: required list<i32>         req_six_with_value     = [6]
     47: required set<i64>          req_seven_with_value = [7]
     48: required map<i8,i16>       req_eight_with_value = { 8 : 8 }
+    49: required binary            req_nine_with_value     = "nine"
     
     51:          Distance          def_one_with_value     = Distance.bar
     52:          double            def_two_with_value     = 2.22
     53:          i16               def_three_with_value = 3
     54:          string            def_four_with_value     = "four"
-    55:          binary            def_five_with_value     = "five"
+    55:          uuid              def_five_with_value  = "55555555-5555-5555-5555-000000000000"
     56:          list<i32>         def_six_with_value     = [6]
     57:          set<i64>          def_seven_with_value = [7]
     58:          map<i8,i16>       def_eight_with_value = { 8 : 8 }
+    59:          binary            def_nine_with_value     = "nine"
     
     90: optional bool              last_of_the_mohicans
 
@@ -124,10 +133,11 @@
     402: optional double             opt_two
     403: optional i16                opt_three
     404: optional string             opt_four
-    405: optional binary             opt_five
+    405: optional uuid               opt_five
     406: optional list<i32>          opt_six
     407: optional set<i64>           opt_seven
     408: optional map<i8,i16>        opt_eight
+    409: optional binary             opt_nine
 }
 
 typedef RaceDetails  RaceDetails2
diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
index afffed5..11b5af4 100644
--- a/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
+++ b/lib/netstd/Tests/Thrift.Tests/DataModel/DeepCopy.cs
@@ -81,16 +81,18 @@
             Assert.IsFalse(instance.__isset.opt_six);
             Assert.IsFalse(instance.__isset.opt_seven);
             Assert.IsFalse(instance.__isset.opt_eight);
+            Assert.IsFalse(instance.__isset.opt_nine);
 
             // set all required to null/default
             instance.Req_one = default;
             instance.Req_two = default;
             instance.Req_three = default;
             Assert.IsNotNull(instance.Req_four);
-            Assert.IsNotNull(instance.Req_five);
-            instance.Req_six = default; 
-            instance.Req_seven = default;;
+            instance.Req_five = default;
+            instance.Req_six = default;
+            instance.Req_seven = default;
             instance.Req_eight = default;
+            Assert.IsNotNull(instance.Req_nine);
 
             // leave non-required fields unset again
             Assert.IsFalse(instance.__isset.def_one);
@@ -101,6 +103,7 @@
             Assert.IsFalse(instance.__isset.def_six);
             Assert.IsFalse(instance.__isset.def_seven);
             Assert.IsFalse(instance.__isset.def_eight);
+            Assert.IsFalse(instance.__isset.def_nine);
 
             // these should have IDL defaults set
 
@@ -112,12 +115,13 @@
             Assert.IsTrue(instance.__isset.opt_six_with_value);
             Assert.IsTrue(instance.__isset.opt_seven_with_value);
             Assert.IsTrue(instance.__isset.opt_eight_with_value);
+            Assert.IsTrue(instance.__isset.opt_nine_with_value);
 
             Assert.AreEqual(instance.Req_one_with_value, (Distance)1);
             Assert.AreEqual(instance.Req_two_with_value, 2.22);
             Assert.AreEqual(instance.Req_three_with_value, 3);
             Assert.AreEqual(instance.Req_four_with_value, "four");
-            Assert.AreEqual("five", Encoding.UTF8.GetString(instance.Req_five_with_value!));
+            Assert.AreEqual(new Guid("55555555-5555-5555-5555-000000000000"), instance.Req_five_with_value);
 
             Assert.IsTrue(instance.Req_six_with_value!.Count == 1);
             Assert.AreEqual(instance.Req_six_with_value[0], 6 );
@@ -128,6 +132,8 @@
             Assert.IsTrue(instance.Req_eight_with_value!.Count == 1);
             Assert.IsTrue(instance.Req_eight_with_value[8] == 8);
 
+            Assert.AreEqual("nine", Encoding.UTF8.GetString(instance.Req_nine_with_value!));
+
             Assert.IsTrue(instance.__isset.def_one_with_value);
             Assert.IsTrue(instance.__isset.def_two_with_value);
             Assert.IsTrue(instance.__isset.def_three_with_value);
@@ -136,6 +142,7 @@
             Assert.IsTrue(instance.__isset.def_six_with_value);
             Assert.IsTrue(instance.__isset.def_seven_with_value);
             Assert.IsTrue(instance.__isset.def_eight_with_value);
+            Assert.IsTrue(instance.__isset.def_nine_with_value);
 
             instance.Last_of_the_mohicans = true;
 
@@ -180,6 +187,7 @@
             instance.Opt_six = ModifyValue(instance.Opt_six);
             instance.Opt_seven = ModifyValue(instance.Opt_seven);
             instance.Opt_eight = ModifyValue(instance.Opt_eight);
+            instance.Opt_nine = ModifyValue(instance.Opt_nine);
 
             instance.Req_one = ModifyValue(instance.Req_one);
             instance.Req_two = ModifyValue(instance.Req_two);
@@ -189,6 +197,7 @@
             instance.Req_six = ModifyValue(instance.Req_six);
             instance.Req_seven = ModifyValue(instance.Req_seven);
             instance.Req_eight = ModifyValue(instance.Req_eight);
+            instance.Req_nine = ModifyValue(instance.Req_nine);
 
             instance.Def_one = ModifyValue(instance.Def_one);
             instance.Def_two = ModifyValue(instance.Def_two);
@@ -198,6 +207,7 @@
             instance.Def_six = ModifyValue(instance.Def_six);
             instance.Def_seven = ModifyValue(instance.Def_seven);
             instance.Def_eight = ModifyValue(instance.Def_eight);
+            instance.Def_nine = ModifyValue(instance.Def_nine);
 
             instance.Opt_one_with_value = ModifyValue(instance.Opt_one_with_value);
             instance.Opt_two_with_value = ModifyValue(instance.Opt_two_with_value);
@@ -207,6 +217,7 @@
             instance.Opt_six_with_value = ModifyValue(instance.Opt_six_with_value);
             instance.Opt_seven_with_value = ModifyValue(instance.Opt_seven_with_value);
             instance.Opt_eight_with_value = ModifyValue(instance.Opt_eight_with_value);
+            instance.Opt_nine_with_value = ModifyValue(instance.Opt_nine_with_value);
 
             instance.Req_one_with_value = ModifyValue(instance.Req_one_with_value);
             instance.Req_two_with_value = ModifyValue(instance.Req_two_with_value);
@@ -216,6 +227,7 @@
             instance.Req_six_with_value = ModifyValue(instance.Req_six_with_value);
             instance.Req_seven_with_value = ModifyValue(instance.Req_seven_with_value);
             instance.Req_eight_with_value = ModifyValue(instance.Req_eight_with_value);
+            instance.Req_nine_with_value = ModifyValue(instance.Req_nine_with_value);
 
             instance.Def_one_with_value = ModifyValue(instance.Def_one_with_value);
             instance.Def_two_with_value = ModifyValue(instance.Def_two_with_value);
@@ -225,6 +237,7 @@
             instance.Def_six_with_value = ModifyValue(instance.Def_six_with_value);
             instance.Def_seven_with_value = ModifyValue(instance.Def_seven_with_value);
             instance.Def_eight_with_value = ModifyValue(instance.Def_eight_with_value);
+            instance.Def_nine_with_value = ModifyValue(instance.Def_nine_with_value);
 
             instance.Last_of_the_mohicans = ModifyValue(instance.Last_of_the_mohicans);
 
@@ -435,6 +448,11 @@
             return value + "1";
         }
 
+        private static Guid ModifyValue(Guid value)
+        {
+            return new Guid( ModifyValue(value.ToByteArray()));
+        }
+
         private static double ModifyValue(double value)
         {
             return value + 1.1;
@@ -461,6 +479,7 @@
             Assert.IsFalse(TCollections.Equals(first.Opt_six, second.Opt_six));
             Assert.IsFalse(TCollections.Equals(first.Opt_seven, second.Opt_seven));
             Assert.IsFalse(TCollections.Equals(first.Opt_eight, second.Opt_eight));
+            Assert.IsFalse(TCollections.Equals(first.Opt_nine, second.Opt_nine));
 
             Assert.AreNotEqual(first.Req_one, second.Req_one);
             Assert.AreNotEqual(first.Req_two, second.Req_two);
@@ -470,6 +489,7 @@
             Assert.IsFalse(TCollections.Equals(first.Req_six, second.Req_six));
             Assert.IsFalse(TCollections.Equals(first.Req_seven, second.Req_seven));
             Assert.IsFalse(TCollections.Equals(first.Req_eight, second.Req_eight));
+            Assert.IsFalse(TCollections.Equals(first.Req_nine, second.Req_nine));
 
             Assert.AreNotEqual(first.Def_one, second.Def_one);
             Assert.AreNotEqual(first.Def_two, second.Def_two);
@@ -479,6 +499,7 @@
             Assert.IsFalse(TCollections.Equals(first.Def_six, second.Def_six));
             Assert.IsFalse(TCollections.Equals(first.Def_seven, second.Def_seven));
             Assert.IsFalse(TCollections.Equals(first.Def_eight, second.Def_eight));
+            Assert.IsFalse(TCollections.Equals(first.Def_nine, second.Def_nine));
 
             Assert.AreNotEqual(first.Opt_one_with_value, second.Opt_one_with_value);
             Assert.AreNotEqual(first.Opt_two_with_value, second.Opt_two_with_value);
@@ -488,6 +509,7 @@
             Assert.IsFalse(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value));
             Assert.IsFalse(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value));
             Assert.IsFalse(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value));
+            Assert.IsFalse(TCollections.Equals(first.Opt_nine_with_value, second.Opt_nine_with_value));
 
             Assert.AreNotEqual(first.Req_one_with_value, second.Req_one_with_value);
             Assert.AreNotEqual(first.Req_two_with_value, second.Req_two_with_value);
@@ -497,6 +519,7 @@
             Assert.IsFalse(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value));
             Assert.IsFalse(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value));
             Assert.IsFalse(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value));
+            Assert.IsFalse(TCollections.Equals(first.Req_nine_with_value, second.Req_nine_with_value));
 
             Assert.AreNotEqual(first.Def_one_with_value, second.Def_one_with_value);
             Assert.AreNotEqual(first.Def_two_with_value, second.Def_two_with_value);
@@ -506,6 +529,7 @@
             Assert.IsFalse(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value));
             Assert.IsFalse(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value));
             Assert.IsFalse(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value));
+            Assert.IsFalse(TCollections.Equals(first.Def_nine_with_value, second.Def_nine_with_value));
 
             Assert.AreNotEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans);
 
@@ -539,6 +563,7 @@
             Assert.IsTrue(TCollections.Equals(first.Opt_six, second.Opt_six));
             Assert.IsTrue(TCollections.Equals(first.Opt_seven, second.Opt_seven));
             Assert.IsTrue(TCollections.Equals(first.Opt_eight, second.Opt_eight));
+            Assert.IsTrue(TCollections.Equals(first.Opt_nine, second.Opt_nine));
 
             Assert.AreEqual(first.Req_one, second.Req_one);
             Assert.AreEqual(first.Req_two, second.Req_two);
@@ -548,6 +573,7 @@
             Assert.IsTrue(TCollections.Equals(first.Req_six, second.Req_six));
             Assert.IsTrue(TCollections.Equals(first.Req_seven, second.Req_seven));
             Assert.IsTrue(TCollections.Equals(first.Req_eight, second.Req_eight));
+            Assert.IsTrue(TCollections.Equals(first.Req_nine, second.Req_nine));
 
             Assert.AreEqual(first.Def_one, second.Def_one);
             Assert.AreEqual(first.Def_two, second.Def_two);
@@ -557,6 +583,7 @@
             Assert.IsTrue(TCollections.Equals(first.Def_six, second.Def_six));
             Assert.IsTrue(TCollections.Equals(first.Def_seven, second.Def_seven));
             Assert.IsTrue(TCollections.Equals(first.Def_eight, second.Def_eight));
+            Assert.IsTrue(TCollections.Equals(first.Def_nine, second.Def_nine));
 
             Assert.AreEqual(first.Opt_one_with_value, second.Opt_one_with_value);
             Assert.AreEqual(first.Opt_two_with_value, second.Opt_two_with_value);
@@ -566,6 +593,7 @@
             Assert.IsTrue(TCollections.Equals(first.Opt_six_with_value, second.Opt_six_with_value));
             Assert.IsTrue(TCollections.Equals(first.Opt_seven_with_value, second.Opt_seven_with_value));
             Assert.IsTrue(TCollections.Equals(first.Opt_eight_with_value, second.Opt_eight_with_value));
+            Assert.IsTrue(TCollections.Equals(first.Opt_nine_with_value, second.Opt_nine_with_value));
 
             Assert.AreEqual(first.Req_one_with_value, second.Req_one_with_value);
             Assert.AreEqual(first.Req_two_with_value, second.Req_two_with_value);
@@ -575,6 +603,7 @@
             Assert.IsTrue(TCollections.Equals(first.Req_six_with_value, second.Req_six_with_value));
             Assert.IsTrue(TCollections.Equals(first.Req_seven_with_value, second.Req_seven_with_value));
             Assert.IsTrue(TCollections.Equals(first.Req_eight_with_value, second.Req_eight_with_value));
+            Assert.IsTrue(TCollections.Equals(first.Req_nine_with_value, second.Req_nine_with_value));
 
             Assert.AreEqual(first.Def_one_with_value, second.Def_one_with_value);
             Assert.AreEqual(first.Def_two_with_value, second.Def_two_with_value);
@@ -584,6 +613,7 @@
             Assert.IsTrue(TCollections.Equals(first.Def_six_with_value, second.Def_six_with_value));
             Assert.IsTrue(TCollections.Equals(first.Def_seven_with_value, second.Def_seven_with_value));
             Assert.IsTrue(TCollections.Equals(first.Def_eight_with_value, second.Def_eight_with_value));
+            Assert.IsTrue(TCollections.Equals(first.Def_nine_with_value, second.Def_nine_with_value));
 
             Assert.AreEqual(first.Last_of_the_mohicans, second.Last_of_the_mohicans);
 
diff --git a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
index ebc1717..80eacc2 100644
--- a/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
+++ b/lib/netstd/Tests/Thrift.Tests/DataModel/NullValuesSet.cs
@@ -48,19 +48,19 @@
             Assert.IsNull(instance.Def_four);
             Assert.IsNull(instance.Opt_four);
 
-            // byte[]
-            Assert.IsTrue(instance.__isset.def_five);
-            Assert.IsTrue(instance.__isset.opt_five);
-            Assert.IsTrue((instance.Req_five == null) || (instance.Req_five.Length == 0));
-            Assert.IsNull(instance.Def_five);
-            Assert.IsNull(instance.Opt_five);
-
             // list<>
             Assert.IsTrue(instance.__isset.def_six);
             Assert.IsTrue(instance.__isset.opt_six);
             Assert.IsNull(instance.Req_six);
             Assert.IsNull(instance.Opt_six);
             Assert.IsNull(instance.Def_six);
+
+            // byte[]
+            Assert.IsTrue(instance.__isset.def_nine);
+            Assert.IsTrue(instance.__isset.opt_nine);
+            Assert.IsTrue((instance.Req_nine == null) || (instance.Req_nine.Length == 0));
+            Assert.IsNull(instance.Def_nine);
+            Assert.IsNull(instance.Opt_nine);
         }
 
         [TestMethod]
@@ -80,27 +80,27 @@
             instance.Def_four = null;
             instance.Opt_four = null;
 
-            // byte[]
-            instance.Req_five = null;
-            instance.Def_five = null;
-            instance.Opt_five = null;
-
             // list<>
             instance.Req_six = null;
             instance.Opt_six = null;
             instance.Def_six = null;
 
+            // byte[]
+            instance.Req_nine = null;
+            instance.Def_nine = null;
+            instance.Opt_nine = null;
+
             // back to normal
             #pragma warning restore CS8625
 
             // test the setup
             CheckInstance(instance);
 
-            // validate proper null checks , any of these throws if not
+            // validate proper null checks, any of these throws if not
             instance.ToString();
             instance.GetHashCode();
 
-            // validate proper null checks , any of these throws if not
+            // validate proper null checks, any of these throws if not
             var copy = instance.DeepCopy();
             CheckInstance(copy);
         }
diff --git a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
index 27edf7b..efd21f8 100644
--- a/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
+++ b/lib/netstd/Tests/Thrift.Tests/Thrift.Tests.csproj
@@ -20,7 +20,7 @@
 
   <PropertyGroup>
     <TargetFramework>net6.0</TargetFramework>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <Nullable>enable</Nullable>
   </PropertyGroup>
 
diff --git a/lib/netstd/Thrift/Properties/AssemblyInfo.cs b/lib/netstd/Thrift/Properties/AssemblyInfo.cs
index 5aa368f..6978f52 100644
--- a/lib/netstd/Thrift/Properties/AssemblyInfo.cs
+++ b/lib/netstd/Thrift/Properties/AssemblyInfo.cs
@@ -52,5 +52,5 @@
 // You can specify all the values or you can default the Build and Revision Numbers
 // by using the '*' as shown below:
 
-[assembly: AssemblyVersion("0.17.0.0")]
-[assembly: AssemblyFileVersion("0.17.0.0")]
+[assembly: AssemblyVersion("0.18.0.0")]
+[assembly: AssemblyFileVersion("0.18.0.0")]
diff --git a/lib/netstd/Thrift/Protocol/Entities/TType.cs b/lib/netstd/Thrift/Protocol/Entities/TType.cs
index 4e922a7..2f3037b 100644
--- a/lib/netstd/Thrift/Protocol/Entities/TType.cs
+++ b/lib/netstd/Thrift/Protocol/Entities/TType.cs
@@ -32,6 +32,7 @@
         Struct = 12,
         Map = 13,
         Set = 14,
-        List = 15
+        List = 15,
+        Uuid = 16
     }
-}
\ No newline at end of file
+}
diff --git a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
index eee137c..7feb698 100644
--- a/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TBinaryProtocol.cs
@@ -21,6 +21,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using Thrift.Protocol.Entities;
+using Thrift.Protocol.Utilities;
 using Thrift.Transport;
 
 
@@ -209,6 +210,14 @@
             await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
         }
 
+        public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var bytes = uuid.SwapByteOrder().ToByteArray();
+            await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+        }
+
         public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -244,6 +253,7 @@
         public override Task ReadMessageEndAsync(CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
+            Transport.ResetConsumedMessageSize();
             return Task.CompletedTask;
         }
 
@@ -401,6 +411,16 @@
             return buf;
         }
 
+        public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            Transport.CheckReadBytesAvailable(16);  // = sizeof(uuid)
+            var buf = new byte[16];
+            await Trans.ReadAllAsync(buf, 0, 16, cancellationToken);
+            return new Guid(buf).SwapByteOrder();
+        }
+
         public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -443,6 +463,7 @@
                 case TType.Map: return sizeof(int);  // element count
                 case TType.Set: return sizeof(int);  // element count
                 case TType.List: return sizeof(int);  // element count
+                case TType.Uuid: return 16;  // uuid bytes
                 default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
diff --git a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
index 6893ad4..dd38f48 100644
--- a/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TCompactProtocol.cs
@@ -24,6 +24,7 @@
 using System.Threading;
 using System.Threading.Tasks;
 using Thrift.Protocol.Entities;
+using Thrift.Protocol.Utilities;
 using Thrift.Transport;
 
 
@@ -43,8 +44,8 @@
         private const byte NoTypeOverride = 0xFF;
 
         // ReSharper disable once InconsistentNaming
-        private static readonly byte[] TTypeToCompactType = new byte[16];
-        private static readonly TType[] CompactTypeToTType = new TType[13];
+        private static readonly byte[] TTypeToCompactType = new byte[17];
+        private static readonly TType[] CompactTypeToTType = new TType[14];
 
         /// <summary>
         ///     Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
@@ -86,18 +87,19 @@
         public TCompactProtocol(TTransport trans)
             : base(trans)
         {
-            TTypeToCompactType[(int) TType.Stop] = Types.Stop;
-            TTypeToCompactType[(int) TType.Bool] = Types.BooleanTrue;
-            TTypeToCompactType[(int) TType.Byte] = Types.Byte;
-            TTypeToCompactType[(int) TType.I16] = Types.I16;
-            TTypeToCompactType[(int) TType.I32] = Types.I32;
-            TTypeToCompactType[(int) TType.I64] = Types.I64;
-            TTypeToCompactType[(int) TType.Double] = Types.Double;
-            TTypeToCompactType[(int) TType.String] = Types.Binary;
-            TTypeToCompactType[(int) TType.List] = Types.List;
-            TTypeToCompactType[(int) TType.Set] = Types.Set;
-            TTypeToCompactType[(int) TType.Map] = Types.Map;
-            TTypeToCompactType[(int) TType.Struct] = Types.Struct;
+            TTypeToCompactType[(int)TType.Stop] = Types.Stop;
+            TTypeToCompactType[(int)TType.Bool] = Types.BooleanTrue;
+            TTypeToCompactType[(int)TType.Byte] = Types.Byte;
+            TTypeToCompactType[(int)TType.I16] = Types.I16;
+            TTypeToCompactType[(int)TType.I32] = Types.I32;
+            TTypeToCompactType[(int)TType.I64] = Types.I64;
+            TTypeToCompactType[(int)TType.Double] = Types.Double;
+            TTypeToCompactType[(int)TType.String] = Types.Binary;
+            TTypeToCompactType[(int)TType.List] = Types.List;
+            TTypeToCompactType[(int)TType.Set] = Types.Set;
+            TTypeToCompactType[(int)TType.Map] = Types.Map;
+            TTypeToCompactType[(int)TType.Struct] = Types.Struct;
+            TTypeToCompactType[(int)TType.Uuid] = Types.Uuid;
 
             CompactTypeToTType[Types.Stop] = TType.Stop;
             CompactTypeToTType[Types.BooleanTrue] = TType.Bool;
@@ -112,6 +114,7 @@
             CompactTypeToTType[Types.Set] = TType.Set;
             CompactTypeToTType[Types.Map] = TType.Map;
             CompactTypeToTType[Types.Struct] = TType.Struct;
+            CompactTypeToTType[Types.Uuid] = TType.Uuid;
         }
 
         public void Reset()
@@ -395,6 +398,14 @@
             await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
         }
 
+        public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            var bytes = uuid.SwapByteOrder().ToByteArray();
+            await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
+        }
+
         public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -448,6 +459,7 @@
         public override Task ReadMessageEndAsync(CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
+            Transport.ResetConsumedMessageSize();
             return Task.CompletedTask;
         }
 
@@ -665,6 +677,16 @@
             return buf;
         }
 
+        public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
+        {
+            cancellationToken.ThrowIfCancellationRequested();
+
+            Transport.CheckReadBytesAvailable(16);  // = sizeof(uuid)
+            var buf = new byte[16];
+            await Trans.ReadAllAsync(buf, 0, 16, cancellationToken);
+            return new Guid(buf).SwapByteOrder();
+        }
+
         public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
         {
             cancellationToken.ThrowIfCancellationRequested();
@@ -792,19 +814,20 @@
         {
             switch (type)
             {
-                case TType.Stop:    return 0;
-                case TType.Void:    return 0;
-                case TType.Bool:   return sizeof(byte);
+                case TType.Stop: return 0;
+                case TType.Void: return 0;
+                case TType.Bool: return sizeof(byte);
                 case TType.Double: return 8;  // uses fixedLongToBytes() which always writes 8 bytes
                 case TType.Byte: return sizeof(byte);
-                case TType.I16:     return sizeof(byte);  // zigzag
-                case TType.I32:     return sizeof(byte);  // zigzag
-                case TType.I64:     return sizeof(byte);  // zigzag
+                case TType.I16: return sizeof(byte);  // zigzag
+                case TType.I32: return sizeof(byte);  // zigzag
+                case TType.I64: return sizeof(byte);  // zigzag
                 case TType.String: return sizeof(byte);  // string length
-                case TType.Struct:  return 0;             // empty struct
-                case TType.Map:     return sizeof(byte);  // element count
-                case TType.Set:    return sizeof(byte);  // element count
-                case TType.List:    return sizeof(byte);  // element count
+                case TType.Struct: return 0;             // empty struct
+                case TType.Map: return sizeof(byte);  // element count
+                case TType.Set: return sizeof(byte);  // element count
+                case TType.List: return sizeof(byte);  // element count
+                case TType.Uuid: return 16;  // uuid bytes
                 default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
@@ -835,6 +858,7 @@
             public const byte Set = 0x0A;
             public const byte Map = 0x0B;
             public const byte Struct = 0x0C;
+            public const byte Uuid = 0x0D;
         }
     }
 }
diff --git a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
index 8799026..82e758b 100644
--- a/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TJSONProtocol.cs
@@ -401,6 +401,10 @@
         {
             await WriteJsonBase64Async(bytes, cancellationToken);
         }
+        public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken = default)
+        {
+            await WriteStringAsync(uuid.ToString("D"), cancellationToken);  // no curly braces
+        }
 
         /// <summary>
         ///     Read in a JSON string, unescaping as appropriate.. Skip Reading from the
@@ -690,7 +694,9 @@
 
         public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
         {
+            cancellationToken.ThrowIfCancellationRequested();
             await ReadJsonArrayEndAsync(cancellationToken);
+            Transport.ResetConsumedMessageSize();
         }
 
         public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
@@ -817,6 +823,11 @@
             return await ReadJsonBase64Async(cancellationToken);
         }
 
+        public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken = default)
+        {
+            return new Guid( await ReadStringAsync(cancellationToken));
+        }
+
         // Return the minimum number of bytes a type will consume on the wire
         public override int GetMinSerializedSize(TType type)
         {
@@ -835,6 +846,7 @@
                 case TType.Map: return 2;  // empty map
                 case TType.Set: return 2;  // empty set
                 case TType.List: return 2;  // empty list
+                case TType.Uuid: return 36;  // "E236974D-F0B0-4E05-8F29-0B455D41B1A1"
                 default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
             }
         }
diff --git a/lib/netstd/Thrift/Protocol/TProtocol.cs b/lib/netstd/Thrift/Protocol/TProtocol.cs
index cd93833..f2bec60 100644
--- a/lib/netstd/Thrift/Protocol/TProtocol.cs
+++ b/lib/netstd/Thrift/Protocol/TProtocol.cs
@@ -148,6 +148,7 @@
         }
 
         public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken = default);
+        public abstract Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken = default);
 
         public abstract ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken = default);
 
@@ -192,5 +193,7 @@
         }
 
         public abstract ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken = default);
+
+        public abstract ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken = default);
     }
 }
diff --git a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
index b032e83..c75cc63 100644
--- a/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
+++ b/lib/netstd/Thrift/Protocol/TProtocolDecorator.cs
@@ -144,6 +144,11 @@
             await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken);
         }
 
+        public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
+        {
+            await _wrappedProtocol.WriteUuidAsync(uuid, cancellationToken);
+        }
+
         public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
         {
             return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken);
@@ -151,7 +156,9 @@
 
         public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
         {
+            cancellationToken.ThrowIfCancellationRequested();
             await _wrappedProtocol.ReadMessageEndAsync(cancellationToken);
+            Transport.ResetConsumedMessageSize();
         }
 
         public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
@@ -244,6 +251,11 @@
             return await _wrappedProtocol.ReadBinaryAsync(cancellationToken);
         }
 
+        public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
+        {
+            return await _wrappedProtocol.ReadUuidAsync(cancellationToken);
+        }
+
         // Returns the minimum amount of bytes needed to store the smallest possible instance of TType.
         public override int GetMinSerializedSize(TType type)
         {
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs b/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs
new file mode 100644
index 0000000..190ddbb
--- /dev/null
+++ b/lib/netstd/Thrift/Protocol/Utilities/TGuidExtensions.cs
@@ -0,0 +1,82 @@
+// Licensed to the Apache Software Foundation(ASF) under one
+// or more contributor license agreements.See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.The ASF licenses this file
+// to you 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.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+
+namespace Thrift.Protocol.Utilities
+{
+    public static class TGuidExtensions
+    {
+        public static Guid SwapByteOrder(this Guid self)
+        {
+            var bytes = self.ToByteArray();
+
+            // already network order on BigEndian machines
+            if (BitConverter.IsLittleEndian)
+            {
+                SwapBytes(ref bytes[0], ref bytes[3]);
+                SwapBytes(ref bytes[1], ref bytes[2]);
+                SwapBytes(ref bytes[4], ref bytes[5]);
+                SwapBytes(ref bytes[6], ref bytes[7]);
+            }
+
+            return new Guid(bytes);
+        }
+
+        private static void SwapBytes(ref byte one, ref byte two)
+        {
+            var tmp = one;
+            one = two;
+            two = tmp;
+        }
+
+        #region SelfTest
+#if DEBUG
+        static private readonly Guid TEST_GUID = new Guid("{00112233-4455-6677-8899-aabbccddeeff}");
+
+        static TGuidExtensions()
+        {
+            SelfTest();
+        }
+
+        private static void SelfTest()
+        {
+            // host to network
+            var guid = TEST_GUID;
+            guid = guid.SwapByteOrder();
+
+            // validate network order
+            var bytes = guid.ToByteArray();
+            for (var i = 0; i < 10; ++i)
+            {
+                var expected = i * 0x11;
+                Debug.Assert( bytes[i] == expected);
+            }
+
+            // network to host and final validation
+            guid = guid.SwapByteOrder();
+            Debug.Assert(guid.Equals(TEST_GUID));
+        }
+
+#endif
+        #endregion
+
+    }
+}
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs
index 6cc1302..f8c261a 100644
--- a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs
+++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolConstants.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -56,6 +56,7 @@
             public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' };
             public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' };
             public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' };
+            public static readonly byte[] NameUuid = { (byte)'u', (byte)'i', (byte)'d' };
         }
     }
-}
\ No newline at end of file
+}
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs
index ff49ebe..67c7bc0 100644
--- a/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs
+++ b/lib/netstd/Thrift/Protocol/Utilities/TJsonProtocolHelper.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -48,6 +48,8 @@
                     return TJSONProtocolConstants.TypeNames.NameSet;
                 case TType.List:
                     return TJSONProtocolConstants.TypeNames.NameList;
+                case TType.Uuid:
+                    return TJSONProtocolConstants.TypeNames.NameUuid;
                 default:
                     throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
             }
@@ -102,6 +104,9 @@
                     case (byte) 't':
                         result = TType.Bool;
                         break;
+                    case (byte)'u':
+                        result = TType.Uuid;
+                        break;
                 }
             }
             if (result == TType.Stop)
@@ -173,4 +178,4 @@
             return (byte)((char)val + 'a');
         }
     }
-}
\ No newline at end of file
+}
diff --git a/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs
index 832e46e..3c8b37a 100644
--- a/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs
+++ b/lib/netstd/Thrift/Protocol/Utilities/TProtocolUtil.cs
@@ -55,6 +55,9 @@
                         // Don't try to decode the string, just skip it.
                         await protocol.ReadBinaryAsync(cancellationToken);
                         break;
+                    case TType.Uuid:
+                        await protocol.ReadUuidAsync(cancellationToken);
+                        break;
                     case TType.Struct:
                         await protocol.ReadStructBeginAsync(cancellationToken);
                         while (true)
diff --git a/lib/netstd/Thrift/Thrift.csproj b/lib/netstd/Thrift/Thrift.csproj
index 69ddbc2..902e3db 100644
--- a/lib/netstd/Thrift/Thrift.csproj
+++ b/lib/netstd/Thrift/Thrift.csproj
@@ -40,8 +40,8 @@
     <SignAssembly>true</SignAssembly>
     <AssemblyOriginatorKeyFile>thrift.snk</AssemblyOriginatorKeyFile>
     <DelaySign>false</DelaySign>
-    <Title>Apache Thrift 0.17.0</Title>
-    <Version>0.17.0.0</Version>
+    <Title>Apache Thrift 0.18.0</Title>
+    <Version>0.18.0.0</Version>
     <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
     <PackageProjectUrl>http://thrift.apache.org/</PackageProjectUrl>
     <Authors>Apache Thrift Developers</Authors>
@@ -50,7 +50,7 @@
     <PackageDescription>C# .NET Core bindings for the Apache Thrift RPC system</PackageDescription>
     <PackageReleaseNotes></PackageReleaseNotes>
     <PackageTags>Apache Thrift RPC</PackageTags>
-    <PackageReleaseNotes>https://github.com/apache/thrift/blob/0.17.0/CHANGES.md</PackageReleaseNotes>
+    <PackageReleaseNotes>https://github.com/apache/thrift/blob/0.18.0/CHANGES.md</PackageReleaseNotes>
     <Copyright>Copyright 2022 The Apache Software Foundation</Copyright>
   </PropertyGroup>
 
diff --git a/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs b/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
index c57db9d..071c660 100644
--- a/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/TNamedPipeTransport.cs
@@ -28,7 +28,7 @@
     {
         private NamedPipeClientStream PipeStream;
         private readonly int ConnectTimeout;
-		private const int DEFAULT_CONNECT_TIMEOUT = 60 * 1000;   // Timeout.Infinite is not a good default
+        private const int DEFAULT_CONNECT_TIMEOUT = 60 * 1000;   // Timeout.Infinite is not a good default
 
         public TNamedPipeTransport(string pipe, TConfiguration config, int timeout = DEFAULT_CONNECT_TIMEOUT) 
             : this(".", pipe, config, timeout)
@@ -61,6 +61,8 @@
         {
             if (PipeStream != null)
             {
+                if (PipeStream.IsConnected)
+                    PipeStream.Close();
                 PipeStream.Dispose();
                 PipeStream = null;
             }
@@ -107,20 +109,24 @@
             }
         }
 
-        public override Task FlushAsync(CancellationToken cancellationToken)
+        public override async Task FlushAsync(CancellationToken cancellationToken)
         {
-            cancellationToken.ThrowIfCancellationRequested();
-
+            await PipeStream.FlushAsync(cancellationToken);
             ResetConsumedMessageSize();
-            return Task.CompletedTask;
         }
 
         
         protected override void Dispose(bool disposing)
         {
-            if(disposing) 
+            if (disposing)
             {
-              PipeStream?.Dispose();
+                if (PipeStream != null)
+                {
+                    if (PipeStream.IsConnected)
+                        PipeStream.Close();
+                    PipeStream.Dispose();
+                    PipeStream = null;
+                }
             }
         }
     }
diff --git a/lib/netstd/Thrift/Transport/Client/TSocketTransport.cs b/lib/netstd/Thrift/Transport/Client/TSocketTransport.cs
index 5e3245b..f3e87d4 100644
--- a/lib/netstd/Thrift/Transport/Client/TSocketTransport.cs
+++ b/lib/netstd/Thrift/Transport/Client/TSocketTransport.cs
@@ -18,7 +18,6 @@
 using System;
 using System.Net;
 using System.Net.Sockets;
-using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 
@@ -37,6 +36,16 @@
             SetInputOutputStream();
         }
 
+        /// <summary>
+        /// The constructor for a TSocketTransport which takes an IPAddress object.
+        /// </summary>
+        /// <param name="host">The IP address.</param>
+        /// <param name="port">The TcpClient port number.</param>
+        /// <param name="config">The <see cref="TConfiguration"/>.</param>
+        /// <param name="timeout">The TcpClient send timeout.</param>
+        /// <remarks>
+        /// The TcpClient is not connected automatically.  You are required to use <see cref="OpenAsync(CancellationToken)"/>.
+        /// </remarks>
         public TSocketTransport(IPAddress host, int port, TConfiguration config, int timeout = 0)
             : base(config)
         {
@@ -46,9 +55,22 @@
             TcpClient = new TcpClient();
             TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
             TcpClient.Client.NoDelay = true;
+
             SetInputOutputStream();
         }
 
+        /// <summary>
+        /// The constructor for a TSocketTransport which takes either a host name, e.g. 'host.example.com' and port number.
+        /// If host is not found using Dns.GetHostEntry(host) an exception will be thrown.
+        /// </summary>
+        /// <param name="host">The host name.</param>
+        /// <param name="port">The TcpClient port number.</param>
+        /// <param name="config">The <see cref="TConfiguration"/>.</param>
+        /// <param name="timeout">The TcpClient send timeout.</param>
+        /// <exception cref="TTransportException"></exception>
+        /// <remarks>
+        /// The TcpClient is connected automatically.
+        /// </remarks>
         public TSocketTransport(string host, int port, TConfiguration config, int timeout = 0)
             : base(config)
         {
@@ -64,6 +86,57 @@
                 TcpClient = new TcpClient(host, port);
                 TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
                 TcpClient.Client.NoDelay = true;
+
+                SetInputOutputStream();
+            }
+            catch (SocketException e)
+            {
+                throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e);
+            }
+        }
+
+        /// <summary>
+        /// <para>The constructor for a TSocketTransport which takes either a host name, e.g. 'host.example.com' or and IP address string, e.g '123.456.789' and port number.
+        /// If hostNameOrIpAddress represents a valid IP address this will be used directly.
+        /// If hostNameOrIpAddress does not represent a valid IP address an IP address will be retrieved using Dns.GetHostEntry(hostNameOrIpAddress).
+        /// If that fails an exception will be thrown.</para>
+        /// </summary>
+        /// <param name="hostNameOrIpAddress">The host name or IP address.</param>
+        /// <param name="port">The TcpClient port number.</param>
+        /// <param name="connectClient">If true attempt to connect the TcpClient.</param>
+        /// <param name="config">The <see cref="TConfiguration"/>.</param>
+        /// <param name="timeout">The TcpClient send timeout.</param>
+        /// <exception cref="TTransportException"></exception>
+        /// <remarks>
+        /// The TcpClient is connected dependent on the value of <paramref name="connectClient"/>./>.
+        /// </remarks>
+        public TSocketTransport(string hostNameOrIpAddress, int port, bool connectClient, TConfiguration config, int timeout = 0)
+            : base(config)
+        {
+            try
+            {
+                if (!IPAddress.TryParse(hostNameOrIpAddress, out var address))
+                {
+                    var entry = Dns.GetHostEntry(hostNameOrIpAddress);
+
+                    if (entry.AddressList.Length == 0)
+                        throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name");
+
+                    address = entry.AddressList[0];
+                }
+
+                Host = address;
+                Port = port;
+
+                TcpClient = new TcpClient();
+                TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
+                TcpClient.Client.NoDelay = true;
+
+                if (connectClient)
+                {
+                    TcpClient.Connect(Host, Port);
+                }
+
                 SetInputOutputStream();
             }
             catch (SocketException e)
diff --git a/lib/netstd/Thrift/Transport/Layered/TBufferedTransport.cs b/lib/netstd/Thrift/Transport/Layered/TBufferedTransport.cs
index 271a994..7474b7f 100644
--- a/lib/netstd/Thrift/Transport/Layered/TBufferedTransport.cs
+++ b/lib/netstd/Thrift/Transport/Layered/TBufferedTransport.cs
@@ -179,6 +179,11 @@
             }
         }
 
+        public override void ResetConsumedMessageSize(long newSize = -1)
+        {
+            base.ResetConsumedMessageSize(newSize);
+            ReadBuffer.ResetConsumedMessageSize(newSize);
+        }
 
         private void CheckNotDisposed()
         {
diff --git a/lib/netstd/Thrift/Transport/Layered/TFramedTransport.cs b/lib/netstd/Thrift/Transport/Layered/TFramedTransport.cs
index 722df76..694ea0f 100644
--- a/lib/netstd/Thrift/Transport/Layered/TFramedTransport.cs
+++ b/lib/netstd/Thrift/Transport/Layered/TFramedTransport.cs
@@ -186,5 +186,11 @@
             }
             IsDisposed = true;
         }
+
+        public override void ResetConsumedMessageSize(long newSize = -1)
+        {
+            base.ResetConsumedMessageSize(newSize);
+            ReadBuffer.ResetConsumedMessageSize(newSize);
+        }
     }
 }
diff --git a/lib/netstd/Thrift/Transport/Layered/TLayeredTransport.cs b/lib/netstd/Thrift/Transport/Layered/TLayeredTransport.cs
index 4d39b39..98fbd22 100644
--- a/lib/netstd/Thrift/Transport/Layered/TLayeredTransport.cs
+++ b/lib/netstd/Thrift/Transport/Layered/TLayeredTransport.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -41,5 +41,10 @@
         {
             InnerTransport.CheckReadBytesAvailable(numBytes);
         }
+
+        public override void ResetConsumedMessageSize(long newSize = -1)
+        {
+            InnerTransport.ResetConsumedMessageSize(newSize);
+        }
     }
 }
diff --git a/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs b/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
index e985a29..8ad62aa 100644
--- a/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
+++ b/lib/netstd/Thrift/Transport/Server/TNamedPipeServerTransport.cs
@@ -24,41 +24,78 @@
 using System.ComponentModel;
 using System.Security.AccessControl;
 using System.Security.Principal;
+using System.Collections.Generic;
+using System.IO;
+using System.Diagnostics;
+
+#pragma warning disable CS1998  // async no await
 
 namespace Thrift.Transport.Server
 {
+    [Obsolete("NamedPipeClientFlags is deprecated, use NamedPipeServerFlags instead.")]
     [Flags]
-    public enum NamedPipeClientFlags {
+    public enum NamedPipeClientFlags {  // bad name
         None = 0x00,
         OnlyLocalClients = 0x01
     };
 
+    [Flags]
+    public enum NamedPipeServerFlags
+    {
+        None = 0x00,
+        OnlyLocalClients = 0x01,
+    };
+
+
     // ReSharper disable once InconsistentNaming
     public class TNamedPipeServerTransport : TServerTransport
     {
+        // to manage incoming connections, we set up a task for each stream to listen on
+        private struct TaskStreamPair
+        {
+            public NamedPipeServerStream Stream;
+            public Task Task;
+
+            public TaskStreamPair(NamedPipeServerStream stream, Task task)
+            {
+                Stream = stream;
+                Task = task;    
+            }
+        }
+
         /// <summary>
         ///     This is the address of the Pipe on the localhost.
         /// </summary>
         private readonly string _pipeAddress;
         private bool _asyncMode = true;
         private volatile bool _isPending = true;
-        private NamedPipeServerStream _stream = null;
+        private readonly List<TaskStreamPair> _streams = new List<TaskStreamPair>();
         private readonly bool _onlyLocalClients = false;  // compatibility default
+        private readonly byte _numListenPipes = 1;  // compatibility default
 
-        public TNamedPipeServerTransport(string pipeAddress, TConfiguration config, NamedPipeClientFlags flags)
+        public TNamedPipeServerTransport(string pipeAddress, TConfiguration config, NamedPipeServerFlags flags, int numListenPipes)
             : base(config)
         {
+            if ((numListenPipes < 1) || (numListenPipes > 254))
+                throw new ArgumentOutOfRangeException(nameof(numListenPipes), "Value must be in the range of [1..254]");
+
+            _pipeAddress = pipeAddress;
+            _onlyLocalClients = flags.HasFlag(NamedPipeServerFlags.OnlyLocalClients);
+            _numListenPipes = (byte)numListenPipes;
+        }
+
+        [Obsolete("NamedPipeClientFlags is deprecated, use NamedPipeServerFlags instead.")]
+        public TNamedPipeServerTransport(string pipeAddress, TConfiguration config, NamedPipeClientFlags flags, int numListenPipes = 1)
+            : base(config)
+        {
+            if ((numListenPipes < 1) || (numListenPipes > 254))
+                throw new ArgumentOutOfRangeException(nameof(numListenPipes), "Value must be in the range of [1..254]");
+
             _pipeAddress = pipeAddress;
             _onlyLocalClients = flags.HasFlag(NamedPipeClientFlags.OnlyLocalClients);
+            _numListenPipes = (byte)numListenPipes;
         }
 
-        [Obsolete("This CTOR is deprecated, please use the other one instead.")]
-        public TNamedPipeServerTransport(string pipeAddress, TConfiguration config)
-            : base(config)
-        {
-            _pipeAddress = pipeAddress;
-            _onlyLocalClients = false;
-        }
 
         public override bool IsOpen() {
             return true;
@@ -69,75 +106,112 @@
             // nothing to do here
         }
 
-        public override void Close()
+        private static void Close(NamedPipeServerStream pipe)
         {
-            if (_stream != null)
+            if (pipe != null)
             {
                 try
                 {
-                    if (_stream.IsConnected)
-                        _stream.Disconnect();
-                    _stream.Dispose();
+                    if (pipe.IsConnected)
+                        pipe.Disconnect();
                 }
                 finally
                 {
-                    _stream = null;
-                    _isPending = false;
+                    pipe.Dispose();
                 }
             }
         }
 
+        public override void Close()
+        {
+            try
+            {
+                if (_streams != null)
+                {
+                    while(_streams.Count > 0)
+                    {
+                        Close(_streams[0].Stream);
+                        _streams.RemoveAt(0);
+                    }
+                }
+            }
+            finally
+            {
+                _streams.Clear();
+                _isPending = false;
+            }
+        }
+
         public override bool IsClientPending()
         {
             return _isPending;
         }
 
-        private void EnsurePipeInstance()
+        private void EnsurePipeInstances()
         {
-            if (_stream == null)
+            // set up a pool for accepting multiple calls when in multithread mode
+            // once connected, we hand that stream over to the processor and create a fresh one
+            try
             {
-                const PipeDirection direction = PipeDirection.InOut;
-                const int maxconn = NamedPipeServerStream.MaxAllowedServerInstances;
-                const PipeTransmissionMode mode = PipeTransmissionMode.Byte;
-                const int inbuf = 4096;
-                const int outbuf = 4096;
-                var options = _asyncMode ? PipeOptions.Asynchronous : PipeOptions.None;
+                while (_streams.Count < _numListenPipes)
+                    _streams.Add(CreatePipeInstance());
+            }
+            catch
+            {
+                // we might not be able to create all requested instances, e.g. due to some existing instances already processing calls
+                // if we have at least one pipe to listen on -> Good Enough(tm) 
+                if (_streams.Count < 1)
+                    throw;  // no pipes is really bad
+            }
+        }
+
+        private TaskStreamPair CreatePipeInstance()
+        {
+            const PipeDirection direction = PipeDirection.InOut;
+            const int maxconn = NamedPipeServerStream.MaxAllowedServerInstances;
+            const PipeTransmissionMode mode = PipeTransmissionMode.Byte;
+            const int inbuf = 4096;
+            const int outbuf = 4096;
+            var options = _asyncMode ? PipeOptions.Asynchronous : PipeOptions.None;
 
 
-                // TODO: "CreatePipeNative" ist only a workaround, and there are have basically two possible outcomes:
-                // - once NamedPipeServerStream() gets a CTOR that supports pipesec, remove CreatePipeNative()
-                // - if 31190 gets resolved before, use _stream.SetAccessControl(pipesec) instead of CreatePipeNative()
-                // EITHER WAY,
-                // - if CreatePipeNative() finally gets removed, also remove "allow unsafe code" from the project settings
+            // TODO: "CreatePipeNative" ist only a workaround, and there are have basically two possible outcomes:
+            // - once NamedPipeServerStream() gets a CTOR that supports pipesec, remove CreatePipeNative()
+            // - if 31190 gets resolved before, use _stream.SetAccessControl(pipesec) instead of CreatePipeNative()
+            // EITHER WAY,
+            // - if CreatePipeNative() finally gets removed, also remove "allow unsafe code" from the project settings
 
-                try
+            NamedPipeServerStream instance;
+            try
+            {
+                var handle = CreatePipeNative(_pipeAddress, inbuf, outbuf, _onlyLocalClients);
+                if ((handle != null) && (!handle.IsInvalid))
                 {
-                    var handle = CreatePipeNative(_pipeAddress, inbuf, outbuf, _onlyLocalClients);
-                    if ((handle != null) && (!handle.IsInvalid))
-                    {
-                        _stream = new NamedPipeServerStream(PipeDirection.InOut, _asyncMode, false, handle);
-                        handle = null; // we don't own it any longer
-                    }
-                    else
-                    {
-                        handle?.Dispose();
-                        _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf/*, pipesec*/);
-                    }
+                    instance = new NamedPipeServerStream(PipeDirection.InOut, _asyncMode, false, handle);
+                    handle = null; // we don't own it any longer
                 }
-                catch (NotImplementedException) // Mono still does not support async, fallback to sync
+                else
                 {
-                    if (_asyncMode)
-                    {
-                        options &= (~PipeOptions.Asynchronous);
-                        _stream = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf);
-                        _asyncMode = false;
-                    }
-                    else
-                    {
-                        throw;
-                    }
+                    handle?.Dispose();
+                    instance = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf/*, pipesec*/);
                 }
             }
+            catch (NotImplementedException) // Mono still does not support async, fallback to sync
+            {
+                if (_asyncMode)
+                {
+                    options &= (~PipeOptions.Asynchronous);
+                    instance = new NamedPipeServerStream(_pipeAddress, direction, maxconn, mode, options, inbuf, outbuf);
+                    _asyncMode = false;
+                }
+                else
+                {
+                    throw;
+                }
+            }
+
+            // the task gets added later
+            return new TaskStreamPair( instance, null);
         }
 
 
@@ -248,14 +322,28 @@
         {
             try
             {
-                EnsurePipeInstance();
+                EnsurePipeInstances();
 
-                await _stream.WaitForConnectionAsync(cancellationToken);
+                // fill the list and wait for any task to be completed
+                var tasks = new List<Task>();
+                for (var i = 0; i < _streams.Count; ++i)
+                {
+                    if (_streams[i].Task == null)
+                    {
+                        var pair = _streams[i];
+                        pair.Task = Task.Run(async () => await pair.Stream.WaitForConnectionAsync(cancellationToken), cancellationToken);
+                        _streams[i] = pair;
+                    }
 
-                var trans = new ServerTransport(_stream, Configuration);
-                _stream = null; // pass ownership to ServerTransport
+                    tasks.Add(_streams[i].Task);
+                }
 
-                //_isPending = false;
+                // there must be an exact mapping between task index and stream index
+                Debug.Assert(_streams.Count == tasks.Count);
+                var index = Task.WaitAny(tasks.ToArray(), cancellationToken);
+
+                var trans = new ServerTransport(_streams[index].Stream, Configuration);
+                _streams.RemoveAt(index); // pass stream ownership to ServerTransport
 
                 return trans;
             }
@@ -278,7 +366,7 @@
 
         private class ServerTransport : TEndpointTransport
         {
-            private readonly NamedPipeServerStream PipeStream;
+            private NamedPipeServerStream PipeStream;
 
             public ServerTransport(NamedPipeServerStream stream, TConfiguration config)
                 : base(config)
@@ -296,7 +384,13 @@
 
             public override void Close()
             {
-                PipeStream?.Dispose();
+                if (PipeStream != null)
+                {
+                    if (PipeStream.IsConnected)
+                        PipeStream.Disconnect();
+                    PipeStream.Dispose();
+                    PipeStream = null;
+                }
             }
 
             public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
@@ -340,19 +434,23 @@
                 }
             }
 
-            public override Task FlushAsync(CancellationToken cancellationToken)
+            public override async Task FlushAsync(CancellationToken cancellationToken)
             {
-                cancellationToken.ThrowIfCancellationRequested();
-
+                await PipeStream.FlushAsync(cancellationToken);
                 ResetConsumedMessageSize();
-                return Task.CompletedTask;
             }
 
             protected override void Dispose(bool disposing)
             {
                 if (disposing)
                 {
-                    PipeStream?.Dispose();
+                    if (PipeStream != null)
+                    {
+                        if (PipeStream.IsConnected)
+                            PipeStream.Disconnect();
+                        PipeStream.Dispose();
+                        PipeStream = null;
+                    }
                 }
             }
         }
diff --git a/lib/netstd/Thrift/Transport/TEndpointTransport.cs b/lib/netstd/Thrift/Transport/TEndpointTransport.cs
index 51a2a17..6c78101 100644
--- a/lib/netstd/Thrift/Transport/TEndpointTransport.cs
+++ b/lib/netstd/Thrift/Transport/TEndpointTransport.cs
@@ -43,7 +43,7 @@
         /// <summary>
         /// Resets RemainingMessageSize to the configured maximum 
         /// </summary>
-        protected void ResetConsumedMessageSize(long newSize = -1)
+        public override void ResetConsumedMessageSize(long newSize = -1)
         {
             // full reset 
             if (newSize < 0)
diff --git a/lib/netstd/Thrift/Transport/TTransport.cs b/lib/netstd/Thrift/Transport/TTransport.cs
index 3f4245a..2f87ca0 100644
--- a/lib/netstd/Thrift/Transport/TTransport.cs
+++ b/lib/netstd/Thrift/Transport/TTransport.cs
@@ -1,4 +1,4 @@
-// Licensed to the Apache Software Foundation(ASF) under one
+// Licensed to the Apache Software Foundation(ASF) under one
 // or more contributor license agreements.See the NOTICE file
 // distributed with this work for additional information
 // regarding copyright ownership.The ASF licenses this file
@@ -35,6 +35,7 @@
         public abstract TConfiguration Configuration { get; }
         public abstract void UpdateKnownMessageSize(long size);
         public abstract void CheckReadBytesAvailable(long numBytes);
+        public abstract void ResetConsumedMessageSize(long newSize = -1);
         public void Dispose()
         {
             Dispose(true);
diff --git a/lib/nodejs/Makefile.am b/lib/nodejs/Makefile.am
index 67f6ff6..6691579 100644
--- a/lib/nodejs/Makefile.am
+++ b/lib/nodejs/Makefile.am
@@ -17,8 +17,8 @@
 
 # We call npm twice to work around npm issues
 
-stubs: $(top_srcdir)/test/ThriftTest.thrift
-	$(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/ThriftTest.thrift
+stubs: $(top_srcdir)/test/v0.16/ThriftTest.thrift
+	$(THRIFT) --gen js:node -o test/ $(top_srcdir)/test/v0.16/ThriftTest.thrift
 
 deps: $(top_srcdir)/package.json
 	$(NPM) install $(top_srcdir)/ || $(NPM) install $(top_srcdir)/
diff --git a/lib/nodejs/test/testAll.sh b/lib/nodejs/test/testAll.sh
index 3ae88b3..37b6b43 100755
--- a/lib/nodejs/test/testAll.sh
+++ b/lib/nodejs/test/testAll.sh
@@ -87,11 +87,11 @@
 
 # generating Thrift code
 
-${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/ThriftTest.thrift
+${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/v0.16/ThriftTest.thrift
 ${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/JsDeepConstructorTest.thrift
 ${THRIFT_COMPILER} -o ${DIR} --gen js:node ${THRIFT_FILES_DIR}/Int64Test.thrift
 mkdir ${DIR}/gen-nodejs-es6
-${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/ThriftTest.thrift
+${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/v0.16/ThriftTest.thrift
 ${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/JsDeepConstructorTest.thrift
 ${THRIFT_COMPILER} -out ${DIR}/gen-nodejs-es6 --gen js:node,es6 ${THRIFT_FILES_DIR}/Int64Test.thrift
 
diff --git a/lib/nodets/Makefile.am b/lib/nodets/Makefile.am
index 939dff2..02d0c11 100644
--- a/lib/nodets/Makefile.am
+++ b/lib/nodets/Makefile.am
@@ -17,9 +17,9 @@
 
 # We call npm twice to work around npm issues
 
-stubs: $(top_srcdir)/test/ThriftTest.thrift
+stubs: $(top_srcdir)/test/v0.16/ThriftTest.thrift
 	mkdir -p test-compiled
-	$(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/ThriftTest.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/ThriftTest.thrift
+	$(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/v0.16/ThriftTest.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/v0.16/ThriftTest.thrift
 	$(THRIFT) --gen js:node,ts -o test/ $(top_srcdir)/test/Int64Test.thrift && $(THRIFT) --gen js:node,ts -o test-compiled $(top_srcdir)/test/Int64Test.thrift
 
 ts-compile: stubs
diff --git a/lib/nodets/test/runClient.sh b/lib/nodets/test/runClient.sh
index 8d5e9a3..9497da3 100755
--- a/lib/nodets/test/runClient.sh
+++ b/lib/nodets/test/runClient.sh
@@ -10,8 +10,8 @@
 compile()
 {
   #generating thrift code
-  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
-  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
 }
 compile
 
diff --git a/lib/nodets/test/runServer.sh b/lib/nodets/test/runServer.sh
index 4eee927..ec26513 100755
--- a/lib/nodets/test/runServer.sh
+++ b/lib/nodets/test/runServer.sh
@@ -10,8 +10,8 @@
 compile()
 {
   #generating thrift code
-  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
-  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
 }
 compile
 
diff --git a/lib/nodets/test/testAll.sh b/lib/nodets/test/testAll.sh
index 3be12c3..8180e2a 100755
--- a/lib/nodets/test/testAll.sh
+++ b/lib/nodets/test/testAll.sh
@@ -10,9 +10,9 @@
 compile()
 {
   #generating thrift code
-  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
   ${DIR}/../../../compiler/cpp/thrift -o ${DIR} --gen js:node,ts ${DIR}/../../../test/Int64Test.thrift
-  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/ThriftTest.thrift
+  ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/v0.16/ThriftTest.thrift
   ${DIR}/../../../compiler/cpp/thrift -o ${COMPILEDDIR} --gen js:node,ts ${DIR}/../../../test/Int64Test.thrift
 
   tsc --outDir $COMPILEDDIR --project $DIR/tsconfig.json
diff --git a/lib/ocaml/_oasis b/lib/ocaml/_oasis
index 56374e0..e37dba7 100644
--- a/lib/ocaml/_oasis
+++ b/lib/ocaml/_oasis
@@ -1,5 +1,5 @@
 Name: libthrift-ocaml
-Version: 0.17.0
+Version: 0.18.0
 OASISFormat: 0.3
 Synopsis: OCaml bindings for the Apache Thrift RPC system
 Authors: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/lib/perl/Makefile.am b/lib/perl/Makefile.am
index 84009bd..8b72436 100644
--- a/lib/perl/Makefile.am
+++ b/lib/perl/Makefile.am
@@ -68,7 +68,7 @@
 	README.md
 
 THRIFT = @top_builddir@/compiler/cpp/thrift
-THRIFT_IF = @top_srcdir@/test/ThriftTest.thrift
+THRIFT_IF = @top_srcdir@/test/v0.16/ThriftTest.thrift
 NAME_BENCHMARKSERVICE =  @top_srcdir@/lib/rb/benchmark/Benchmark.thrift
 NAME_AGGR = @top_srcdir@/contrib/async-test/aggr.thrift
 
diff --git a/lib/perl/lib/Thrift.pm b/lib/perl/lib/Thrift.pm
index e7e1f0c..c10abd8 100644
--- a/lib/perl/lib/Thrift.pm
+++ b/lib/perl/lib/Thrift.pm
@@ -31,6 +31,6 @@
 #
 
 package Thrift;
-use version 0.77; our $VERSION = version->declare("v0.17.0");
+use version 0.77; our $VERSION = version->declare("v0.18.0");
 
 1;
diff --git a/lib/php/test/Makefile.am b/lib/php/test/Makefile.am
index 6f4e50a..30765c3 100644
--- a/lib/php/test/Makefile.am
+++ b/lib/php/test/Makefile.am
@@ -19,9 +19,9 @@
 
 PHPUNIT=php $(top_srcdir)/vendor/bin/phpunit
 
-stubs: ../../../test/ThriftTest.thrift  TestValidators.thrift
+stubs: ../../../test/v0.16/ThriftTest.thrift  TestValidators.thrift
 	mkdir -p ./packages/php
-	$(THRIFT) --gen php -r --out ./packages/php ../../../test/ThriftTest.thrift
+	$(THRIFT) --gen php -r --out ./packages/php ../../../test/v0.16/ThriftTest.thrift
 	mkdir -p ./packages/phpv
 	mkdir -p ./packages/phpvo
 	mkdir -p ./packages/phpjs
diff --git a/lib/php/test/TestValidators.thrift b/lib/php/test/TestValidators.thrift
index 9c38d92..a980470 100644
--- a/lib/php/test/TestValidators.thrift
+++ b/lib/php/test/TestValidators.thrift
@@ -19,7 +19,7 @@
 
 namespace php TestValidators
 
-include "../../../test/ThriftTest.thrift"
+include "../../../test/v0.16/ThriftTest.thrift"
 
 union UnionOfStrings {
   1: string aa;
diff --git a/lib/py/setup.py b/lib/py/setup.py
index bba69c8..7be2b5d 100644
--- a/lib/py/setup.py
+++ b/lib/py/setup.py
@@ -105,7 +105,7 @@
     twisted_deps = ['twisted']
 
     setup(name='thrift',
-          version='0.17.0',
+          version='0.18.0',
           description='Python bindings for the Apache Thrift RPC system',
           long_description=read_file("README.md"),
           long_description_content_type="text/markdown",
diff --git a/lib/py/src/transport/TSocket.py b/lib/py/src/transport/TSocket.py
index eea5366..ee7b26d 100644
--- a/lib/py/src/transport/TSocket.py
+++ b/lib/py/src/transport/TSocket.py
@@ -131,9 +131,9 @@
         for family, socktype, _, _, sockaddr in addrs:
             handle = self._do_open(family, socktype)
 
-            # TCP_KEEPALIVE
+            # TCP keep-alive
             if self._socket_keepalive:
-                handle.setsockopt(socket.IPPROTO_TCP, socket.SO_KEEPALIVE, 1)
+                handle.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
 
             handle.settimeout(self._timeout)
             try:
diff --git a/lib/rb/Rakefile b/lib/rb/Rakefile
index b509281..c6b650e 100644
--- a/lib/rb/Rakefile
+++ b/lib/rb/Rakefile
@@ -65,7 +65,7 @@
   
   task :'debug_proto' do
     sh "mkdir", "-p", "test/debug_proto"
-    sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/DebugProtoTest.thrift"
+    sh THRIFT, '--gen', 'rb', "-o", "test/debug_proto", "../../test/v0.16/DebugProtoTest.thrift"
   end
 end
 
diff --git a/lib/rb/thrift.gemspec b/lib/rb/thrift.gemspec
index 150b959..e6cc55b 100644
--- a/lib/rb/thrift.gemspec
+++ b/lib/rb/thrift.gemspec
@@ -3,7 +3,7 @@
 
 Gem::Specification.new do |s|
   s.name        = 'thrift'
-  s.version     = '0.17.0'
+  s.version     = '0.18.0'
   s.authors     = ['Apache Thrift Developers']
   s.email       = ['dev@thrift.apache.org']
   s.homepage    = 'http://thrift.apache.org'
diff --git a/lib/rs/Cargo.toml b/lib/rs/Cargo.toml
index 292f1bb..1ef524e 100644
--- a/lib/rs/Cargo.toml
+++ b/lib/rs/Cargo.toml
@@ -1,8 +1,8 @@
 [package]
 name = "thrift"
 description = "Rust bindings for the Apache Thrift RPC system"
-edition = "2018"
-version = "0.17.0"
+edition = "2021"
+version = "0.18.0"
 license = "Apache-2.0"
 authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
 homepage = "http://thrift.apache.org"
diff --git a/lib/rs/README.md b/lib/rs/README.md
index 30e36d4..010bb17 100644
--- a/lib/rs/README.md
+++ b/lib/rs/README.md
@@ -40,7 +40,7 @@
 ## Compatibility
 
 The Rust library and auto-generated code targets Rust versions 1.28+.
-It does not currently use any Rust 2018 features.
+It does not currently use any Rust 2021 features.
 
 ### Breaking Changes
 
@@ -136,7 +136,7 @@
 
   As a result of this change the Rust representation of an enum changes from a standard
   Rust enum into a newtype struct with associated constants.
-  
+
   For example:
 
   ```thrift
@@ -150,7 +150,7 @@
   ```
 
   used to generate:
-  
+
   ```rust
     // OLD AUTO-GENERATED RUST
     pub enum Operation {
@@ -162,11 +162,11 @@
   ```
 
   It *now* generates:
-  
+
   ```rust
     // NEW AUTO-GENERATED RUST
     pub struct Operation(pub i32);
-  
+
     impl Operation {
       pub const ADD: Operation = Operation(0);
       pub const SUBTRACT: Operation = Operation(1);
@@ -177,19 +177,19 @@
 
 ##### Thrift 0.14.0
 
-* **[THRIFT-5158]** - Rust library and generator now support Rust 2018 only. Required rust 1.40.0 or higher
+* **[THRIFT-5158]** - Rust library and generator now support Rust 2021 only. Required rust 1.61.0 or higher
 
-    The Rust `thrift` library was updated to Rust 2018 via `cargo fix --edition`.
+    The Rust `thrift` library was updated to Rust 2021 via `cargo fix --edition`.
     All test code in the repo was updated as well. The code generator was also updated
-    to support Rust 2018 only.
+    to support Rust 2021 only.
 
 ##### Thrift 0.13.0
 
 * **[THRIFT-4536]** - Use TryFrom from std, required rust 1.34.0 or higher
 
     Previously TryFrom was from try_from crate, it is now from the std library,
-    but this functionality is only available in rust 1.34.0. Additionally, 
-    ordered-float is now re-exported under the thrift module to reduce 
+    but this functionality is only available in rust 1.34.0. Additionally,
+    ordered-float is now re-exported under the thrift module to reduce
     possible dependency mismatches.
 
 ##### Thrift 0.12.0
@@ -208,9 +208,9 @@
       DIVIDE,
     }
     ```
-    
+
     used to generate:
-    
+
     ```rust
     // OLD AUTO-GENERATED RUST
     pub enum Operation {
@@ -220,9 +220,9 @@
        DIVIDE,
      }
     ```
-  
+
     It *now* generates:
-  
+
     ```rust
     // NEW AUTO-GENERATED RUST
     pub enum Operation {
@@ -232,7 +232,7 @@
        Divide,
      }
     ```
-    
+
     You will have to change all enum variants in your code to use camel-cased names.
     This should be a search and replace.
 
diff --git a/lib/rs/src/protocol/compact.rs b/lib/rs/src/protocol/compact.rs
index 566f344..87cfbfc 100644
--- a/lib/rs/src/protocol/compact.rs
+++ b/lib/rs/src/protocol/compact.rs
@@ -84,14 +84,13 @@
         let header = self.read_byte()?;
         let element_type = collection_u8_to_type(header & 0x0F)?;
 
-        let element_count;
         let possible_element_count = (header & 0xF0) >> 4;
-        if possible_element_count != 15 {
+        let element_count = if possible_element_count != 15 {
             // high bits set high if count and type encoded separately
-            element_count = possible_element_count as i32;
+            possible_element_count as i32
         } else {
-            element_count = self.transport.read_varint::<u32>()? as i32;
-        }
+            self.transport.read_varint::<u32>()? as i32
+        };
 
         Ok((element_type, element_count))
     }
diff --git a/lib/rs/src/protocol/mod.rs b/lib/rs/src/protocol/mod.rs
index f693375..019f717 100644
--- a/lib/rs/src/protocol/mod.rs
+++ b/lib/rs/src/protocol/mod.rs
@@ -920,7 +920,7 @@
     field_ident.id.ok_or_else(|| {
         crate::Error::Protocol(crate::ProtocolError {
             kind: crate::ProtocolErrorKind::Unknown,
-            message: format!("missing field in in {:?}", field_ident),
+            message: format!("missing field id in {:?}", field_ident),
         })
     })
 }
diff --git a/lib/rs/src/server/multiplexed.rs b/lib/rs/src/server/multiplexed.rs
index 8331d91..f6811a4 100644
--- a/lib/rs/src/server/multiplexed.rs
+++ b/lib/rs/src/server/multiplexed.rs
@@ -170,8 +170,7 @@
             let (_, svc_call) = svc_call.split_at(1); // remove colon from service call name
             (Some(svc_name), svc_call)
         })
-        .or_else(|| Some((None, ident_name)))
-        .unwrap()
+        .unwrap_or((None, ident_name))
 }
 
 fn missing_processor_message(svc_name: Option<&str>) -> String {
@@ -272,10 +271,10 @@
             _: &mut dyn TInputProtocol,
             _: &mut dyn TOutputProtocol,
         ) -> crate::Result<()> {
-            let res = self
-                .invoked
-                .compare_and_swap(false, true, Ordering::Relaxed);
-            if res {
+            let res =
+                self.invoked
+                    .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed);
+            if res.is_ok() {
                 Ok(())
             } else {
                 Err("failed swap".into())
diff --git a/lib/rs/test/Cargo.toml b/lib/rs/test/Cargo.toml
index 47b8cbf..a1c6836 100644
--- a/lib/rs/test/Cargo.toml
+++ b/lib/rs/test/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "kitchen-sink"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 license = "Apache-2.0"
 authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
 publish = false
diff --git a/lib/rs/test/src/bin/kitchen_sink_client.rs b/lib/rs/test/src/bin/kitchen_sink_client.rs
index b98afb8..4cd2ba9 100644
--- a/lib/rs/test/src/bin/kitchen_sink_client.rs
+++ b/lib/rs/test/src/bin/kitchen_sink_client.rs
@@ -33,7 +33,6 @@
 use kitchen_sink::recursive::{CoRec, CoRec2, RecList, RecTree, TTestServiceSyncClient};
 use kitchen_sink::ultimate::{FullMealServiceSyncClient, TFullMealServiceSyncClient};
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
     TInputProtocol, TOutputProtocol,
diff --git a/lib/rs/test/src/bin/kitchen_sink_server.rs b/lib/rs/test/src/bin/kitchen_sink_server.rs
index ea571c6..1abd07c 100644
--- a/lib/rs/test/src/bin/kitchen_sink_server.rs
+++ b/lib/rs/test/src/bin/kitchen_sink_server.rs
@@ -18,7 +18,6 @@
 use clap::{clap_app, value_t};
 use log::*;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
     TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
diff --git a/lib/rs/test/src/lib.rs b/lib/rs/test/src/lib.rs
index 91fd027..06f65cb 100644
--- a/lib/rs/test/src/lib.rs
+++ b/lib/rs/test/src/lib.rs
@@ -18,8 +18,8 @@
 pub mod base_one;
 pub mod base_two;
 pub mod midlayer;
-pub mod ultimate;
 pub mod recursive;
+pub mod ultimate;
 
 #[cfg(test)]
 mod tests {
diff --git a/lib/rs/test_recursive/Cargo.toml b/lib/rs/test_recursive/Cargo.toml
index 6b2aa85..28dbf38 100644
--- a/lib/rs/test_recursive/Cargo.toml
+++ b/lib/rs/test_recursive/Cargo.toml
@@ -3,7 +3,7 @@
 description = "Test namespace support in generated thrift files using recursive Make generation"
 version = "0.1.0"
 authors = ["Allen George <allengeorge@apache.org>"]
-edition = "2018"
+edition = "2021"
 
 [dependencies]
 thrift = { path = "../" }
diff --git a/lib/rs/test_recursive/src/lib.rs b/lib/rs/test_recursive/src/lib.rs
index bac37b4..5b9211c 100644
--- a/lib/rs/test_recursive/src/lib.rs
+++ b/lib/rs/test_recursive/src/lib.rs
@@ -17,9 +17,9 @@
 
 #![allow(dead_code)]
 
+pub mod maintenance;
 pub mod transit;
 pub mod vehicles;
-pub mod maintenance;
 
 mod server {
     use crate::maintenance::maintenance_facility::{
diff --git a/lib/st/package.xml b/lib/st/package.xml
index 70cf0ac..2b2ce8f 100644
--- a/lib/st/package.xml
+++ b/lib/st/package.xml
@@ -17,7 +17,7 @@
  specific language governing permissions and limitations
  under the License.
  -->
-<!-- Apache Thrift Smalltalk library version 0.17.0 -->
+<!-- Apache Thrift Smalltalk library version 0.18.0 -->
 <package>
   <name>libthrift-st</name>
   <file>thrift.st</file>
diff --git a/lib/swift/Sources/Thrift.swift b/lib/swift/Sources/Thrift.swift
index 82b0421..73303ae 100644
--- a/lib/swift/Sources/Thrift.swift
+++ b/lib/swift/Sources/Thrift.swift
@@ -1,3 +1,3 @@
 class Thrift {
-	let version = "0.17.0"
+	let version = "0.18.0"
 }
diff --git a/lib/swift/Tests/ThriftTests/ThriftTests.swift b/lib/swift/Tests/ThriftTests/ThriftTests.swift
index d19c89d..a37c604 100644
--- a/lib/swift/Tests/ThriftTests/ThriftTests.swift
+++ b/lib/swift/Tests/ThriftTests/ThriftTests.swift
@@ -3,7 +3,7 @@
 
 class ThriftTests: XCTestCase {
   func testVersion() {
-    XCTAssertEqual(Thrift().version, "0.17.0")
+    XCTAssertEqual(Thrift().version, "0.18.0")
   }
 
   static var allTests : [(String, (ThriftTests) -> () throws -> Void)] {
diff --git a/lib/ts/Gruntfile.js b/lib/ts/Gruntfile.js
index fcd79f8..61ab582 100644
--- a/lib/ts/Gruntfile.js
+++ b/lib/ts/Gruntfile.js
@@ -32,9 +32,9 @@
       ThriftGen: {
         command: [
           'mkdir -p test/gen-js',
-          '../../compiler/cpp/thrift -gen js:ts --out test/gen-js ../../test/ThriftTest.thrift',
+          '../../compiler/cpp/thrift -gen js:ts --out test/gen-js ../../test/v0.16/ThriftTest.thrift',
           'mkdir -p test/gen-nodejs',
-          '../../compiler/cpp/thrift -gen js:node,ts --out test/gen-nodejs ../../test/ThriftTest.thrift',
+          '../../compiler/cpp/thrift -gen js:node,ts --out test/gen-nodejs ../../test/v0.16/ThriftTest.thrift',
         ].join(' && ')
       },
       ThriftBrowserifyNodeInt64: {
diff --git a/lib/ts/package-lock.json b/lib/ts/package-lock.json
index dea9f31..ac3a332 100644
--- a/lib/ts/package-lock.json
+++ b/lib/ts/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/lib/ts/package.json b/lib/ts/package.json
index 8a564c6..403488a 100644
--- a/lib/ts/package.json
+++ b/lib/ts/package.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "description": "Thrift is a software framework for scalable cross-language services development.",
   "author": {
     "name": "Apache Thrift Developers",
diff --git a/lib/ts/test/build.xml b/lib/ts/test/build.xml
index 5c3a4a8..a53335b 100644
--- a/lib/ts/test/build.xml
+++ b/lib/ts/test/build.xml
@@ -167,10 +167,10 @@
 
   <target name="generate">
     <exec executable="${thrift.compiler}" failonerror="true">
-      <arg line="--gen java ${thrift.dir}/test/ThriftTest.thrift" />
+      <arg line="--gen java ${thrift.dir}/test/v0.16/ThriftTest.thrift" />
     </exec>
     <exec executable="${thrift.compiler}" failonerror="true">
-      <arg line="--gen js:jquery ${thrift.dir}/test/ThriftTest.thrift" />
+      <arg line="--gen js:jquery ${thrift.dir}/test/v0.16/ThriftTest.thrift" />
     </exec>
     <exec executable="${thrift.compiler}" failonerror="true">
       <arg line="--gen js:jquery ${thrift.dir}/test/DoubleConstantsTest.thrift" />
diff --git a/lib/xml/thrift-idl.xsd b/lib/xml/thrift-idl.xsd
index 09dd695..db847bc 100644
--- a/lib/xml/thrift-idl.xsd
+++ b/lib/xml/thrift-idl.xsd
@@ -277,6 +277,7 @@
       <enumeration value="map" />
       <enumeration value="set" />
       <enumeration value="list" />
+      <enumeration value="uuid" />
     </restriction>
   </simpleType>
 
diff --git a/package-lock.json b/package-lock.json
index 14bfa8a..77ef548 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thrift",
-  "version": "0.17.0",
+  "version": "0.18.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/package.json b/package.json
index 8f2e1c8..2562538 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
     "type": "git",
     "url": "https://github.com/apache/thrift.git"
   },
-  "version": "0.17.0",
+  "version": "0.18.0",
   "author": {
     "name": "Apache Thrift Developers",
     "email": "dev@thrift.apache.org",
diff --git a/rust-toolchain b/rust-toolchain
index 32b7211..91951fd 100644
--- a/rust-toolchain
+++ b/rust-toolchain
@@ -1 +1 @@
-1.40.0
+1.61.0
diff --git a/sonar-project.properties b/sonar-project.properties
index 08d4c4a..0ec39de 100644
--- a/sonar-project.properties
+++ b/sonar-project.properties
@@ -16,7 +16,7 @@
 services that work efficiently and seamlessly between all major languages.
 
 # Apache Thrift Version
-sonar.projectVersion=0.17.0
+sonar.projectVersion=0.18.0
 # use this to set another version string
 # $ sonar-runner -D sonar.projectVersion=`git rev-parse HEAD`
 # set projectDate in combination with projectVersion for imports of old releases
@@ -54,7 +54,7 @@
 module1.sonar.projectBaseDir=lib/java
 module1.sonar.sources=src
 module1.sonar.tests=test
-module1.sonar.binaries=build/libs/libthrift-0.17.0.jar
+module1.sonar.binaries=build/libs/libthrift-0.18.0.jar
 module1.sonar.libraries=build/deps/*.jar
 module1.sonar.language=java
 
@@ -62,7 +62,7 @@
 module2.sonar.projectBaseDir=.
 module2.sonar.sources=tutorial/java/src, tutorial/java/gen-java
 module2.sonar.binaries=tutorial/java/tutorial.jar
-module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-0.17.0.jar
+module2.sonar.libraries=lib/java/build/deps/*.jar,lib/java/build/libs/libthrift-0.18.0.jar
 module2.sonar.language=java
 
 module3.sonar.projectName=Apache Thrift - JavaScript Library
diff --git a/test/ConstantsDemo.thrift b/test/ConstantsDemo.thrift
index 204e805..e03f053 100644
--- a/test/ConstantsDemo.thrift
+++ b/test/ConstantsDemo.thrift
@@ -65,6 +65,8 @@
 
 const set<i32> GEN_SET = [ 235, 235, 53235 ]
 
+const uuid GEN_UUID = "00000000-4444-CCCC-ffff-0123456789ab"
+
 exception Blah {
   1:  i32 bing }
 
diff --git a/test/DebugProtoTest.thrift b/test/DebugProtoTest.thrift
index 5d0face..3750d8d 100644
--- a/test/DebugProtoTest.thrift
+++ b/test/DebugProtoTest.thrift
@@ -48,6 +48,7 @@
   12: list<i8> byte_list = [1, 2, 3],
   13: list<i16> i16_list = [1,2,3],
   14: list<i64> i64_list = [1,2,3]
+  15: uuid rfc4122_uuid
 }
 
 struct Bonk {
diff --git a/test/DoubleConstantsTest.thrift b/test/DoubleConstantsTest.thrift
index c9212ab..b4c6f7f 100644
--- a/test/DoubleConstantsTest.thrift
+++ b/test/DoubleConstantsTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace java thrift.test
 namespace cpp thrift.test
 
diff --git a/test/Identifiers.thrift b/test/Identifiers.thrift
index aa3e4ea..ffe937d 100644
--- a/test/Identifiers.thrift
+++ b/test/Identifiers.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 // THRIFT-4953
 struct NoFieldIdentifiersTest {
   string field_without_id1,
diff --git a/test/Include.thrift b/test/Include.thrift
index 562319b..f61cf05 100644
--- a/test/Include.thrift
+++ b/test/Include.thrift
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-include "ThriftTest.thrift"
+include "v0.16/ThriftTest.thrift"
 
 struct IncludeTest {
   1: required ThriftTest.Bools bools
diff --git a/test/JsDeepConstructorTest.thrift b/test/JsDeepConstructorTest.thrift
index ef5126f..b34709c 100644
--- a/test/JsDeepConstructorTest.thrift
+++ b/test/JsDeepConstructorTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 struct Simple {
   1: string value
 }
diff --git a/test/Makefile.am b/test/Makefile.am
index e94a92f..478fb2c 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -25,6 +25,11 @@
 PRECROSS_TARGET += precross-c_glib
 endif
 
+if WITH_CL
+SUBDIRS += cl
+PRECROSS_TARGET += precross-cl
+endif
+
 if WITH_CPP
 SUBDIRS += cpp
 PRECROSS_TARGET += precross-cpp
@@ -113,6 +118,7 @@
 EXTRA_DIST = \
 	audit \
 	c_glib \
+	cl \
 	cpp \
 	crossrunner \
 	dart \
@@ -133,6 +139,7 @@
 	BrokenConstants.thrift \
 	ConstantsDemo.thrift \
 	DebugProtoTest.thrift \
+	v0.16/DebugProtoTest.thrift \
 	DenseLinkingTest.thrift \
 	DocTest.thrift \
 	DoubleConstantsTest.thrift \
@@ -152,6 +159,7 @@
 	SmallTest.thrift \
 	StressTest.thrift \
 	ThriftTest.thrift \
+	v0.16/ThriftTest.thrift \
 	TypedefTest.thrift \
 	Types.thrift \
 	UnsafeTypes.thrift \
diff --git a/test/NameConflictTest.thrift b/test/NameConflictTest.thrift
index d3efb47..b06659f 100644
--- a/test/NameConflictTest.thrift
+++ b/test/NameConflictTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 // Naming testcases, sepcifically for these tickets (but not limited to them)
 // THRIFT-2508 Uncompileable C# code due to language keywords in IDL
 // THRIFT-2557 error CS0542 member names cannot be the same as their enclosing type
@@ -97,6 +116,20 @@
   2: bool Problem
 }
 
+struct Thrift5626 {
+   1: i8       i8
+   2: i16      i16
+   3: i32      i32
+   4: i64      i64
+   5: uuid     uuid
+   6: string   string
+   7: binary   binary
+   8: bool     bool
+   9: byte     byte
+  10: list<string>        list
+  11: set<string>         set
+  12: map<string,string>  map
+}
 
 service extern {
     delegate event(1: partial get)
diff --git a/test/ReuseObjects.thrift b/test/ReuseObjects.thrift
index 2dd6c6e..1dd36cd 100644
--- a/test/ReuseObjects.thrift
+++ b/test/ReuseObjects.thrift
@@ -21,7 +21,7 @@
 
 namespace java thrift.test
 
-include "ThriftTest.thrift"
+include "v0.16/ThriftTest.thrift"
 
 struct Reuse {
   1: i32 val1;
diff --git a/test/ThriftTest.thrift b/test/ThriftTest.thrift
index 4a1045f..42607cc 100644
--- a/test/ThriftTest.thrift
+++ b/test/ThriftTest.thrift
@@ -112,6 +112,7 @@
   // Do not insert line break as test/go/Makefile.am is removing this line with pattern match
   3: required list<map<set<i32> (python.immutable = ""), map<i32,set<list<map<Insanity,string>(python.immutable = "")> (python.immutable = "")>>>> list_field,
   4: binary binary_field
+  5: uuid uuid_field
 }
 
 union SomeUnion {
@@ -196,6 +197,13 @@
   binary       testBinary(1: binary thing),
 
   /**
+   * Prints 'testUuid("%s")' where '%s' is the uuid given. Note that the uuid byte order should be correct.
+   * @param uuid  thing - the uuid to print
+   * @return uuid  - returns the uuid 'thing'
+   */
+  uuid       testUuid(1: uuid thing),
+
+  /**
    * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
    * @param Xtruct thing - the Xtruct to print
    * @return Xtruct - returns the Xtruct 'thing'
diff --git a/test/VoidMethExceptionsTest.thrift b/test/VoidMethExceptionsTest.thrift
index fc75976..195f772 100644
--- a/test/VoidMethExceptionsTest.thrift
+++ b/test/VoidMethExceptionsTest.thrift
@@ -1,3 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
 namespace java thrift.test.voidmethexceptions
 
 exception TExampleException {
diff --git a/test/c_glib/CMakeLists.txt b/test/c_glib/CMakeLists.txt
index 410774d..ecbd2ae 100644
--- a/test/c_glib/CMakeLists.txt
+++ b/test/c_glib/CMakeLists.txt
@@ -56,5 +56,5 @@
 #
 
 add_custom_command(OUTPUT gen-c_glib/t_test_second_service.c  gen-c_glib/t_test_second_service.h  gen-c_glib/t_test_thrift_test.c  gen-c_glib/t_test_thrift_test.h  gen-c_glib/t_test_thrift_test_types.c  gen-c_glib/t_test_thrift_test_types.h
-    COMMAND ${THRIFT_COMPILER} --gen c_glib -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen c_glib -r ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
 )
diff --git a/test/c_glib/Makefile.am b/test/c_glib/Makefile.am
index 98a3734..f55a977 100644
--- a/test/c_glib/Makefile.am
+++ b/test/c_glib/Makefile.am
@@ -56,7 +56,7 @@
 #
 # Common thrift code generation rules
 #
-gen-c_glib/t_test_second_service.c  gen-c_glib/t_test_second_service.h  gen-c_glib/t_test_thrift_test.c  gen-c_glib/t_test_thrift_test.h  gen-c_glib/t_test_thrift_test_types.c  gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+gen-c_glib/t_test_second_service.c  gen-c_glib/t_test_second_service.h  gen-c_glib/t_test_thrift_test.c  gen-c_glib/t_test_thrift_test.h  gen-c_glib/t_test_thrift_test_types.c  gen-c_glib/t_test_thrift_test_types.h: $(top_srcdir)/test/v0.16/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen c_glib -r $<
 
 AM_CFLAGS = -g -Wall -Wextra $(GLIB_CFLAGS) $(GOBJECT_CFLAGS)
diff --git a/test/cl/Makefile.am b/test/cl/Makefile.am
new file mode 100755
index 0000000..b5e72bc
--- /dev/null
+++ b/test/cl/Makefile.am
@@ -0,0 +1,42 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+THRIFT = $(top_builddir)/compiler/cpp/thrift
+
+stubs: ../ThriftTest.thrift
+	$(THRIFT) --gen cl ../ThriftTest.thrift
+
+TestServer: make-test-server.lisp
+	$(SBCL) --script make-test-server.lisp
+
+TestClient: make-test-client.lisp
+	$(SBCL) --script make-test-client.lisp
+
+precross: stubs TestServer TestClient
+
+clean-local:
+	$(RM) -r gen-cl
+	$(RM) TestServer
+	$(RM) TestClient
+
+EXTRA_DIST = \
+	implementation.lisp \
+	make-test-client.lisp \
+	make-test-server.lisp \
+	tests.lisp
diff --git a/test/cl/implementation.lisp b/test/cl/implementation.lisp
new file mode 100644
index 0000000..0caf7be
--- /dev/null
+++ b/test/cl/implementation.lisp
@@ -0,0 +1,136 @@
+(in-package #:thrift.test-implementation)
+
+;;;; 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.
+
+(defun thrift.test.thrift-test-implementation:test-void ()
+  (format t "testVoid()~%"))
+
+(defun thrift.test.thrift-test-implementation:test-string (thing)
+  (format t "testString(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-bool (thing)
+  (format t "testBool(~a)~%" (if thing "true" "false"))
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-byte (thing)
+  (format t "testByte(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-i32 (thing)
+  (format t "testI32(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-i64 (thing)
+  (format t "testI64(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-double (thing)
+  (format t "testDouble(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-binary (thing)
+  (format t "testBinary(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-struct (thing)
+  (format t "testStruct(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-nest (thing)
+  (format t "testNest(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-map (thing)
+  (format t "testMap(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-string-map (thing)
+  (format t "testStringMap(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-set (thing)
+  (format t "testSet(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-list (thing)
+  (format t "testList(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-enum (thing)
+  (format t "testEnum(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-typedef (thing)
+  (format t "testTypedef(~a)~%" thing)
+  thing)
+
+(defun thrift.test.thrift-test-implementation:test-map-map (hello)
+  (format t "testMapMap(~a)~%" hello)
+  '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1))) (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4)))))
+
+(defun thrift.test.thrift-test-implementation:test-insanity (argument)
+  (let ((result `((1 . ((2 . ,argument) (3 . ,argument)))
+                  (2 . ((6 . ,(thrift.test::make-insanity :user-map nil :xtructs nil)))))))
+    (format t "~a~%" result)
+    result))
+
+(defun thrift.test.thrift-test-implementation:test-multi (arg0 arg1 arg2 arg3 arg4 arg5)
+  (declare (ignorable arg3 arg4 arg5))
+  (format t "testMulti()~%")
+  (thrift.test:make-xtruct :string-thing "Hello2"
+                           :byte-thing arg0
+                           :i32-thing arg1
+                           :i64-thing arg2))
+
+(defun thrift.test.thrift-test-implementation:test-exception (arg)
+  (format t "testException(~a)~%" arg)
+  (cond
+    ((string= arg "Xception") (error 'thrift.test:xception
+                                     :error-code 1001
+                                     :message arg))
+    ((string= arg "TException") (error 'thrift.test:xception
+                                       :error-code 0
+                                       :message "Stuff!"))))
+
+(defun thrift.test.thrift-test-implementation:test-multi-exception (arg0 arg1)
+  (format t "testMultiException(~a, ~a)~%" arg0 arg1)
+  (cond
+    ((string= arg0 "Xception") (error 'thrift.test:xception
+                                     :error-code 1001
+                                     :message "This is an Xception"))
+    ((string= arg0 "Xception2") (error 'thrift.test:xception2
+                                     :error-code 2002
+                                     :struct-thing (thrift.test:make-xtruct :string-thing "This is an Xception2"
+                                                                            :byte-thing 0
+                                                                            :i32-thing 0
+                                                                            :i64-thing 0))))
+  (thrift.test:make-xtruct :string-thing arg1
+                           :byte-thing 0
+                           :i32-thing 0
+                           :i64-thing 0))
+
+(defun thrift.test.thrift-test-implementation:test-oneway (seconds)
+  (format t "testOneway(~a): Sleeping...~%" seconds)
+  (sleep seconds)
+  (format t "testOneway(~a): done sleeping!~%" seconds))
+
+;;; Removed from the IDL definition.
+#+(or)
+(defun thrift.test.second-service-implementation:blah-blah ()
+  (format t "blahBlah()~%"))
+
+(defun thrift.test.second-service-implementation:secondtest-string (thing)
+  (format t "secondtestString(~a)~%" thing)
+  (concatenate 'string "testString(\"" thing "\")"))
+
diff --git a/test/cl/make-test-client.lisp b/test/cl/make-test-client.lisp
new file mode 100644
index 0000000..fa049e7
--- /dev/null
+++ b/test/cl/make-test-client.lisp
@@ -0,0 +1,96 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+#+(or) (when (not (boundp 'sb-impl::default-external-format)
+                 (setf sb-impl::default-external-format :UTF-8)))
+
+(require "asdf")
+(load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*))
+(require "sb-grovel") ;; necessary for :net.didierverna.clon.termio
+(asdf:load-asd (first (directory (merge-pathnames "../../lib/cl/externals/software/clon-*/termio/net.didierverna.clon.termio.asd"
+                                                  *load-truename*))))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-system :fiasco)
+(asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*))
+(asdf:load-system :thrift-gen-thrifttest)
+
+(net.didierverna.clon:nickname-package)
+
+(defpackage #:thrift-cross
+  (:use #:common-lisp #:fiasco)
+  (:export #:cross-test))
+
+(in-package #:thrift-cross)
+
+(defparameter *prot* nil)
+
+(load (merge-pathnames "tests.lisp" *load-truename*) :external-format :UTF-8)
+
+(clon:defsynopsis ()
+  (text :contents "The Common Lisp client for Thrift's cross-language test suite.")
+  (group (:header "Allowed options:")
+    (flag :short-name "h" :long-name "help"
+          :description "Print this help and exit.")
+    (stropt :long-name "host"
+            :description "The host to connect to."
+            :default-value "localhost"
+            :argument-name "ARG")
+    (stropt :long-name "port"
+            :description "Number of the port to listen for connections on."
+            :default-value "9090"
+            :argument-name "ARG"
+            :argument-type :optional)
+    (stropt :long-name "transport"
+            :description "Transport: transport to use (\"buffered\", \"framed\")"
+            :default-value "buffered"
+            :argument-name "ARG")
+    (stropt :long-name "protocol"
+            :description "Protocol: protocol to use (\"binary\", \"multi\")"
+            :default-value "binary"
+            :argument-name "ARG")))
+
+(defun main ()
+  "Entry point for our standalone application."
+  (clon:make-context)
+  (when (clon:getopt :short-name "h")
+    (clon:help)
+    (clon:exit))
+  (let ((port "9090")
+        (host "localhost")
+        (framed nil)
+        (multiplexed nil))
+    (clon:do-cmdline-options (option name value source)
+      (print (list option name value source))
+      (if (string= name "host")
+          (setf host value))
+      (if (string= name "port")
+          (setf port value))
+      (if (string= name "transport")
+          (cond ((string= value "buffered") (setf framed nil))
+                ((string= value "framed") (setf framed t))
+                (t (error "Unsupported transport."))))
+      (if (string= name "protocol")
+          (cond ((string= value "binary") (setf multiplexed nil))
+                ((string= value "multi") (setf multiplexed t))
+                (t (error "Unsupported protocol.")))))
+    (terpri)
+    (setf *prot* (thrift.implementation::client (puri:parse-uri
+                                                 (concatenate 'string "thrift://" host ":" port))
+                                                :framed framed
+                                                :multiplexed multiplexed))
+    (let ((result (cross-test :multiplexed multiplexed)))
+      (thrift.implementation::close *prot*)
+      (clon:exit result))))
+
+(clon:dump "TestClient" main)
diff --git a/test/cl/make-test-server.lisp b/test/cl/make-test-server.lisp
new file mode 100644
index 0000000..a027968
--- /dev/null
+++ b/test/cl/make-test-server.lisp
@@ -0,0 +1,83 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+(require "asdf")
+(load (merge-pathnames "../../lib/cl/load-locally.lisp" *load-truename*))
+(require "sb-grovel") ;; necessary for :net.didierverna.clon.termio
+(asdf:load-asd (first (directory (merge-pathnames "../../lib/cl/externals/software/clon-*/termio/net.didierverna.clon.termio.asd"
+                                                  *load-truename*))))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/ThriftTest/thrift-gen-ThriftTest.asd" *load-truename*))
+(asdf:load-system :thrift-gen-thrifttest)
+(load (merge-pathnames "implementation.lisp" *load-truename*))
+
+(net.didierverna.clon:nickname-package)
+
+(clon:defsynopsis ()
+  (text :contents "The Common Lisp server for Thrift's cross-language test suite.")
+  (group (:header "Allowed options:")
+    (flag :short-name "h" :long-name "help"
+          :description "Print this help and exit.")
+    (stropt :long-name "port"
+            :description "Number of the port to listen for connections on."
+            :default-value "9090"
+            :argument-name "ARG"
+            :argument-type :optional)
+    (stropt :long-name "server-type"
+            :description "The type of server, currently only \"simple\" is available."
+            :default-value "simple"
+            :argument-name "ARG")
+    (stropt :long-name "transport"
+            :description "Transport: transport to use (\"buffered\" or \"framed\")"
+            :default-value "buffered"
+            :argument-name "ARG")
+    (stropt :long-name "protocol"
+            :description "Protocol: protocol to use (\"binary\" or \"multi\")"
+            :default-value "binary"
+            :argument-name "ARG")))
+
+(defun main ()
+  "Entry point for our standalone application."
+  (clon:make-context)
+  (when (clon:getopt :short-name "h")
+    (clon:help)
+    (clon:exit))
+  (let ((port "9090")
+        (framed nil)
+        (multiplexed nil))
+    (clon:do-cmdline-options (option name value source)
+      (print (list option name value source))
+      (if (string= name "port")
+          (setf port value))
+      (if (string= name "transport")
+          (cond ((string= value "buffered") (setf framed nil))
+                ((string= value "framed") (setf framed t))
+                (t (error "Unsupported transport."))))
+      (if (string= name "protocol")
+          (cond ((string= value "binary") (setf multiplexed nil))
+                ((string= value "multi") (setf multiplexed t))
+                (t (error "Unsupported protocol.")))))
+    (terpri)
+    (let ((services (if multiplexed
+                        (list thrift.test:thrift-test thrift.test:second-service)
+                        thrift.test:thrift-test)))
+      (thrift:serve (puri:parse-uri (concatenate 'string
+                                                 "thrift://127.0.0.1:"
+                                                 port))
+                    services
+                    :framed framed
+                    :multiplexed multiplexed)))
+  (clon:exit))
+
+(clon:dump "TestServer" main)
diff --git a/test/cl/tests.lisp b/test/cl/tests.lisp
new file mode 100644
index 0000000..c5035fd
--- /dev/null
+++ b/test/cl/tests.lisp
@@ -0,0 +1,240 @@
+(in-package #:thrift-cross)
+
+;;;; 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.
+
+;;;; The tests here only make sense in the context of a TestServer
+;;;; running and the dynamic variable thrift-cross::*prot*
+;;;; being set with a client connection to the TestServer. Normally,
+;;;; this is handled in make-test-client.lisp.
+
+
+;;; Standard Thrift cross-test error codes
+(defparameter *test_basetypes* 1)
+(defparameter *test_structs* 2)
+(defparameter *test_containers* 4)
+(defparameter *test_exceptions* 8)
+(defparameter *test_unknown* 64)
+(defparameter *test_timeout* 128)
+
+(defun cross-test (&key (multiplexed nil))
+  "The main cross-test runner."
+  (let ((result nil))
+    (handler-case
+        (progn
+          (unless (run-package-tests :package :base-types)
+            (pushnew *test_basetypes* result))
+          (unless (run-package-tests :package :structs)
+            (pushnew *test_structs* result))
+          (unless (run-package-tests :package :containers)
+            (pushnew *test_containers* result))
+          (unless (run-package-tests :package :exceptions)
+            (pushnew *test_exceptions* result))
+          (unless (run-package-tests :package :misc)
+            (pushnew *test_unknown* result))
+
+          ;; It doesn't seem like anyone actually uses
+          ;; the second test service when testing multiplexing,
+          ;; so this would fail against servers in other
+          ;; languages. For now, anyway.
+          #+(or)
+          (when multiplexed
+            (unless (run-package-tests :package :multiplex)
+              (pushnew *test_unknown* result))))
+      (error (e) (pushnew *test_unknown* result)))
+    (apply #'+ result)))
+
+(fiasco:define-test-package #:base-types)
+
+(in-package #:base-types)
+
+(defconstant *lang-string* "Afrikaans, Alemannisch, Aragonés, العربية, مصرى, Asturianu, Aymar aru, Azərbaycan, Башҡорт, Boarisch, Žemaitėška, Беларуская, Беларуская (тарашкевіца), Български, Bamanankan, বাংলা, Brezhoneg, Bosanski, Català, Mìng-dĕ̤ng-ngṳ̄, Нохчийн, Cebuano, ᏣᎳᎩ, Česky, Словѣ́ньскъ / ⰔⰎⰑⰂⰡⰐⰠⰔⰍⰟ, Чӑвашла, Cymraeg, Dansk, Zazaki, ދިވެހިބަސް, Ελληνικά, Emiliàn e rumagnòl, English, Esperanto, Español, Eesti, Euskara, فارسی, Suomi, Võro, Føroyskt, Français, Arpetan, Furlan, Frysk, Gaeilge, 贛語, Gàidhlig, Galego, Avañe'ẽ, ગુજરાતી, Gaelg, עברית, हिन्दी, Fiji Hindi, Hrvatski, Kreyòl ayisyen, Magyar, Հայերեն, Interlingua, Bahasa Indonesia, Ilokano, Ido, Íslenska, Italiano, 日本語, Lojban, Basa Jawa, ქართული, Kongo, Kalaallisut, ಕನ್ನಡ, 한국어, Къарачай-Малкъар, Ripoarisch, Kurdî, Коми, Kernewek, Кыргызча, Latina, Ladino, Lëtzebuergesch, Limburgs, Lingála, ລາວ, Lietuvių, Latviešu, Basa Banyumasan, Malagasy, Македонски, മലയാളം, मराठी, مازِرونی, Bahasa Melayu, Nnapulitano, Nedersaksisch, नेपाल भाषा, Nederlands, ‪Norsk (nynorsk)‬, ‪Norsk (bokmål)‬, Nouormand, Diné bizaad, Occitan, Иронау, Papiamentu, Deitsch, Polski, پنجابی, پښتو, Norfuk / Pitkern, Português, Runa Simi, Rumantsch, Romani, Română, Русский, Саха тыла, Sardu, Sicilianu, Scots, Sámegiella, Simple English, Slovenčina, Slovenščina, Српски / Srpski, Seeltersk, Svenska, Kiswahili, தமிழ், తెలుగు, Тоҷикӣ, ไทย, Türkmençe, Tagalog, Türkçe, Татарча/Tatarça, Українська, اردو, Tiếng Việt, Volapük, Walon, Winaray, 吴语, isiXhosa, ייִדיש, Yorùbá, Zeêuws, 中文, Bân-lâm-gú, 粵語")
+
+(defparameter *trick-string* (format nil "quote: \" backslash: \\ newline: ~% backspace: ~C ~
+                                          tab: ~T junk: !@#$%&()(&%$#{}{}<><><" #\backspace))
+
+(defconstant *binary-sequence* #(128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127))
+
+(deftest void-test ()
+  (is (null (thrift.test.thrift-test:test-void thrift-cross::*prot*))))
+
+(deftest boolean-test ()
+  (is (thrift.test.thrift-test:test-bool thrift-cross::*prot* t))
+  (is (not (thrift.test.thrift-test:test-bool thrift-cross::*prot* nil))))
+
+(deftest integer-test ()
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 127) 127))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* -128) -128))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 42) 42))
+  (is (= (thrift.test.thrift-test:test-byte thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* 2147483647) 2147483647))
+  (is (= (thrift.test.thrift-test:test-i32 thrift-cross::*prot* -2147483648) -2147483648))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 0) 0))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* 9223372036854775807) 9223372036854775807))
+  (is (= (thrift.test.thrift-test:test-i64 thrift-cross::*prot* -9223372036854775808) -9223372036854775808)))
+
+(deftest double-test ()
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 0.0) 0))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* 42.0) 42))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -555.0) -555))
+  (is (= (thrift.test.thrift-test:test-double thrift-cross::*prot* -52.3678) -52.3678)))
+
+(deftest string-test ()
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "") ""))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* "(defun botsbuildbots () (botsbuilsbots))")
+               "(defun botsbuildbots () (botsbuilsbots))"))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *lang-string*) *lang-string*))
+  (is (string= (thrift.test.thrift-test:test-string thrift-cross::*prot* *trick-string*) *trick-string*)))
+
+(deftest binary-test ()
+  (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* #()) #()))
+  (is (equalp (thrift.test.thrift-test:test-binary thrift-cross::*prot* *binary-sequence*) *binary-sequence*)))
+
+(deftest enum-test ()
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.five) thrift.test:numberz.five))
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.eight) thrift.test:numberz.eight))
+  (is (= (thrift.test.thrift-test:test-enum thrift-cross::*prot* thrift.test:numberz.one) thrift.test:numberz.one)))
+
+(deftest typedef-test ()
+  (is (= (thrift.test.thrift-test:test-typedef thrift-cross::*prot* 309858235082523) 309858235082523)))
+
+(fiasco:define-test-package #:structs)
+
+(in-package #:structs)
+
+(defparameter *test-struct* (thrift.test:make-xtruct :string-thing "Hell is empty."
+                                                     :byte-thing -2
+                                                     :i32-thing 42
+                                                     :i64-thing 42424242))
+
+(defparameter *test-nest* (thrift.test:make-xtruct2 :byte-thing 42
+                                                    :struct-thing *test-struct*
+                                                    :i32-thing -42))
+
+(deftest struct-test ()
+  (let ((rec-struct (thrift.test.thrift-test:test-struct thrift-cross::*prot* *test-struct*)))
+    (is (string= (thrift.test:xtruct-string-thing *test-struct*)
+                 (thrift.test:xtruct-string-thing rec-struct)))
+    (is (= (thrift.test:xtruct-byte-thing *test-struct*)
+           (thrift.test:xtruct-byte-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i32-thing *test-struct*)
+           (thrift.test:xtruct-i32-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i64-thing *test-struct*)
+           (thrift.test:xtruct-i64-thing rec-struct)))))
+
+(deftest nest-test ()
+  (let* ((rec-nest (thrift.test.thrift-test:test-nest thrift-cross::*prot* *test-nest*))
+         (rec-struct (thrift.test:xtruct2-struct-thing rec-nest)))
+    (is (string= (thrift.test:xtruct-string-thing *test-struct*)
+                 (thrift.test:xtruct-string-thing rec-struct)))
+    (is (= (thrift.test:xtruct-byte-thing *test-struct*)
+           (thrift.test:xtruct-byte-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i32-thing *test-struct*)
+           (thrift.test:xtruct-i32-thing rec-struct)))
+    (is (= (thrift.test:xtruct-i64-thing *test-struct*)
+           (thrift.test:xtruct-i64-thing rec-struct)))
+    (is (= (thrift.test:xtruct2-byte-thing *test-nest*)
+           (thrift.test:xtruct2-byte-thing rec-nest)))
+    (is (= (thrift.test:xtruct2-i32-thing *test-nest*)
+           (thrift.test:xtruct2-i32-thing rec-nest)))))
+
+(fiasco:define-test-package #:containers)
+
+(in-package #:containers)
+
+(deftest list-test ()
+  (is (null (thrift.test.thrift-test:test-list thrift-cross::*prot* nil)))
+  (is (equal (thrift.test.thrift-test:test-list thrift-cross::*prot* '(42 -42 0 5)) '(42 -42 0 5))))
+
+(deftest set-test ()
+  (is (null (thrift.test.thrift-test:test-set thrift-cross::*prot* nil)))
+  (is (equal (sort (thrift.test.thrift-test:test-set thrift-cross::*prot* (list 42 -42 0 5)) #'<)
+             '(-42 0 5 42))))
+
+(defun map= (map1 map2 &key (car-predicate #'equal) (cdr-predicate #'equal))
+  "Compare two assoc maps according to the predicates given."
+  (not (set-exclusive-or map1 map2 :test (lambda (el1 el2)
+                                           (and (funcall car-predicate
+                                                         (car el1)
+                                                         (car el2))
+                                                (funcall cdr-predicate
+                                                         (cdr el1)
+                                                         (cdr el2)))))))
+
+(deftest map-test ()
+  (is (null (thrift.test.thrift-test:test-map thrift-cross::*prot* nil)))
+  (is (map= (thrift.test.thrift-test:test-map thrift-cross::*prot* '((0 . 1) (42 . -42) (5 . 5)))
+            '((0 . 1) (42 . -42) (5 . 5))))
+  (is (map= (thrift.test.thrift-test:test-map-map thrift-cross::*prot* 42)
+            '((-4 . ((-4 . -4) (-3 . -3) (-2 . -2) (-1 . -1)))
+              (4 . ((1 . 1) (2 . 2) (3 . 3) (4 . 4))))
+            :cdr-predicate #'map=)))
+
+(fiasco:define-test-package #:exceptions)
+
+(in-package #:exceptions)
+
+(defun test-xception (expected-code expected-message function &rest args)
+  "A helper function to test whether xception is signalled, and whether its fields have the expected values."
+  (handler-case (progn (apply function args)
+                       nil)
+    (thrift.test:xception (ex) (and (= (thrift.test::xception-error-code ex) expected-code)
+                                    (string= (thrift.test::xception-message ex) expected-message)))))
+
+(defun test-xception2 (expected-code expected-message function &rest args)
+  "A helper function to test whether xception2 is signalled, and whether its fields have the expected values."
+  (handler-case (progn (apply function args)
+                       nil)
+    (thrift.test:xception2 (ex) (and (= (thrift.test::xception2-error-code ex) expected-code)
+                                     (string= (thrift.test::xtruct-string-thing
+                                               (thrift.test::xception2-struct-thing ex))
+                                              expected-message)))))
+
+(deftest exception-test ()
+  (is (test-xception 1001 "Xception" #'thrift.test.thrift-test:test-exception thrift-cross::*prot* "Xception"))
+  (signals thrift:application-error (thrift.test.thrift-test:test-exception thrift-cross::*prot* "TException"))
+  (finishes (thrift.test.thrift-test:test-exception thrift-cross::*prot* "success")))
+
+(deftest multi-exception-test ()
+  (is (test-xception 1001
+                     "This is an Xception"
+                     #'thrift.test.thrift-test:test-multi-exception
+                     thrift-cross::*prot*
+                     "Xception"
+                     "meaningless"))
+  (is (test-xception2 2002
+                      "This is an Xception2"
+                      #'thrift.test.thrift-test:test-multi-exception
+                      thrift-cross::*prot*
+                      "Xception2"
+                      "meaningless too!"))
+  (is (string= "foobar" (thrift.test:xtruct-string-thing
+                         (thrift.test.thrift-test:test-multi-exception thrift-cross::*prot*
+                                                           "success!"
+                                                           "foobar")))))
+
+(fiasco:define-test-package #:misc)
+
+(in-package #:misc)
+
+(deftest oneway-test ()
+  (is (null (thrift.test.thrift-test:test-oneway thrift-cross::*prot* 1))))
+
+(fiasco:define-test-package #:multiplex)
+
+(in-package #:multiplex)
+
+(deftest multiplex-test ()
+  ;; Removed from the IDL definition.
+  ;; (finishes (thrift.test.second-service:blah-blah thrift-cross::*prot*))
+  (is (string= "asd" (thrift.test.second-service:secondtest-string thrift-cross::*prot* "asd"))))
diff --git a/test/cpp/CMakeLists.txt b/test/cpp/CMakeLists.txt
index a6c1fd5..f693a27 100644
--- a/test/cpp/CMakeLists.txt
+++ b/test/cpp/CMakeLists.txt
@@ -100,7 +100,7 @@
 #
 
 add_custom_command(OUTPUT gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest.h gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp
-    COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/ThriftTest.thrift
+    COMMAND ${THRIFT_COMPILER} --gen cpp:templates,cob_style -r ${PROJECT_SOURCE_DIR}/test/v0.16/ThriftTest.thrift
 )
 
 add_custom_command(OUTPUT gen-cpp/Service.cpp
diff --git a/test/cpp/Makefile.am b/test/cpp/Makefile.am
index d3754f4..9e8b676 100644
--- a/test/cpp/Makefile.am
+++ b/test/cpp/Makefile.am
@@ -97,7 +97,7 @@
 #
 # Common thrift code generation rules
 #
-gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/ThriftTest.thrift $(THRIFT)
+gen-cpp/ThriftTest.cpp gen-cpp/ThriftTest_types.cpp gen-cpp/ThriftTest_constants.cpp gen-cpp/SecondService.cpp gen-cpp/SecondService.h gen-cpp/SecondService.tcc: $(top_srcdir)/test/v0.16/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen cpp:templates,cob_style -r $<
 
 gen-cpp/Service.cpp: $(top_srcdir)/test/StressTest.thrift $(THRIFT)
diff --git a/test/crossrunner/util.py b/test/crossrunner/util.py
index c214df8..8511f58 100644
--- a/test/crossrunner/util.py
+++ b/test/crossrunner/util.py
@@ -21,7 +21,7 @@
 
 
 def domain_socket_path(port):
-    return '/tmp/ThriftTest.thrift.%d' % port
+    return '/tmp/v0.16/ThriftTest.thrift.%d' % port
 
 
 def merge_dict(base, update):
diff --git a/test/dart/Makefile.am b/test/dart/Makefile.am
index 27fdc09..81f2f5b 100644
--- a/test/dart/Makefile.am
+++ b/test/dart/Makefile.am
@@ -17,8 +17,8 @@
 # under the License.
 #
 
-gen-dart/thrift_test/lib/thrift_test.dart: ../ThriftTest.thrift
-	$(THRIFT) --gen dart ../ThriftTest.thrift
+gen-dart/thrift_test/lib/thrift_test.dart: ../v0.16/ThriftTest.thrift
+	$(THRIFT) --gen dart ../v0.16/ThriftTest.thrift
 
 pub-get-gen: gen-dart/thrift_test/lib/thrift_test.dart
 	cd gen-dart/thrift_test; ${DARTPUB} get
diff --git a/test/dart/test_client/pubspec.yaml b/test/dart/test_client/pubspec.yaml
index 2898169..3ce1544 100644
--- a/test/dart/test_client/pubspec.yaml
+++ b/test/dart/test_client/pubspec.yaml
@@ -16,7 +16,7 @@
 # under the License.
 
 name: thrift_test_client
-version: 0.17.0
+version: 0.18.0
 description: A client integration test for the Dart Thrift library
 author: Apache Thrift Developers <dev@thrift.apache.org>
 homepage: http://thrift.apache.org
diff --git a/test/erl/Makefile.am b/test/erl/Makefile.am
index 145a763..5bc90fa 100644
--- a/test/erl/Makefile.am
+++ b/test/erl/Makefile.am
@@ -25,7 +25,7 @@
 	for f in $(THRIFT_FILES) ; do \
 	  $(THRIFT) --gen $(ERL_FLAG) -o src $$f ; \
 	done ; \
-	$(THRIFT) --gen $(ERL_FLAG) -o src ../ThriftTest.thrift
+	$(THRIFT) --gen $(ERL_FLAG) -o src ../v0.16/ThriftTest.thrift
 	touch .generated
 
 precross: .generated
diff --git a/test/erl/src/thrift_test.app.src b/test/erl/src/thrift_test.app.src
index 60f7f14..e94e36d 100644
--- a/test/erl/src/thrift_test.app.src
+++ b/test/erl/src/thrift_test.app.src
@@ -22,7 +22,7 @@
   {description, "Thrift cross language test"},
 
   % The version of the applicaton
-  {vsn, "0.17.0"},
+  {vsn, "0.18.0"},
 
   % All modules used by the application.
   {modules, [
diff --git a/test/go/Makefile.am b/test/go/Makefile.am
index ef00df3..32c2be0 100644
--- a/test/go/Makefile.am
+++ b/test/go/Makefile.am
@@ -26,7 +26,7 @@
 endif
 
 THRIFTCMD = $(THRIFT) -out src/gen --gen go:thrift_import=github.com/apache/thrift/lib/go/thrift,package_prefix=github.com/apache/thrift/test/go/src/gen/$(COMPILER_EXTRAFLAG)
-THRIFTTEST = $(top_srcdir)/test/ThriftTest.thrift
+THRIFTTEST = $(top_srcdir)/test/v0.16/ThriftTest.thrift
 
 precross: bin/testclient bin/testserver
 
diff --git a/test/haxe/TestClientServer.hxproj b/test/haxe/TestClientServer.hxproj
index 30fecf3..6750415 100644
--- a/test/haxe/TestClientServer.hxproj
+++ b/test/haxe/TestClientServer.hxproj
@@ -8,9 +8,9 @@
     <movie fps="30" />
     <movie width="800" />
     <movie height="600" />
-    <movie version="1" />
+    <movie version="0" />
     <movie minorVersion="0" />
-    <movie platform="C++" />
+    <movie platform="C#" />
     <movie background="#FFFFFF" />
   </output>
   <!-- Other classes to be compiled into your SWF -->
@@ -30,7 +30,7 @@
   </build>
   <!-- haxelib libraries -->
   <haxelib>
-    <!-- example: <library name="..." /> -->
+    <library name="uuid" />
   </haxelib>
   <!-- Class files to compile (other referenced classes will automatically be included) -->
   <compileTargets>
diff --git a/test/haxe/cpp.hxml b/test/haxe/cpp.hxml
index 6adb52d..1b581a9 100644
--- a/test/haxe/cpp.hxml
+++ b/test/haxe/cpp.hxml
@@ -31,11 +31,11 @@
 #To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
 #-D HXCPP_M64
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/csharp.hxml b/test/haxe/csharp.hxml
index 295c017..8dd891c 100644
--- a/test/haxe/csharp.hxml
+++ b/test/haxe/csharp.hxml
@@ -26,13 +26,13 @@
 -main Main
 
 #CSHARP target
--cs bin/Tutorial.exe
+-cs bin/ThriftTest.exe
+
+# libs
+-lib uuid
 
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/flash.hxml b/test/haxe/flash.hxml
index a1f0568..e60515e 100644
--- a/test/haxe/flash.hxml
+++ b/test/haxe/flash.hxml
@@ -26,7 +26,10 @@
 -main Main
 
 #Flash target
--swf bin/Tutorial.swf
+-swf bin/ThriftTest.swf
+
+# libs
+-lib uuid
 
 #Add debug information
 -debug
@@ -35,7 +38,4 @@
 # --macro allowPackage("sys")
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/java.hxml b/test/haxe/java.hxml
index c615565..807a92a 100644
--- a/test/haxe/java.hxml
+++ b/test/haxe/java.hxml
@@ -26,13 +26,13 @@
 -main Main
 
 #Java target
--java bin/Tutorial.jar
+-java bin/ThriftTest.jar
+
+# libs
+-lib uuid
 
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/javascript.hxml b/test/haxe/javascript.hxml
index b2b3876..892e84b 100644
--- a/test/haxe/javascript.hxml
+++ b/test/haxe/javascript.hxml
@@ -26,7 +26,7 @@
 -main Main
 
 #JavaScript target
--js bin/Tutorial.js
+-js bin/ThriftTest.js
 
 #You can use -D source-map-content (requires Haxe 3.1+) to have the .hx 
 #files directly embedded into the map file, this way you only have to 
@@ -34,11 +34,11 @@
 #you modify your .hx files.
 -D source-map-content
 
+# libs
+-lib uuid
+
 #Generate source map and add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/neko.hxml b/test/haxe/neko.hxml
index 6161f69..20c1ea6 100644
--- a/test/haxe/neko.hxml
+++ b/test/haxe/neko.hxml
@@ -26,13 +26,13 @@
 -main Main
 
 #neko target
--neko bin/Tutorial.n
+-neko bin/ThriftTest.n
+
+# libs
+-lib uuid
 
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/php-web-server.hxml b/test/haxe/php-web-server.hxml
index 102ae97..4c121fb 100644
--- a/test/haxe/php-web-server.hxml
+++ b/test/haxe/php-web-server.hxml
@@ -39,7 +39,4 @@
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
diff --git a/test/haxe/php.hxml b/test/haxe/php.hxml
index 4edb86c..6d44227 100644
--- a/test/haxe/php.hxml
+++ b/test/haxe/php.hxml
@@ -36,7 +36,4 @@
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
diff --git a/test/haxe/python.hxml b/test/haxe/python.hxml
index f2c19fa..0079fdb 100644
--- a/test/haxe/python.hxml
+++ b/test/haxe/python.hxml
@@ -26,13 +26,13 @@
 -main Main
 
 #Python target
--python bin/Tutorial.py
+-python bin/ThriftTest.py
+
+# libs
+-lib uuid
 
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/test/haxe/src/TestClient.hx b/test/haxe/src/TestClient.hx
index 579dc00..3a07562 100644
--- a/test/haxe/src/TestClient.hx
+++ b/test/haxe/src/TestClient.hx
@@ -27,6 +27,8 @@
 import haxe.ds.StringMap;
 import haxe.ds.ObjectMap;
 
+import uuid.Uuid;
+
 import org.apache.thrift.*;
 import org.apache.thrift.helper.*;
 import org.apache.thrift.protocol.*;
@@ -366,6 +368,14 @@
             rslt.Expect( false, 'ZigZag.UnitTest: $e  Test #101');
         }
 
+        try {
+            UuidHelper.UnitTest();
+            rslt.Expect( true, 'UuidHelper.UnitTest  Test #102');
+        }
+        catch( e : Dynamic) {
+            rslt.Expect( false, 'UuidHelper.UnitTest: $e  Test #102');
+        }
+
         #end
     }
 
@@ -537,6 +547,19 @@
         trace(' = $dub');
         rslt.Expect(dub == 5.325098235, '$dub == 5.325098235');
 
+
+		var uuidOut : String = UuidHelper.CanonicalUuid("{00112233-4455-6677-8899-AABBCCDDEEFF}");
+        trace('testUuid(${uuidOut}');
+        try {
+            var uuidIn = client.testUuid(uuidOut);
+            trace('testUuid() = ${uuidIn}');
+            rslt.Expect( uuidIn == uuidOut, '${uuidIn} == ${uuidOut}');
+        }
+        catch (e : TApplicationException) {
+            trace('testUuid(${uuidOut}): '+e.errorMsg);  // may not be supported by the server
+        }
+
+        
         var binOut = PrepareTestData(true);
         trace('testBinary('+BytesToHex(binOut)+')');
         try {
diff --git a/test/haxe/src/TestServerHandler.hx b/test/haxe/src/TestServerHandler.hx
index 0e19105..34e471b 100644
--- a/test/haxe/src/TestServerHandler.hx
+++ b/test/haxe/src/TestServerHandler.hx
@@ -25,6 +25,7 @@
 import org.apache.thrift.server.*;
 import org.apache.thrift.meta_data.*;
 import org.apache.thrift.helper.*;
+import uuid.Uuid;
 
 import haxe.Int32;
 import haxe.Int64;
@@ -147,6 +148,19 @@
     }
 
     /**
+     * Prints 'testUuid("%s")' 
+     * @param Uuid  thing - the uuid to print
+     * @return Uuid  - returns the uuid 'thing'
+     *
+     * @param thing
+     */
+    public function testUuid(thing : String) : String
+    {
+        trace('testUuid($thing)');
+        return thing;
+    }
+
+    /**
     * Prints 'testStruct("{%s}")' where thing has been formatted
     *  into a string of comma separated values
     * @param Xtruct thing - the Xtruct to print
diff --git a/test/lua/Makefile.am b/test/lua/Makefile.am
index b2683e1..a3ab3e2 100644
--- a/test/lua/Makefile.am
+++ b/test/lua/Makefile.am
@@ -20,7 +20,7 @@
 THRIFT = $(top_builddir)/compiler/cpp/thrift
 
 # Remove "MapType =" line to ignore some map bug for now
-stubs: ../ThriftTest.thrift $(THRIFT)
+stubs: ../v0.16/ThriftTest.thrift $(THRIFT)
 	$(THRIFT) --gen lua $<
 	$(SED) -i.bak 's/MapType =//g' gen-lua/ThriftTest_ttypes.lua
 	$(RM) gen-lua/ThriftTest_ttypes.lua.bak
diff --git a/test/netstd/Client/Client.csproj b/test/netstd/Client/Client.csproj
index 9d4ab48..2373e40 100644
--- a/test/netstd/Client/Client.csproj
+++ b/test/netstd/Client/Client.csproj
@@ -24,7 +24,7 @@
     <AssemblyName>Client</AssemblyName>
     <PackageId>Client</PackageId>
     <OutputType>Exe</OutputType>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
     <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
diff --git a/test/netstd/Client/TestClient.cs b/test/netstd/Client/TestClient.cs
index 29c0d2e..1227a38 100644
--- a/test/netstd/Client/TestClient.cs
+++ b/test/netstd/Client/TestClient.cs
@@ -407,7 +407,7 @@
                 {
                     Console.WriteLine("*** FAILED ***");
                     Console.WriteLine("Error while parsing arguments");
-                    Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
+                    Console.WriteLine("{0} {1}\nStack:\n{2}", ex.GetType().Name, ex.Message, ex.StackTrace);
                     return ErrorUnknown;
                 }
 
@@ -588,8 +588,28 @@
                 returnCode |= ErrorBaseTypes;
             }
 
+            // testUuid()
+            var uuidOut = new Guid("{00112233-4455-6677-8899-AABBCCDDEEFF}");
+            Console.Write("testUuid({0})", uuidOut);
+            try
+            {
+                var uuidIn = await client.testUuid(uuidOut, MakeTimeoutToken());
+                Console.WriteLine(" = {0}", uuidIn);
+                if (!uuidIn.Equals(uuidOut))
+                {
+                    Console.WriteLine("*** FAILED ***");
+                    returnCode |= ErrorBaseTypes;
+                }
+            }
+            catch (Thrift.TApplicationException ex)
+            {
+                Console.WriteLine("*** FAILED ***");
+                returnCode |= ErrorBaseTypes;
+                Console.WriteLine(ex.Message + "\n" + ex.StackTrace);
+            }
+
             // testBinary()
-            foreach(BinaryTestSize binTestCase in Enum.GetValues(typeof(BinaryTestSize)))
+            foreach (BinaryTestSize binTestCase in Enum.GetValues(typeof(BinaryTestSize)))
             {
                 var binOut = PrepareTestData(true, binTestCase);
 
diff --git a/test/netstd/Server/Server.csproj b/test/netstd/Server/Server.csproj
index 439e5c1..0a78e88 100644
--- a/test/netstd/Server/Server.csproj
+++ b/test/netstd/Server/Server.csproj
@@ -1,4 +1,4 @@
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
   <!--
     Licensed to the Apache Software Foundation(ASF) under one
     or more contributor license agreements.See the NOTICE file
@@ -24,7 +24,7 @@
     <AssemblyName>Server</AssemblyName>
     <PackageId>Server</PackageId>
     <OutputType>Exe</OutputType>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <GenerateAssemblyTitleAttribute>false</GenerateAssemblyTitleAttribute>
     <GenerateAssemblyDescriptionAttribute>false</GenerateAssemblyDescriptionAttribute>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
diff --git a/test/netstd/Server/TestServer.cs b/test/netstd/Server/TestServer.cs
index 86072b0..1eb5030 100644
--- a/test/netstd/Server/TestServer.cs
+++ b/test/netstd/Server/TestServer.cs
@@ -204,7 +204,6 @@
         {
             //public TServer Server { get; set; }
             private readonly int handlerID;
-            private readonly StringBuilder sb = new();
             private readonly TestLogDelegate logger;
 
             public TestHandlerAsync()
@@ -216,11 +215,12 @@
 
             public void TestConsoleLogger(string msg, params object[] values)
             {
-                sb.Clear();
+                var sb = new StringBuilder();
                 sb.AppendFormat("handler{0:D3}:", handlerID);
                 sb.AppendFormat(msg, values);
                 sb.AppendLine();
-                Console.Write(sb.ToString());
+                lock (typeof(Console))
+                    Console.Write(sb.ToString());
             }
 
             public Task testVoid(CancellationToken cancellationToken)
@@ -271,6 +271,12 @@
                 return Task.FromResult(thing ?? Array.Empty<byte>());
             }
 
+            public Task<Guid> testUuid(Guid thing, CancellationToken cancellationToken)
+            {
+                logger.Invoke("testUuid({0})", thing.ToString("B"));
+                return Task.FromResult(thing);
+            }
+
             public Task<Xtruct> testStruct(Xtruct? thing, CancellationToken cancellationToken)
             {
                 logger.Invoke("testStruct({{\"{0}\", {1}, {2}, {3}}})", thing?.String_thing ?? "<null>", thing?.Byte_thing ?? 0, thing?.I32_thing ?? 0, thing?.I64_thing ?? 0);
@@ -292,7 +298,7 @@
 
             public Task<Dictionary<int, int>> testMap(Dictionary<int, int>? thing, CancellationToken cancellationToken)
             {
-                sb.Clear();
+                var sb = new StringBuilder();
                 sb.Append("testMap({{");
                 if (thing != null)
                 {
@@ -317,7 +323,7 @@
 
             public Task<Dictionary<string, string>> testStringMap(Dictionary<string, string>? thing, CancellationToken cancellationToken)
             {
-                sb.Clear();
+                var sb = new StringBuilder();
                 sb.Append("testStringMap({{");
                 if (thing != null)
                 {
@@ -342,7 +348,7 @@
 
             public Task<HashSet<int>> testSet(HashSet<int>? thing, CancellationToken cancellationToken)
             {
-                sb.Clear();
+                var sb = new StringBuilder();
                 sb.Append("testSet({{");
                 if (thing != null)
                 {
@@ -367,7 +373,7 @@
 
             public Task<List<int>> testList(List<int>? thing, CancellationToken cancellationToken)
             {
-                sb.Clear();
+                var sb = new StringBuilder();
                 sb.Append("testList({{");
                 if (thing != null)
                 {
@@ -573,7 +579,7 @@
                     {
                         Console.WriteLine("*** FAILED ***");
                         Console.WriteLine("Error while  parsing arguments");
-                        Console.WriteLine(ex.Message + " ST: " + ex.StackTrace);
+                        Console.WriteLine("{0} {1}\nStack:\n{2}", ex.GetType().Name, ex.Message, ex.StackTrace);
                         return 1;
                     }
 
@@ -584,7 +590,8 @@
                     {
                         case TransportChoice.NamedPipe:
                             Debug.Assert(param.pipe != null);
-                            trans = new TNamedPipeServerTransport(param.pipe, Configuration, NamedPipeClientFlags.OnlyLocalClients);
+                            var numListen = (param.server == ServerChoice.Simple) ? 1 : 16;
+                            trans = new TNamedPipeServerTransport(param.pipe, Configuration, NamedPipeServerFlags.OnlyLocalClients, numListen);
                             break;
 
 
diff --git a/test/perl/Makefile.am b/test/perl/Makefile.am
index 1dbaf28..589fe62 100644
--- a/test/perl/Makefile.am
+++ b/test/perl/Makefile.am
@@ -17,8 +17,8 @@
 # under the License.
 #
 
-stubs: ../ThriftTest.thrift
-	$(THRIFT) --gen perl ../ThriftTest.thrift
+stubs: ../v0.16/ThriftTest.thrift
+	$(THRIFT) --gen perl ../v0.16/ThriftTest.thrift
 
 precross: stubs
 
diff --git a/test/php/Makefile.am b/test/php/Makefile.am
index 9e13aff..b1ac686 100644
--- a/test/php/Makefile.am
+++ b/test/php/Makefile.am
@@ -17,11 +17,11 @@
 # under the License.
 #
 
-stubs: ../ThriftTest.thrift
-	$(THRIFT) --gen php ../ThriftTest.thrift
-	$(THRIFT) --gen php:inlined ../ThriftTest.thrift
+stubs: ../v0.16/ThriftTest.thrift
+	$(THRIFT) --gen php ../v0.16/ThriftTest.thrift
+	$(THRIFT) --gen php:inlined ../v0.16/ThriftTest.thrift
 	$(MKDIR_P) gen-php-classmap
-	$(THRIFT) -out gen-php-classmap --gen php:classmap ../ThriftTest.thrift
+	$(THRIFT) -out gen-php-classmap --gen php:classmap ../v0.16/ThriftTest.thrift
 
 php_ext_dir:
 	mkdir -p php_ext_dir
diff --git a/test/py.tornado/Makefile.am b/test/py.tornado/Makefile.am
index e962f0c..3b78793 100644
--- a/test/py.tornado/Makefile.am
+++ b/test/py.tornado/Makefile.am
@@ -19,8 +19,8 @@
 
 THRIFT = $(top_srcdir)/compiler/cpp/thrift
 
-thrift_gen: ../ThriftTest.thrift ../SmallTest.thrift
-	$(THRIFT) --gen py:tornado ../ThriftTest.thrift
+thrift_gen: ../v0.16/ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:tornado ../v0.16/ThriftTest.thrift
 	$(THRIFT) --gen py:tornado ../SmallTest.thrift
 
 check: thrift_gen
diff --git a/test/py.twisted/Makefile.am b/test/py.twisted/Makefile.am
index dee8e2f..bd0cdb1 100644
--- a/test/py.twisted/Makefile.am
+++ b/test/py.twisted/Makefile.am
@@ -19,8 +19,8 @@
 
 TRIAL ?= trial
 
-stubs: ../ThriftTest.thrift ../SmallTest.thrift
-	$(THRIFT) --gen py:twisted ../ThriftTest.thrift
+stubs: ../v0.16/ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen py:twisted ../v0.16/ThriftTest.thrift
 	$(THRIFT) --gen py:twisted ../SmallTest.thrift
 
 check: stubs
diff --git a/test/py/Makefile.am b/test/py/Makefile.am
index 57529d7..7c78f17 100644
--- a/test/py/Makefile.am
+++ b/test/py/Makefile.am
@@ -71,35 +71,51 @@
 
 
 gen-py/%/__init__.py: ../%.thrift $(THRIFT)
-	$(THRIFT) --gen py  $<
+	test -f ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py  ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py  $<
 
 gen-py-default/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-default || $(MKDIR_P) gen-py-default
-	$(THRIFT) --gen py -out gen-py-default $<
+	test -f ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py -out gen-py-default ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py -out gen-py-default $<
 
 gen-py-slots/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-slots || $(MKDIR_P) gen-py-slots
-	$(THRIFT) --gen py:slots -out gen-py-slots $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:slots -out gen-py-slots ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:slots -out gen-py-slots $<
 
 gen-py-oldstyle/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-oldstyle || $(MKDIR_P) gen-py-oldstyle
-	$(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:old_style -out gen-py-oldstyle ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:old_style -out gen-py-oldstyle $<
 
 gen-py-no_utf8strings/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-no_utf8strings || $(MKDIR_P) gen-py-no_utf8strings
-	$(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:no_utf8strings -out gen-py-no_utf8strings $<
 
 gen-py-dynamic/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-dynamic || $(MKDIR_P) gen-py-dynamic
-	$(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:dynamic -out gen-py-dynamic ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:dynamic -out gen-py-dynamic $<
 
 gen-py-dynamicslots/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-dynamicslots || $(MKDIR_P) gen-py-dynamicslots
-	$(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:dynamic,slots -out gen-py-dynamicslots $<
 
 gen-py-enum/%/__init__.py: ../%.thrift $(THRIFT)
 	test -d gen-py-enum || $(MKDIR_P) gen-py-enum
-	$(THRIFT) --gen py:enum -out gen-py-enum $<
+	test ../v0.16/$(notdir $<) \
+	&& $(THRIFT) --gen py:enum -out gen-py-enum ../v0.16/$(notdir $<) \
+	|| $(THRIFT) --gen py:enum -out gen-py-enum $<
 
 clean-local:
 	$(RM) -r build
diff --git a/test/py/generate.cmake b/test/py/generate.cmake
index e6a6735..eb6f111 100644
--- a/test/py/generate.cmake
+++ b/test/py/generate.cmake
@@ -7,21 +7,21 @@
   endif()
 endmacro(GENERATE)
 
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py gen-py-default)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:slots gen-py-slots)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:old_style gen-py-oldstyle)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:no_utf8strings gen-py-no_utf8strings)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic gen-py-dynamic)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:dynamic,slots gen-py-dynamicslots)
-generate(${MY_PROJECT_DIR}/test/ThriftTest.thrift py:enum gen-py-enum)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:dynamic,slots gen-py-dynamicslots)
+generate(${MY_PROJECT_DIR}/test/v0.16/ThriftTest.thrift py:enum gen-py-enum)
 
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py gen-py-default)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:slots gen-py-slots)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:old_style gen-py-oldstyle)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:no_utf8strings gen-py-no_utf8strings)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)
-generate(${MY_PROJECT_DIR}/test/DebugProtoTest.thrift py:enum gen-py-enum)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py gen-py-default)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:slots gen-py-slots)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:old_style gen-py-oldstyle)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:no_utf8strings gen-py-no_utf8strings)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:dynamic gen-py-dynamic)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:dynamic,slots gen-py-dynamicslots)
+generate(${MY_PROJECT_DIR}/test/v0.16/DebugProtoTest.thrift py:enum gen-py-enum)
 
 generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py gen-py-default)
 generate(${MY_PROJECT_DIR}/test/DoubleConstantsTest.thrift py:slots gen-py-slots)
diff --git a/test/rb/Makefile.am b/test/rb/Makefile.am
index 3910934..5dd7559 100644
--- a/test/rb/Makefile.am
+++ b/test/rb/Makefile.am
@@ -17,8 +17,8 @@
 # under the License.
 #
 
-stubs: $(THRIFT) ../ThriftTest.thrift ../SmallTest.thrift
-	$(THRIFT) --gen rb ../ThriftTest.thrift
+stubs: $(THRIFT) ../v0.16/ThriftTest.thrift ../SmallTest.thrift
+	$(THRIFT) --gen rb ../v0.16/ThriftTest.thrift
 	$(THRIFT) --gen rb ../SmallTest.thrift
 	$(THRIFT) --gen rb ../Recursive.thrift
 
diff --git a/test/rs/Cargo.toml b/test/rs/Cargo.toml
index 401282a..b039fff 100644
--- a/test/rs/Cargo.toml
+++ b/test/rs/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "thrift-test"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 license = "Apache-2.0"
 authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
 publish = false
diff --git a/test/rs/Makefile.am b/test/rs/Makefile.am
index 78db5ee..103f80c 100644
--- a/test/rs/Makefile.am
+++ b/test/rs/Makefile.am
@@ -17,8 +17,8 @@
 # under the License.
 #
 
-stubs: ../ThriftTest.thrift
-	$(THRIFT) -I ./thrifts -out src --gen rs ../ThriftTest.thrift
+stubs: ../v0.16/ThriftTest.thrift
+	$(THRIFT) -I ./thrifts -out src --gen rs ../v0.16/ThriftTest.thrift
 
 precross: stubs
 	$(CARGO) build
diff --git a/test/rs/src/bin/test_client.rs b/test/rs/src/bin/test_client.rs
index 8274aae..a44bac3 100644
--- a/test/rs/src/bin/test_client.rs
+++ b/test/rs/src/bin/test_client.rs
@@ -16,7 +16,6 @@
 // under the License.
 
 use clap::{clap_app, value_t};
-use env_logger;
 use log::*;
 
 use std::collections::{BTreeMap, BTreeSet};
@@ -28,7 +27,6 @@
 #[cfg(unix)]
 use std::path::Path;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocol, TBinaryOutputProtocol, TCompactInputProtocol, TCompactOutputProtocol,
     TInputProtocol, TMultiplexedOutputProtocol, TOutputProtocol,
@@ -346,60 +344,44 @@
 
     info!("testList");
     {
-        let mut v_snd: Vec<i32> = Vec::new();
-        v_snd.push(29384);
-        v_snd.push(238);
-        v_snd.push(32498);
+        let v_snd: Vec<i32> = vec![29384, 238, 32498];
 
-        let mut v_cmp: Vec<i32> = Vec::new();
-        v_cmp.push(29384);
-        v_cmp.push(238);
-        v_cmp.push(32498);
+        let v_cmp: Vec<i32> = vec![29384, 238, 32498];
 
         verify_expected_result(thrift_test_client.test_list(v_snd), v_cmp)?;
     }
 
     info!("testSet");
     {
-        let mut s_snd: BTreeSet<i32> = BTreeSet::new();
-        s_snd.insert(293_481);
-        s_snd.insert(23);
-        s_snd.insert(3234);
+        let s_snd: BTreeSet<i32> = BTreeSet::from([293_481, 23, 3234]);
 
-        let mut s_cmp: BTreeSet<i32> = BTreeSet::new();
-        s_cmp.insert(293_481);
-        s_cmp.insert(23);
-        s_cmp.insert(3234);
+        let s_cmp: BTreeSet<i32> = BTreeSet::from([293_481, 23, 3234]);
 
         verify_expected_result(thrift_test_client.test_set(s_snd), s_cmp)?;
     }
 
     info!("testMap");
     {
-        let mut m_snd: BTreeMap<i32, i32> = BTreeMap::new();
-        m_snd.insert(2, 4);
-        m_snd.insert(4, 6);
-        m_snd.insert(8, 7);
+        let m_snd: BTreeMap<i32, i32> = BTreeMap::from([(2, 4), (4, 6), (8, 7)]);
 
-        let mut m_cmp: BTreeMap<i32, i32> = BTreeMap::new();
-        m_cmp.insert(2, 4);
-        m_cmp.insert(4, 6);
-        m_cmp.insert(8, 7);
+        let m_cmp: BTreeMap<i32, i32> = BTreeMap::from([(2, 4), (4, 6), (8, 7)]);
 
         verify_expected_result(thrift_test_client.test_map(m_snd), m_cmp)?;
     }
 
     info!("testStringMap");
     {
-        let mut m_snd: BTreeMap<String, String> = BTreeMap::new();
-        m_snd.insert("2".to_owned(), "4_string".to_owned());
-        m_snd.insert("4".to_owned(), "6_string".to_owned());
-        m_snd.insert("8".to_owned(), "7_string".to_owned());
+        let m_snd: BTreeMap<String, String> = BTreeMap::from([
+            ("2".to_owned(), "4_string".to_owned()),
+            ("4".to_owned(), "6_string".to_owned()),
+            ("8".to_owned(), "7_string".to_owned()),
+        ]);
 
-        let mut m_rcv: BTreeMap<String, String> = BTreeMap::new();
-        m_rcv.insert("2".to_owned(), "4_string".to_owned());
-        m_rcv.insert("4".to_owned(), "6_string".to_owned());
-        m_rcv.insert("8".to_owned(), "7_string".to_owned());
+        let m_rcv: BTreeMap<String, String> = BTreeMap::from([
+            ("2".to_owned(), "4_string".to_owned()),
+            ("4".to_owned(), "6_string".to_owned()),
+            ("8".to_owned(), "7_string".to_owned()),
+        ]);
 
         verify_expected_result(thrift_test_client.test_string_map(m_snd), m_rcv)?;
     }
@@ -409,27 +391,19 @@
     // => 2, 3 => 3, 4 => 4, }, }
     info!("testMapMap");
     {
-        let mut m_cmp_nested_0: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in (-4 as i32)..0 {
-            m_cmp_nested_0.insert(i, i);
-        }
-        let mut m_cmp_nested_1: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in 1..5 {
-            m_cmp_nested_1.insert(i, i);
-        }
+        let m_cmp_nested_0: BTreeMap<i32, i32> = (-4..0).map(|i| (i, i)).collect();
+        let m_cmp_nested_1: BTreeMap<i32, i32> = (1..5).map(|i| (i, i)).collect();
 
-        let mut m_cmp: BTreeMap<i32, BTreeMap<i32, i32>> = BTreeMap::new();
-        m_cmp.insert(-4, m_cmp_nested_0);
-        m_cmp.insert(4, m_cmp_nested_1);
+        let m_cmp: BTreeMap<i32, BTreeMap<i32, i32>> =
+            BTreeMap::from([(-4, m_cmp_nested_0), (4, m_cmp_nested_1)]);
 
         verify_expected_result(thrift_test_client.test_map_map(42), m_cmp)?;
     }
 
     info!("testMulti");
     {
-        let mut m_snd: BTreeMap<i16, String> = BTreeMap::new();
-        m_snd.insert(1298, "fizz".to_owned());
-        m_snd.insert(-148, "buzz".to_owned());
+        let m_snd: BTreeMap<i16, String> =
+            BTreeMap::from([(1298, "fizz".to_owned()), (-148, "buzz".to_owned())]);
 
         let s_cmp = Xtruct {
             string_thing: Some("Hello2".to_owned()),
@@ -452,48 +426,48 @@
     //   2 => { 6 => <empty Insanity struct>, },
     // }
     {
-        let mut arg_map_usermap: BTreeMap<Numberz, i64> = BTreeMap::new();
-        arg_map_usermap.insert(Numberz::ONE, 4289);
-        arg_map_usermap.insert(Numberz::EIGHT, 19);
+        let arg_map_usermap: BTreeMap<Numberz, i64> =
+            BTreeMap::from([(Numberz::ONE, 4289), (Numberz::EIGHT, 19)]);
 
-        let mut arg_vec_xtructs: Vec<Xtruct> = Vec::new();
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("foo".to_owned()),
-            byte_thing: Some(8),
-            i32_thing: Some(29),
-            i64_thing: Some(92384),
-        });
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("bar".to_owned()),
-            byte_thing: Some(28),
-            i32_thing: Some(2),
-            i64_thing: Some(-1281),
-        });
-        arg_vec_xtructs.push(Xtruct {
-            string_thing: Some("baz".to_owned()),
-            byte_thing: Some(0),
-            i32_thing: Some(3_948_539),
-            i64_thing: Some(-12_938_492),
-        });
+        let arg_vec_xtructs: Vec<Xtruct> = vec![
+            Xtruct {
+                string_thing: Some("foo".to_owned()),
+                byte_thing: Some(8),
+                i32_thing: Some(29),
+                i64_thing: Some(92384),
+            },
+            Xtruct {
+                string_thing: Some("bar".to_owned()),
+                byte_thing: Some(28),
+                i32_thing: Some(2),
+                i64_thing: Some(-1281),
+            },
+            Xtruct {
+                string_thing: Some("baz".to_owned()),
+                byte_thing: Some(0),
+                i32_thing: Some(3_948_539),
+                i64_thing: Some(-12_938_492),
+            },
+        ];
 
-        let mut s_cmp_nested_1: BTreeMap<Numberz, Insanity> = BTreeMap::new();
         let insanity = Insanity {
             user_map: Some(arg_map_usermap),
             xtructs: Some(arg_vec_xtructs),
         };
-        s_cmp_nested_1.insert(Numberz::TWO, insanity.clone());
-        s_cmp_nested_1.insert(Numberz::THREE, insanity.clone());
+        let s_cmp_nested_1: BTreeMap<Numberz, Insanity> = BTreeMap::from([
+            (Numberz::TWO, insanity.clone()),
+            (Numberz::THREE, insanity.clone()),
+        ]);
 
-        let mut s_cmp_nested_2: BTreeMap<Numberz, Insanity> = BTreeMap::new();
         let empty_insanity = Insanity {
             user_map: Some(BTreeMap::new()),
             xtructs: Some(Vec::new()),
         };
-        s_cmp_nested_2.insert(Numberz::SIX, empty_insanity);
+        let s_cmp_nested_2: BTreeMap<Numberz, Insanity> =
+            BTreeMap::from([(Numberz::SIX, empty_insanity)]);
 
-        let mut s_cmp: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> = BTreeMap::new();
-        s_cmp.insert(1 as UserId, s_cmp_nested_1);
-        s_cmp.insert(2 as UserId, s_cmp_nested_2);
+        let s_cmp: BTreeMap<UserId, BTreeMap<Numberz, Insanity>> =
+            BTreeMap::from([(1, s_cmp_nested_1), (2, s_cmp_nested_2)]);
 
         verify_expected_result(thrift_test_client.test_insanity(insanity), s_cmp)?;
     }
diff --git a/test/rs/src/bin/test_server.rs b/test/rs/src/bin/test_server.rs
index 7e6d08f..92a4bcc 100644
--- a/test/rs/src/bin/test_server.rs
+++ b/test/rs/src/bin/test_server.rs
@@ -16,14 +16,12 @@
 // under the License.
 
 use clap::{clap_app, value_t};
-use env_logger;
 use log::*;
 
 use std::collections::{BTreeMap, BTreeSet};
 use std::thread;
 use std::time::Duration;
 
-use thrift;
 use thrift::protocol::{
     TBinaryInputProtocolFactory, TBinaryOutputProtocolFactory, TCompactInputProtocolFactory,
     TCompactOutputProtocolFactory, TInputProtocolFactory, TOutputProtocolFactory,
@@ -256,7 +254,7 @@
         info!("testMapMap({})", hello);
 
         let mut inner_map_0: BTreeMap<i32, i32> = BTreeMap::new();
-        for i in -4..(0 as i32) {
+        for i in -4..0_i32 {
             inner_map_0.insert(i, i);
         }
 
diff --git a/test/rs/src/lib.rs b/test/rs/src/lib.rs
index 9cfd7a6..7c53620 100644
--- a/test/rs/src/lib.rs
+++ b/test/rs/src/lib.rs
@@ -15,5 +15,11 @@
 // specific language governing permissions and limitations
 // under the License.
 
+// FIXME - need changes in gen before lifting this exception
+#![allow(
+    clippy::match_single_binding,
+    clippy::unnecessary_wraps,
+    clippy::derivable_impls
+)]
 mod thrift_test;
 pub use crate::thrift_test::*;
diff --git a/test/v0.16/ConstantsDemo.thrift b/test/v0.16/ConstantsDemo.thrift
new file mode 100644
index 0000000..204e805
--- /dev/null
+++ b/test/v0.16/ConstantsDemo.thrift
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+namespace cpp yozone
+namespace erl consts_
+namespace haxe constantsDemo
+
+struct thing {
+  1: i32 hello,
+  2: i32 goodbye
+}
+
+enum enumconstants {
+  ONE = 1,
+  TWO = 2
+}
+
+// struct thing2 {
+//   /** standard docstring */
+//   1: enumconstants val = TWO
+// }
+
+typedef i32 myIntType
+const myIntType myInt = 3
+
+//const map<enumconstants,string> GEN_ENUM_NAMES = {ONE : "HOWDY", TWO: "PARTNER"}
+
+const i32 hex_const = 0x0001F
+const i32 negative_hex_constant = -0x0001F
+
+const i32 GEN_ME = -3523553
+const double GEn_DUB = 325.532
+const double GEn_DU = 085.2355
+const string GEN_STRING = "asldkjasfd"
+
+const double e10 = 1e10   // fails with 0.9.3 and earlier
+const double e11 = -1e10  
+
+const map<i32,i32> GEN_MAP = { 35532 : 233, 43523 : 853 }
+const list<i32> GEN_LIST = [ 235235, 23598352, 3253523 ]
+
+const map<i32, map<i32, i32>> GEN_MAPMAP = { 235 : { 532 : 53255, 235:235}}
+
+const map<string,i32> GEN_MAP2 = { "hello" : 233, "lkj98d" : 853, 'lkjsdf' : 098325 }
+
+const thing GEN_THING = { 'hello' : 325, 'goodbye' : 325352 }
+
+const map<i32,thing> GEN_WHAT = { 35 : { 'hello' : 325, 'goodbye' : 325352 } }
+
+const set<i32> GEN_SET = [ 235, 235, 53235 ]
+
+exception Blah {
+  1:  i32 bing }
+
+exception Gak {}
+
+service yowza {
+  void blingity(),
+  i32 blangity() throws (1: Blah hoot )
+}
diff --git a/test/v0.16/DebugProtoTest.thrift b/test/v0.16/DebugProtoTest.thrift
new file mode 100644
index 0000000..5d0face
--- /dev/null
+++ b/test/v0.16/DebugProtoTest.thrift
@@ -0,0 +1,393 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+namespace c_glib TTest
+namespace cpp thrift.test.debug
+namespace java thrift.test
+namespace rb thrift.test
+
+struct Doubles {
+ 1: double nan,
+ 2: double inf,
+ 3: double neginf,
+ 4: double repeating,
+ 5: double big,
+ 6: double tiny,
+ 7: double zero,
+ 8: double negzero,
+}
+
+struct OneOfEach {
+  1: bool im_true,
+  2: bool im_false,
+  3: i8 a_bite = 0x7f,
+  4: i16 integer16 = 0x7fff,
+  5: i32 integer32,
+  6: i64 integer64 = 10000000000,
+  7: double double_precision,
+  8: string some_characters,
+  9: string zomg_unicode,
+  10: bool what_who,
+  11: binary base64,
+  12: list<i8> byte_list = [1, 2, 3],
+  13: list<i16> i16_list = [1,2,3],
+  14: list<i64> i64_list = [1,2,3]
+}
+
+struct Bonk {
+  1: i32 type,
+  2: string message,
+}
+
+struct Nesting {
+  1: Bonk my_bonk,
+  2: OneOfEach my_ooe,
+}
+
+struct HolyMoley {
+  1: list<OneOfEach> big,
+  2: set<list<string> (python.immutable = "")> contain,
+  3: map<string,list<Bonk>> bonks,
+}
+
+struct Backwards {
+  2: i32 first_tag2,
+  1: i32 second_tag1,
+}
+
+struct Empty {
+} (
+  python.immutable = "",
+)
+
+struct Wrapper {
+  1: Empty foo
+} (
+  python.immutable = "",
+)
+
+struct RandomStuff {
+  1: i32 a,
+  2: i32 b,
+  3: i32 c,
+  4: i32 d,
+  5: list<i32> myintlist,
+  6: map<i32,Wrapper> maps,
+  7: i64 bigint,
+  8: double triple,
+}
+
+struct Base64 {
+  1: i32 a,
+  2: binary b1,
+  3: binary b2,
+  4: binary b3,
+  5: binary b4,
+  6: binary b5,
+  7: binary b6,
+}
+
+struct CompactProtoTestStruct {
+  // primitive fields
+  1: i8     a_byte;
+  2: i16    a_i16;
+  3: i32    a_i32;
+  4: i64    a_i64;
+  5: double a_double;
+  6: string a_string;
+  7: binary a_binary;
+  8: bool   true_field;
+  9: bool   false_field;
+  10: Empty empty_struct_field;
+
+  // primitives in lists
+  11: list<i8>      byte_list;
+  12: list<i16>     i16_list;
+  13: list<i32>     i32_list;
+  14: list<i64>     i64_list;
+  15: list<double>  double_list;
+  16: list<string>  string_list;
+  17: list<binary>  binary_list;
+  18: list<bool>    boolean_list;
+  19: list<Empty>   struct_list;
+
+  // primitives in sets
+  20: set<i8>       byte_set;
+  21: set<i16>      i16_set;
+  22: set<i32>      i32_set;
+  23: set<i64>      i64_set;
+  24: set<double>   double_set;
+  25: set<string>   string_set;
+  26: set<binary>   binary_set;
+  27: set<bool>     boolean_set;
+  28: set<Empty>    struct_set;
+
+  // maps
+  // primitives as keys
+  29: map<i8, i8>               byte_byte_map;
+  30: map<i16, i8>              i16_byte_map;
+  31: map<i32, i8>              i32_byte_map;
+  32: map<i64, i8>              i64_byte_map;
+  33: map<double, i8>           double_byte_map;
+  34: map<string, i8>           string_byte_map;
+  35: map<binary, i8>           binary_byte_map;
+  36: map<bool, i8>             boolean_byte_map;
+  // primitives as values
+  37: map<i8, i16>              byte_i16_map;
+  38: map<i8, i32>              byte_i32_map;
+  39: map<i8, i64>              byte_i64_map;
+  40: map<i8, double>           byte_double_map;
+  41: map<i8, string>           byte_string_map;
+  42: map<i8, binary>           byte_binary_map;
+  43: map<i8, bool>             byte_boolean_map;
+  // collections as keys
+  44: map<list<i8> (python.immutable = ""), i8>       list_byte_map;
+  45: map<set<i8> (python.immutable = ""), i8>        set_byte_map;
+  46: map<map<i8,i8> (python.immutable = ""), i8>     map_byte_map;
+  // collections as values
+  47: map<i8, map<i8,i8>>     byte_map_map;
+  48: map<i8, set<i8>>        byte_set_map;
+  49: map<i8, list<i8>>       byte_list_map;
+  
+  // large field IDs
+  500 : i64  field500;
+  5000 : i64  field5000;
+  20000 : i64  field20000;
+}
+
+// To be used to test the serialization of an empty map
+struct SingleMapTestStruct {
+  1: required map<i32, i32>       i32_map;
+}
+
+const CompactProtoTestStruct COMPACT_TEST = {
+  'a_byte'             : 127,
+  'a_i16'              : 32000,
+  'a_i32'              : 1000000000,
+  'a_i64'              : 0xffffffffff,
+  'a_double'           : 5.6789,
+  'a_string'           : "my string",
+//'a_binary,'
+  'true_field'         : 1,
+  'false_field'        : 0,
+  'empty_struct_field' : {},
+  'byte_list'          : [-127, -1, 0, 1, 127],
+  'i16_list'           : [-1, 0, 1, 0x7fff],
+  'i32_list'           : [-1, 0, 0xff, 0xffff, 0xffffff, 0x7fffffff],
+  'i64_list'           : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+  'double_list'        : [0.1, 0.2, 0.3],
+  'string_list'        : ["first", "second", "third"],
+//'binary_list,'
+  'boolean_list'       : [1, 1, 1, 0, 0, 0],
+  'struct_list'        : [{}, {}],
+  'byte_set'           : [-127, -1, 0, 1, 127],
+  'i16_set'            : [-1, 0, 1, 0x7fff],
+  'i32_set'            : [1, 2, 3],
+  'i64_set'            : [-1, 0, 0xff, 0xffff, 0xffffff, 0xffffffff, 0xffffffffff, 0xffffffffffff, 0xffffffffffffff, 0x7fffffffffffffff],
+  'double_set'         : [0.1, 0.2, 0.3],
+  'string_set'         : ["first", "second", "third"],
+//'binary_set,'
+  'boolean_set'        : [1, 0],
+  'struct_set'         : [{}],
+  'byte_byte_map'      : {1 : 2},
+  'i16_byte_map'       : {1 : 1, -1 : 1, 0x7fff : 1},
+  'i32_byte_map'       : {1 : 1, -1 : 1, 0x7fffffff : 1},
+  'i64_byte_map'       : {0 : 1,  1 : 1, -1 : 1, 0x7fffffffffffffff : 1},
+  'double_byte_map'    : {-1.1 : 1, 1.1 : 1},
+  'string_byte_map'    : {"first" : 1, "second" : 2, "third" : 3, "" : 0},
+//'binary_byte_map,'
+  'boolean_byte_map'   : {1 : 1, 0 : 0},
+  'byte_i16_map'       : {1 : 1, 2 : -1, 3 : 0x7fff},
+  'byte_i32_map'       : {1 : 1, 2 : -1, 3 : 0x7fffffff},
+  'byte_i64_map'       : {1 : 1, 2 : -1, 3 : 0x7fffffffffffffff},
+  'byte_double_map'    : {1 : 0.1, 2 : -0.1, 3 : 1000000.1},
+  'byte_string_map'    : {1 : "", 2 : "blah", 3 : "loooooooooooooong string"},
+//'byte_binary_map,'
+  'byte_boolean_map'   : {1 : 1, 2 : 0},
+  'list_byte_map'      : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0},
+  'set_byte_map'       : {[1, 2, 3] : 1, [0, 1] : 2, [] : 0},
+  'map_byte_map'       : {{1 : 1} : 1, {2 : 2} : 2, {} : 0},
+  'byte_map_map'       : {0 : {}, 1 : {1 : 1}, 2 : {1 : 1, 2 : 2}},
+  'byte_set_map'       : {0 : [], 1 : [1], 2 : [1, 2]},
+  'byte_list_map'      : {0 : [], 1 : [1], 2 : [1, 2]},
+  
+  'field500'           : 500,
+  'field5000'          : 5000,
+  'field20000'         : 20000,
+}
+
+
+const i32 MYCONST = 2
+
+
+exception ExceptionWithAMap {
+  1: string blah;
+  2: map<string, string> map_field;
+}
+
+exception MutableException {
+  1: string msg;
+} (python.immutable = "false")
+
+exception ExceptionWithoutFields {}
+
+service ServiceForExceptionWithAMap {
+  void methodThatThrowsAnException() throws (1: ExceptionWithAMap xwamap);
+}
+
+service Srv {
+  i32 Janky(1: i32 arg);
+
+  // return type only methods
+
+  void voidMethod();
+  i32 primitiveMethod();
+  CompactProtoTestStruct structMethod();
+
+  void methodWithDefaultArgs(1: i32 something = MYCONST);
+
+  oneway void onewayMethod();
+
+  bool declaredExceptionMethod(1: bool shouldThrow) throws (1: ExceptionWithAMap xwamap);
+}
+
+service Inherited extends Srv {
+  i32 identity(1: i32 arg)
+}
+
+service EmptyService {}
+
+// The only purpose of this thing is to increase the size of the generated code
+// so that ZlibTest has more highly compressible data to play with.
+struct BlowUp {
+  1: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b1;
+  2: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b2;
+  3: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b3;
+  4: map<list<i32>(python.immutable = ""),set<map<i32,string> (python.immutable = "")>> b4;
+}
+
+
+struct ReverseOrderStruct {
+  4: string first;
+  3: i16 second;
+  2: i32 third;
+  1: i64 fourth;
+}
+
+service ReverseOrderService {
+  void myMethod(4: string first, 3: i16 second, 2: i32 third, 1: i64 fourth);
+}
+
+enum SomeEnum {
+  ONE = 1
+  TWO = 2
+}
+
+/** This is a docstring on a constant! */
+const SomeEnum MY_SOME_ENUM = SomeEnum.ONE
+
+const SomeEnum MY_SOME_ENUM_1 = 1
+/*const SomeEnum MY_SOME_ENUM_2 = 7*/
+
+const map<SomeEnum,SomeEnum> MY_ENUM_MAP = {
+  SomeEnum.ONE : SomeEnum.TWO
+}
+
+struct StructWithSomeEnum {
+  1: SomeEnum blah;
+}
+
+const map<SomeEnum,StructWithSomeEnum> EXTRA_CRAZY_MAP = {
+  SomeEnum.ONE : {"blah" : SomeEnum.TWO}
+}
+
+union TestUnion {
+  /**
+   * A doc string
+   */
+  1: string string_field;
+  2: i32 i32_field;
+  3: OneOfEach struct_field;
+  4: list<RandomStuff> struct_list;
+  5: i32 other_i32_field;
+  6: SomeEnum enum_field;
+  7: set<i32> i32_set;
+  8: map<i32, i32> i32_map;
+}
+
+union TestUnionMinusStringField {
+  2: i32 i32_field;
+  3: OneOfEach struct_field;
+  4: list<RandomStuff> struct_list;
+  5: i32 other_i32_field;
+  6: SomeEnum enum_field;
+  7: set<i32> i32_set;
+  8: map<i32, i32> i32_map;
+}
+
+union ComparableUnion {
+  1: string string_field;
+  2: binary binary_field;
+}
+
+struct StructWithAUnion {
+  1: TestUnion test_union;
+}
+
+struct PrimitiveThenStruct {
+  1: i32 blah;
+  2: i32 blah2;
+  3: Backwards bw;
+}
+
+typedef map<i32,i32> SomeMap
+
+struct StructWithASomemap {
+  1: required SomeMap somemap_field;
+}
+
+struct BigFieldIdStruct {
+  1: string field1;
+  45: string field2;
+}
+
+struct BreaksRubyCompactProtocol {
+  1: string field1;
+  2: BigFieldIdStruct field2;
+  3: i32 field3;
+}
+
+struct TupleProtocolTestStruct {
+  optional i32 field1;
+  optional i32 field2;
+  optional i32 field3;
+  optional i32 field4;
+  optional i32 field5;
+  optional i32 field6;
+  optional i32 field7;
+  optional i32 field8;
+  optional i32 field9;
+  optional i32 field10;
+  optional i32 field11;
+  optional i32 field12;
+}
+
+struct ListDoublePerf {
+  1: list<double> field;
+}
diff --git a/test/v0.16/NameConflictTest.thrift b/test/v0.16/NameConflictTest.thrift
new file mode 100644
index 0000000..d581ce5
--- /dev/null
+++ b/test/v0.16/NameConflictTest.thrift
@@ -0,0 +1,143 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+// Naming testcases, sepcifically for these tickets (but not limited to them)
+// THRIFT-2508 Uncompileable C# code due to language keywords in IDL
+// THRIFT-2557 error CS0542 member names cannot be the same as their enclosing type
+
+
+struct using {
+    1: double single
+    2: double integer
+}
+
+struct delegate {
+    1: string partial
+    2: delegate delegate
+}
+
+struct get {
+    1: bool sbyte
+}
+
+struct partial {
+    1: using using
+    2: bool read
+    3: bool write
+}
+
+enum Maybe {
+  JUST = 1,
+  TRUE = 2,
+  FALSE = 3
+}
+
+enum Either {
+  LEFT = 1,
+  RIGHT = 2
+}
+
+struct foldr {
+  1: string id
+}
+
+struct of {
+  1: string let
+  2: string where
+}
+
+struct ofOf {
+  1: of Of
+}
+
+
+struct ClassAndProp {
+  1: bool ClassAndProp
+  2: bool ClassAndProp_
+  3: bool ClassAndProp__
+  4: bool ClassAndProper
+}
+
+struct second_chance {
+  1: bool SECOND_CHANCE
+  2: bool SECOND_CHANCE_
+  3: bool SECOND_CHANCE__
+  4: bool SECOND_CHANCES
+}
+
+struct NOW_EAT_THIS {
+  1: bool now_eat_this
+  2: bool now_eat_this_
+  3: bool now_eat_this__
+  4: bool now_eat_this_and_this
+}
+
+struct TheEdgeCase {
+  1: bool theEdgeCase
+  2: bool theEdgeCase_
+  3: bool theEdgeCase__
+  4: bool TheEdgeCase
+  5: bool TheEdgeCase_
+  6: bool TheEdgeCase__
+}
+
+struct Tricky_ {
+  1: bool tricky
+  2: bool Tricky
+}
+
+struct Nested {
+  1: ClassAndProp ClassAndProp
+  2: second_chance second_chance
+  3: NOW_EAT_THIS NOW_EAT_THIS
+  4: TheEdgeCase TheEdgeCase
+  5: Tricky_ Tricky_
+  6: Nested Nested
+}
+
+exception Problem_ {
+  1: bool problem
+  2: bool Problem
+}
+
+struct Thrift5626 {
+   1: i8       i8
+   2: i16      i16
+   3: i32      i32
+   4: i64      i64
+   //5: uuid     uuid
+   6: string   string
+   7: binary   binary
+   8: bool     bool
+   9: byte     byte
+  10: list<string>        list
+  11: set<string>         set
+  12: map<string,string>  map
+}
+
+service extern {
+    delegate event(1: partial get)
+    void Foo(1: Nested Foo_args) throws (1: Problem_ Foo_result)
+}
+
+service qualified {
+    Maybe maybe(1: Maybe foldr)
+    Either either(1: foldr of)
+}
+// eof
diff --git a/test/v0.16/ThriftTest.thrift b/test/v0.16/ThriftTest.thrift
new file mode 100644
index 0000000..4a1045f
--- /dev/null
+++ b/test/v0.16/ThriftTest.thrift
@@ -0,0 +1,418 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ *
+ * Contains some contributions under the Thrift Software License.
+ * Please see doc/old-thrift-license.txt in the Thrift distribution for
+ * details.
+ */
+
+namespace c_glib TTest
+namespace cpp thrift.test
+namespace delphi Thrift.Test
+namespace go thrifttest
+namespace java thrift.test
+namespace js ThriftTest
+namespace lua ThriftTest
+namespace netstd ThriftTest
+namespace perl ThriftTest
+namespace php ThriftTest
+namespace py ThriftTest
+namespace py.twisted ThriftTest
+namespace rb Thrift.Test
+namespace st ThriftTest
+namespace xsd test (uri = 'http://thrift.apache.org/ns/ThriftTest')
+
+// Presence of namespaces and sub-namespaces for which there is
+// no generator should compile with warnings only
+namespace noexist ThriftTest
+namespace cpp.noexist ThriftTest
+
+namespace * thrift.test
+
+/**
+ * Docstring!
+ */
+enum Numberz
+{
+  ONE = 1,
+  TWO,
+  THREE,
+  FIVE = 5,
+  SIX,
+  EIGHT = 8
+}
+
+const Numberz myNumberz = Numberz.ONE;
+// the following is expected to fail:
+// const Numberz urNumberz = ONE;
+
+typedef i64 UserId
+
+struct Bonk
+{
+  1: string message,
+  2: i32 type
+}
+
+typedef map<string,Bonk> MapType
+
+struct Bools {
+  1: bool im_true,
+  2: bool im_false,
+}
+
+struct Xtruct
+{
+  1:  string string_thing,
+  4:  i8     byte_thing,
+  9:  i32    i32_thing,
+  11: i64    i64_thing
+}
+
+struct Xtruct2
+{
+  1: i8     byte_thing,  // used to be byte, hence the name
+  2: Xtruct struct_thing,
+  3: i32    i32_thing
+}
+
+struct Xtruct3
+{
+  1:  string string_thing,
+  4:  i32    changed,
+  9:  i32    i32_thing,
+  11: i64    i64_thing
+}
+
+
+struct Insanity
+{
+  1: map<Numberz, UserId> userMap,
+  2: list<Xtruct> xtructs
+} (python.immutable= "")
+
+struct CrazyNesting {
+  1: string string_field,
+  2: optional set<Insanity> set_field,
+  // Do not insert line break as test/go/Makefile.am is removing this line with pattern match
+  3: required list<map<set<i32> (python.immutable = ""), map<i32,set<list<map<Insanity,string>(python.immutable = "")> (python.immutable = "")>>>> list_field,
+  4: binary binary_field
+}
+
+union SomeUnion {
+  1: map<Numberz, UserId> map_thing,
+  2: string string_thing,
+  3: i32 i32_thing,
+  4: Xtruct3 xtruct_thing,
+  5: Insanity insanity_thing
+}
+
+exception Xception {
+  1: i32 errorCode,
+  2: string message
+}
+
+exception Xception2 {
+  1: i32 errorCode,
+  2: Xtruct struct_thing
+}
+
+struct EmptyStruct {}
+
+struct OneField {
+  1: EmptyStruct field
+}
+
+service ThriftTest
+{
+  /**
+   * Prints "testVoid()" and returns nothing.
+   */
+  void         testVoid(),
+
+  /**
+   * Prints 'testString("%s")' with thing as '%s'
+   * @param string thing - the string to print
+   * @return string - returns the string 'thing'
+   */
+  string       testString(1: string thing),
+
+  /**
+   * Prints 'testBool("%s")' where '%s' with thing as 'true' or 'false'
+   * @param bool  thing - the bool data to print
+   * @return bool  - returns the bool 'thing'
+   */
+  bool         testBool(1: bool thing),
+
+  /**
+   * Prints 'testByte("%d")' with thing as '%d'
+   * The types i8 and byte are synonyms, use of i8 is encouraged, byte still exists for the sake of compatibility.
+   * @param byte thing - the i8/byte to print
+   * @return i8 - returns the i8/byte 'thing'
+   */
+  i8           testByte(1: i8 thing),
+
+  /**
+   * Prints 'testI32("%d")' with thing as '%d'
+   * @param i32 thing - the i32 to print
+   * @return i32 - returns the i32 'thing'
+   */
+  i32          testI32(1: i32 thing),
+
+  /**
+   * Prints 'testI64("%d")' with thing as '%d'
+   * @param i64 thing - the i64 to print
+   * @return i64 - returns the i64 'thing'
+   */
+  i64          testI64(1: i64 thing),
+
+  /**
+   * Prints 'testDouble("%f")' with thing as '%f'
+   * @param double thing - the double to print
+   * @return double - returns the double 'thing'
+   */
+  double       testDouble(1: double thing),
+
+  /**
+   * Prints 'testBinary("%s")' where '%s' is a hex-formatted string of thing's data
+   * @param binary  thing - the binary data to print
+   * @return binary  - returns the binary 'thing'
+   */
+  binary       testBinary(1: binary thing),
+
+  /**
+   * Prints 'testStruct("{%s}")' where thing has been formatted into a string of comma separated values
+   * @param Xtruct thing - the Xtruct to print
+   * @return Xtruct - returns the Xtruct 'thing'
+   */
+  Xtruct       testStruct(1: Xtruct thing),
+
+  /**
+   * Prints 'testNest("{%s}")' where thing has been formatted into a string of the nested struct
+   * @param Xtruct2 thing - the Xtruct2 to print
+   * @return Xtruct2 - returns the Xtruct2 'thing'
+   */
+  Xtruct2      testNest(1: Xtruct2 thing),
+
+  /**
+   * Prints 'testMap("{%s")' where thing has been formatted into a string of 'key => value' pairs
+   *  separated by commas and new lines
+   * @param map<i32,i32> thing - the map<i32,i32> to print
+   * @return map<i32,i32> - returns the map<i32,i32> 'thing'
+   */
+  map<i32,i32> testMap(1: map<i32,i32> thing),
+
+  /**
+   * Prints 'testStringMap("{%s}")' where thing has been formatted into a string of 'key => value' pairs
+   *  separated by commas and new lines
+   * @param map<string,string> thing - the map<string,string> to print
+   * @return map<string,string> - returns the map<string,string> 'thing'
+   */
+  map<string,string> testStringMap(1: map<string,string> thing),
+
+  /**
+   * Prints 'testSet("{%s}")' where thing has been formatted into a string of values
+   *  separated by commas and new lines
+   * @param set<i32> thing - the set<i32> to print
+   * @return set<i32> - returns the set<i32> 'thing'
+   */
+  set<i32>     testSet(1: set<i32> thing),
+
+  /**
+   * Prints 'testList("{%s}")' where thing has been formatted into a string of values
+   *  separated by commas and new lines
+   * @param list<i32> thing - the list<i32> to print
+   * @return list<i32> - returns the list<i32> 'thing'
+   */
+  list<i32>    testList(1: list<i32> thing),
+
+  /**
+   * Prints 'testEnum("%d")' where thing has been formatted into its numeric value
+   * @param Numberz thing - the Numberz to print
+   * @return Numberz - returns the Numberz 'thing'
+   */
+  Numberz      testEnum(1: Numberz thing),
+
+  /**
+   * Prints 'testTypedef("%d")' with thing as '%d'
+   * @param UserId thing - the UserId to print
+   * @return UserId - returns the UserId 'thing'
+   */
+  UserId       testTypedef(1: UserId thing),
+
+  /**
+   * Prints 'testMapMap("%d")' with hello as '%d'
+   * @param i32 hello - the i32 to print
+   * @return map<i32,map<i32,i32>> - returns a dictionary with these values:
+   *   {-4 => {-4 => -4, -3 => -3, -2 => -2, -1 => -1, }, 4 => {1 => 1, 2 => 2, 3 => 3, 4 => 4, }, }
+   */
+  map<i32,map<i32,i32>> testMapMap(1: i32 hello),
+
+  /**
+   * So you think you've got this all worked out, eh?
+   *
+   * Creates a map with these values and prints it out:
+   *   { 1 => { 2 => argument,
+   *            3 => argument,
+   *          },
+   *     2 => { 6 => <empty Insanity struct>, },
+   *   }
+   * @return map<UserId, map<Numberz,Insanity>> - a map with the above values
+   */
+  map<UserId, map<Numberz,Insanity>> testInsanity(1: Insanity argument),
+
+  /**
+   * Prints 'testMulti()'
+   * @param i8 arg0 -
+   * @param i32 arg1 -
+   * @param i64 arg2 -
+   * @param map<i16, string> arg3 -
+   * @param Numberz arg4 -
+   * @param UserId arg5 -
+   * @return Xtruct - returns an Xtruct with string_thing = "Hello2, byte_thing = arg0, i32_thing = arg1
+   *    and i64_thing = arg2
+   */
+  Xtruct testMulti(1: i8 arg0, 2: i32 arg1, 3: i64 arg2, 4: map<i16, string> arg3, 5: Numberz arg4, 6: UserId arg5),
+
+  /**
+   * Print 'testException(%s)' with arg as '%s'
+   * @param string arg - a string indication what type of exception to throw
+   * if arg == "Xception" throw Xception with errorCode = 1001 and message = arg
+   * else if arg == "TException" throw TException
+   * else do not throw anything
+   */
+  void testException(1: string arg) throws(1: Xception err1),
+
+  /**
+   * Print 'testMultiException(%s, %s)' with arg0 as '%s' and arg1 as '%s'
+   * @param string arg - a string indicating what type of exception to throw
+   * if arg0 == "Xception" throw Xception with errorCode = 1001 and message = "This is an Xception"
+   * else if arg0 == "Xception2" throw Xception2 with errorCode = 2002 and struct_thing.string_thing = "This is an Xception2"
+   * else do not throw anything
+   * @return Xtruct - an Xtruct with string_thing = arg1
+   */
+  Xtruct testMultiException(1: string arg0, 2: string arg1) throws(1: Xception err1, 2: Xception2 err2)
+
+  /**
+   * Print 'testOneway(%d): Sleeping...' with secondsToSleep as '%d'
+   * sleep 'secondsToSleep'
+   * Print 'testOneway(%d): done sleeping!' with secondsToSleep as '%d'
+   * @param i32 secondsToSleep - the number of seconds to sleep
+   */
+  oneway void testOneway(1:i32 secondsToSleep)
+}
+
+service SecondService
+{
+  /**
+   * Prints 'testString("%s")' with thing as '%s'
+   * @param string thing - the string to print
+   * @return string - returns the string 'thing'
+   */
+  string secondtestString(1: string thing)
+}
+
+struct VersioningTestV1 {
+       1: i32 begin_in_both,
+       3: string old_string,
+       12: i32 end_in_both
+}
+
+struct VersioningTestV2 {
+       1: i32 begin_in_both,
+
+       2: i32 newint,
+       3: i8 newbyte,
+       4: i16 newshort,
+       5: i64 newlong,
+       6: double newdouble
+       7: Bonk newstruct,
+       8: list<i32> newlist,
+       9: set<i32> newset,
+       10: map<i32, i32> newmap,
+       11: string newstring,
+       12: i32 end_in_both
+}
+
+struct ListTypeVersioningV1 {
+       1: list<i32> myints;
+       2: string hello;
+}
+
+struct ListTypeVersioningV2 {
+       1: list<string> strings;
+       2: string hello;
+}
+
+struct GuessProtocolStruct {
+  7: map<string,string> map_field,
+}
+
+struct LargeDeltas {
+  1: Bools b1,
+  10: Bools b10,
+  100: Bools b100,
+  500: bool check_true,
+  1000: Bools b1000,
+  1500: bool check_false,
+  2000: VersioningTestV2 vertwo2000,
+  2500: set<string> a_set2500,
+  3000: VersioningTestV2 vertwo3000,
+  4000: list<i32> big_numbers
+}
+
+struct NestedListsI32x2 {
+  1: list<list<i32>> integerlist
+}
+struct NestedListsI32x3 {
+  1: list<list<list<i32>>> integerlist
+}
+struct NestedMixedx2 {
+  1: list<set<i32>> int_set_list
+  2: map<i32,set<string>> map_int_strset
+  3: list<map<i32,set<string>>> map_int_strset_list
+}
+struct ListBonks {
+  1: list<Bonk> bonk
+}
+struct NestedListsBonk {
+  1: list<list<list<Bonk>>> bonk
+}
+
+struct BoolTest {
+  1: optional bool b = true;
+  2: optional string s = "true";
+}
+
+struct StructA {
+  1: required string s;
+}
+
+struct StructB {
+  1: optional StructA aa;
+  2: required StructA ab;
+}
+
+struct OptionalSetDefaultTest {
+  1: optional set<string> with_default = [ "test" ]
+}
+
+struct OptionalBinary {
+  1: optional set<binary> bin_set = {}
+  2: optional map<binary,i32> bin_map = {}
+}
diff --git a/tutorial/Makefile.am b/tutorial/Makefile.am
index 77e8593..24969d1 100644
--- a/tutorial/Makefile.am
+++ b/tutorial/Makefile.am
@@ -74,6 +74,10 @@
 SUBDIRS += rs
 endif
 
+if WITH_CL
+SUBDIRS += cl
+endif
+
 if WITH_PERL
 SUBDIRS += perl
 endif
@@ -82,8 +86,12 @@
 SUBDIRS += php
 endif
 
+if WITH_SWIFT
+SUBDIRS += swift
+endif
+
 #
-# generate html for ThriftTest.thrift
+# generate html for tutorial.thrift
 #
 all-local:
 	$(top_builddir)/compiler/cpp/thrift --gen html -r $(top_srcdir)/tutorial/tutorial.thrift
diff --git a/tutorial/cl/Makefile.am b/tutorial/cl/Makefile.am
new file mode 100755
index 0000000..70c5e07
--- /dev/null
+++ b/tutorial/cl/Makefile.am
@@ -0,0 +1,66 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+
+setup-local-lisp-env: ../../lib/cl/ensure-externals.sh
+	bash ../../lib/cl/ensure-externals.sh
+
+gen-cl: $(top_srcdir)/tutorial/tutorial.thrift
+	$(THRIFT) --gen cl -r $<
+
+ALL_FILE_PREREQS = \
+		   load-locally.lisp \
+		   make-tutorial-server.lisp \
+		   make-tutorial-client.lisp \
+		   shared-implementation.lisp \
+		   thrift-tutorial.asd \
+		   tutorial-implementation.lisp
+
+# NOTE: the server and client cannot be built in parallel
+# because on loading the make-tutorial-* scripts SBCL will
+# attempt to compile their dependencies. Unfortunately,
+# because their dependencies are shared, parallel jobs can
+# end up overwriting or corrupting the compiled files
+all-local: gen-cl setup-local-lisp-env $(ALL_FILE_PREREQS)
+	$(SBCL) --script make-tutorial-server.lisp
+	$(SBCL) --script make-tutorial-client.lisp
+
+tutorialserver: all
+	./TutorialServer
+
+tutorialclient: all
+	./TutorialClient
+
+clean-local:
+	-$(RM) -r gen-*
+	-$(RM) -r externals
+	-$(RM) -r quicklisp
+	-$(RM) -r lib
+	-$(RM) quicklisp.lisp
+	-$(RM) backport-update.zip
+	-$(RM) shared-implementation.fasl
+	-$(RM) tutorial-implementation.fasl
+	-$(RM) TutorialServer
+	-$(RM) TutorialClient
+
+EXTRA_DIST = \
+	tutorial-implementation.lisp \
+	shared-implementation.lisp \
+	thrift-tutorial.asd \
+	make-tutorial-server.lisp \
+	make-tutorial-client.lisp \
+	load-locally.lisp
diff --git a/tutorial/cl/load-locally.lisp b/tutorial/cl/load-locally.lisp
new file mode 100644
index 0000000..b52a0a2
--- /dev/null
+++ b/tutorial/cl/load-locally.lisp
@@ -0,0 +1,22 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+;;;; Just a script for loading the library itself, using bundled dependencies.
+;;;; This is an identical copy of the file in lib/cl.
+
+(require "asdf")
+
+(load (merge-pathnames "externals/bundle.lisp" *load-truename*))
+(asdf:load-asd (merge-pathnames "lib/de.setf.thrift-backport-update/thrift.asd" *load-truename*))
+(asdf:load-system :thrift)
diff --git a/tutorial/cl/make-tutorial-client.lisp b/tutorial/cl/make-tutorial-client.lisp
new file mode 100644
index 0000000..5b8183e
--- /dev/null
+++ b/tutorial/cl/make-tutorial-client.lisp
@@ -0,0 +1,54 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+(require "asdf")
+(load (merge-pathnames "load-locally.lisp" *load-truename*))
+(require "sb-grovel") ;; necessary for :net.didierverna.clon.termio
+(asdf:load-asd (first (directory (merge-pathnames "../../lib/cl/externals/software/clon-*/termio/net.didierverna.clon.termio.asd"
+                                                  *load-truename*))))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
+(asdf:load-system :thrift-tutorial)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  "Entry point for the binary."
+  (thrift:with-client (prot #u"thrift://127.0.0.1:9090")
+    (tutorial.calculator:ping prot)
+    (format t "ping()~%")
+    (format t "1 + 1 = ~a~%" (tutorial.calculator:add prot 1 1))
+    (let ((work-instance (tutorial:make-work :num1 5
+                                             :num2 0
+                                             :op tutorial:operation.divide
+                                             :comment "Booya!")))
+      (handler-case (format t
+                            "5 / 0 = ~a - Oh, really? An exception should have been thrown here.~%"
+                            (tutorial.calculator:calculate prot 1 work-instance))
+        (tutorial:invalidoperation (e)
+          (format t "---~%(Expected) Invalid Operation caught: ~%~a~%---~%" e))))
+    (let ((work-instance (tutorial:make-work :num1 15
+                                             :num2 10
+                                             :op tutorial:operation.subtract
+                                             :comment "Playing nice this time.")))
+      (handler-case (format t
+                            "15 - 10 = ~a~%"
+                            (tutorial.calculator:calculate prot 1 work-instance))
+        (tutorial:invalidoperation (e)
+          (format t "---~%(Unexpected) Invalid Operation caught: ~%~a~%---~%" e))))
+    (format t "Check log: ~a~%" (shared.shared-service:get-struct prot 1))))
+
+(clon:dump "TutorialClient" main)
diff --git a/tutorial/cl/make-tutorial-server.lisp b/tutorial/cl/make-tutorial-server.lisp
new file mode 100644
index 0000000..9f47be8
--- /dev/null
+++ b/tutorial/cl/make-tutorial-server.lisp
@@ -0,0 +1,32 @@
+(in-package #:cl-user)
+
+;;;; 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.
+
+(require "asdf")
+(load (merge-pathnames "load-locally.lisp" *load-truename*))
+(require "sb-grovel") ;; necessary for :net.didierverna.clon.termio
+(asdf:load-asd (first (directory (merge-pathnames "../../lib/cl/externals/software/clon-*/termio/net.didierverna.clon.termio.asd"
+                                                  *load-truename*))))
+(asdf:load-system :net.didierverna.clon)
+(asdf:load-asd (merge-pathnames "gen-cl/shared/thrift-gen-shared.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "gen-cl/tutorial/thrift-gen-tutorial.asd" *load-truename*))
+(asdf:load-asd (merge-pathnames "thrift-tutorial.asd" *load-truename*))
+(asdf:load-system :thrift-tutorial)
+
+(net.didierverna.clon:nickname-package)
+
+(defun main ()
+  "Entry point for the binary."
+  (thrift:serve #u"thrift://127.0.0.1:9090" tutorial:calculator))
+
+(clon:dump "TutorialServer" main)
diff --git a/tutorial/cl/shared-implementation.lisp b/tutorial/cl/shared-implementation.lisp
new file mode 100644
index 0000000..c197626
--- /dev/null
+++ b/tutorial/cl/shared-implementation.lisp
@@ -0,0 +1,25 @@
+(in-package #:shared-implementation)
+
+;;;; 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.
+
+(defvar *structs* (make-hash-table))
+
+(defun shared.shared-service-implementation:get-struct (key)
+  (format t "getStruct(~a)~%" key)
+  (gethash key *structs*))
+
+(defun add-log (key value)
+  (setf (gethash key *structs*)
+        (make-instance 'shared:sharedstruct
+                       :key key
+                       :value (write-to-string value))))
diff --git a/tutorial/cl/thrift-tutorial.asd b/tutorial/cl/thrift-tutorial.asd
new file mode 100644
index 0000000..8a03537
--- /dev/null
+++ b/tutorial/cl/thrift-tutorial.asd
@@ -0,0 +1,17 @@
+;;;; 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.
+
+(asdf:defsystem #:thrift-tutorial
+  :depends-on (#:thrift-gen-tutorial)
+  :serial t
+  :components ((:file "shared-implementation")
+               (:file "tutorial-implementation")))
diff --git a/tutorial/cl/tutorial-implementation.lisp b/tutorial/cl/tutorial-implementation.lisp
new file mode 100644
index 0000000..5c92fe4
--- /dev/null
+++ b/tutorial/cl/tutorial-implementation.lisp
@@ -0,0 +1,41 @@
+(in-package #:tutorial-implementation)
+
+;;;; 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.
+
+(defun tutorial.calculator-implementation:ping ()
+  (format t "ping()~%"))
+
+(defun tutorial.calculator-implementation:add (num1 num2)
+  (format t "add(~a, ~a)~%" num1 num2)
+  (+ num1 num2))
+
+(defun tutorial.calculator-implementation:calculate (logid work)
+  (format t "calculate(~a, ~a)~%" logid work)
+  (handler-case
+      (let* ((num1 (tutorial:work-num1 work))
+             (num2 (tutorial:work-num2 work))
+             (op (tutorial:work-op work))
+             (result
+              (cond
+                ((= op tutorial:operation.add) (+ num1 num2))
+                ((= op tutorial:operation.subtract) (- num1 num2))
+                ((= op tutorial:operation.multiply) (* num1 num2))
+                ((= op tutorial:operation.divide) (/ num1 num2)))))
+        (shared-implementation::add-log logid result)
+        result)
+    (division-by-zero () (error 'tutorial:invalidoperation
+                                :why "Division by zero."
+                                :what-op (tutorial:work-op work)))))
+
+(defun tutorial.calculator-implementation:zip ()
+  (format t "zip()~%"))
diff --git a/tutorial/dart/client/pubspec.yaml b/tutorial/dart/client/pubspec.yaml
index 028f003..dda5ff0 100644
--- a/tutorial/dart/client/pubspec.yaml
+++ b/tutorial/dart/client/pubspec.yaml
@@ -16,7 +16,7 @@
 # under the License.
 
 name: tutorial_client
-version: 0.17.0
+version: 0.18.0
 description: A Dart client implementation of the Apache Thrift tutorial
 author: Apache Thrift Developers <dev@thrift.apache.org>
 homepage: http://thrift.apache.org
diff --git a/tutorial/dart/console_client/pubspec.yaml b/tutorial/dart/console_client/pubspec.yaml
index 435177f..7aeea57 100644
--- a/tutorial/dart/console_client/pubspec.yaml
+++ b/tutorial/dart/console_client/pubspec.yaml
@@ -16,7 +16,7 @@
 # under the License.
 
 name: tutorial_console_client
-version: 0.17.0
+version: 0.18.0
 description: >
   A Dart console client to implementation of the Apache Thrift tutorial
 author: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/tutorial/dart/server/pubspec.yaml b/tutorial/dart/server/pubspec.yaml
index 0590094..0ac202a 100644
--- a/tutorial/dart/server/pubspec.yaml
+++ b/tutorial/dart/server/pubspec.yaml
@@ -16,7 +16,7 @@
 # under the License.
 
 name: tutorial_server
-version: 0.17.0
+version: 0.18.0
 description: A Dart server to support the Apache Thrift tutorial
 author: Apache Thrift Developers <dev@thrift.apache.org>
 homepage: http://thrift.apache.org
diff --git a/tutorial/delphi/DelphiClient/DelphiClient.dproj b/tutorial/delphi/DelphiClient/DelphiClient.dproj
index ec487e9..45daec2 100644
--- a/tutorial/delphi/DelphiClient/DelphiClient.dproj
+++ b/tutorial/delphi/DelphiClient/DelphiClient.dproj
@@ -124,13 +124,13 @@
 					<VersionInfoKeys>
 						<VersionInfoKeys Name="CompanyName"/>
 						<VersionInfoKeys Name="FileDescription">Thrift Tutorial</VersionInfoKeys>
-						<VersionInfoKeys Name="FileVersion">0.17.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="FileVersion">0.18.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="InternalName">DelphiClient</VersionInfoKeys>
 						<VersionInfoKeys Name="LegalCopyright">Copyright © 2012 The Apache Software Foundation</VersionInfoKeys>
 						<VersionInfoKeys Name="LegalTrademarks"/>
 						<VersionInfoKeys Name="OriginalFilename">DelphiClient.exe</VersionInfoKeys>
 						<VersionInfoKeys Name="ProductName">Thrift</VersionInfoKeys>
-						<VersionInfoKeys Name="ProductVersion">0.17.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="ProductVersion">0.18.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="Comments"/>
 					</VersionInfoKeys>
 					<Source>
diff --git a/tutorial/delphi/DelphiServer/DelphiServer.dproj b/tutorial/delphi/DelphiServer/DelphiServer.dproj
index 31e8fd8..91cf7bb 100644
--- a/tutorial/delphi/DelphiServer/DelphiServer.dproj
+++ b/tutorial/delphi/DelphiServer/DelphiServer.dproj
@@ -121,13 +121,13 @@
 					<VersionInfoKeys>
 						<VersionInfoKeys Name="CompanyName"/>
 						<VersionInfoKeys Name="FileDescription">Thrift Tutorial</VersionInfoKeys>
-						<VersionInfoKeys Name="FileVersion">0.17.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="FileVersion">0.18.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="InternalName">DelphiServer</VersionInfoKeys>
 						<VersionInfoKeys Name="LegalCopyright">Copyright © 2012 The Apache Software Foundation</VersionInfoKeys>
 						<VersionInfoKeys Name="LegalTrademarks"/>
 						<VersionInfoKeys Name="OriginalFilename">DelphiServer.exe</VersionInfoKeys>
 						<VersionInfoKeys Name="ProductName">Thrift</VersionInfoKeys>
-						<VersionInfoKeys Name="ProductVersion">0.17.0.0</VersionInfoKeys>
+						<VersionInfoKeys Name="ProductVersion">0.18.0.0</VersionInfoKeys>
 						<VersionInfoKeys Name="Comments"/>
 					</VersionInfoKeys>
 					<Source>
diff --git a/tutorial/haxe/cpp.hxml b/tutorial/haxe/cpp.hxml
index 6adb52d..1b581a9 100644
--- a/tutorial/haxe/cpp.hxml
+++ b/tutorial/haxe/cpp.hxml
@@ -31,11 +31,11 @@
 #To produce 64 bit binaries the file should define the HXCPP_M64 compile variable:
 #-D HXCPP_M64
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/csharp.hxml b/tutorial/haxe/csharp.hxml
index 295c017..41d20ad 100644
--- a/tutorial/haxe/csharp.hxml
+++ b/tutorial/haxe/csharp.hxml
@@ -28,11 +28,11 @@
 #CSHARP target
 -cs bin/Tutorial.exe
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/flash.hxml b/tutorial/haxe/flash.hxml
index a1f0568..50c4a60 100644
--- a/tutorial/haxe/flash.hxml
+++ b/tutorial/haxe/flash.hxml
@@ -28,6 +28,9 @@
 #Flash target
 -swf bin/Tutorial.swf
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
@@ -35,7 +38,4 @@
 # --macro allowPackage("sys")
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/java.hxml b/tutorial/haxe/java.hxml
index c615565..1f810c7 100644
--- a/tutorial/haxe/java.hxml
+++ b/tutorial/haxe/java.hxml
@@ -28,11 +28,11 @@
 #Java target
 -java bin/Tutorial.jar
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/javascript.hxml b/tutorial/haxe/javascript.hxml
index b2b3876..b9a39bb 100644
--- a/tutorial/haxe/javascript.hxml
+++ b/tutorial/haxe/javascript.hxml
@@ -34,11 +34,11 @@
 #you modify your .hx files.
 -D source-map-content
 
+# libs
+-lib uuid
+
 #Generate source map and add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/neko.hxml b/tutorial/haxe/neko.hxml
index 6161f69..00b0556 100644
--- a/tutorial/haxe/neko.hxml
+++ b/tutorial/haxe/neko.hxml
@@ -28,11 +28,11 @@
 #neko target
 -neko bin/Tutorial.n
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/haxe/php-web-server.hxml b/tutorial/haxe/php-web-server.hxml
index c6e9432..4961cfa 100644
--- a/tutorial/haxe/php-web-server.hxml
+++ b/tutorial/haxe/php-web-server.hxml
@@ -39,7 +39,4 @@
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
diff --git a/tutorial/haxe/php.hxml b/tutorial/haxe/php.hxml
index 42bbf74..847da3b 100644
--- a/tutorial/haxe/php.hxml
+++ b/tutorial/haxe/php.hxml
@@ -29,11 +29,11 @@
 -php bin/php/
 -D php-front=Main-debug.php
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
diff --git a/tutorial/haxe/python.hxml b/tutorial/haxe/python.hxml
index f2c19fa..e591042 100644
--- a/tutorial/haxe/python.hxml
+++ b/tutorial/haxe/python.hxml
@@ -28,11 +28,11 @@
 #Python target
 -python bin/Tutorial.py
 
+# libs
+-lib uuid
+
 #Add debug information
 -debug
 
 #dead code elimination : remove unused code
-#"-dce no" : do not remove unused code
-#"-dce std" : remove unused code in the std lib (default)
-#"-dce full" : remove all unused code
 -dce full
\ No newline at end of file
diff --git a/tutorial/netstd/Client/Client.csproj b/tutorial/netstd/Client/Client.csproj
index 158e592..c07f9cd 100644
--- a/tutorial/netstd/Client/Client.csproj
+++ b/tutorial/netstd/Client/Client.csproj
@@ -24,7 +24,7 @@
     <AssemblyName>Client</AssemblyName>
     <PackageId>Client</PackageId>
     <OutputType>Exe</OutputType>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
     <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
     <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
diff --git a/tutorial/netstd/Interfaces/Interfaces.csproj b/tutorial/netstd/Interfaces/Interfaces.csproj
index d04b243..544c532 100644
--- a/tutorial/netstd/Interfaces/Interfaces.csproj
+++ b/tutorial/netstd/Interfaces/Interfaces.csproj
@@ -22,7 +22,7 @@
     <TargetFramework>net6.0</TargetFramework>
     <AssemblyName>Interfaces</AssemblyName>
     <PackageId>Interfaces</PackageId>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
     <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
     <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
diff --git a/tutorial/netstd/Server/Server.csproj b/tutorial/netstd/Server/Server.csproj
index cf11a75..b55b008 100644
--- a/tutorial/netstd/Server/Server.csproj
+++ b/tutorial/netstd/Server/Server.csproj
@@ -24,7 +24,7 @@
     <AssemblyName>Server</AssemblyName>
     <PackageId>Server</PackageId>
     <OutputType>Exe</OutputType>
-    <Version>0.17.0.0</Version>
+    <Version>0.18.0.0</Version>
     <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
     <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
     <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
diff --git a/tutorial/ocaml/_oasis b/tutorial/ocaml/_oasis
index 9e211fc..0eaa568 100644
--- a/tutorial/ocaml/_oasis
+++ b/tutorial/ocaml/_oasis
@@ -1,5 +1,5 @@
 Name: tutorial
-Version: 0.17.0
+Version: 0.18.0
 OASISFormat: 0.3
 Synopsis: OCaml Tutorial example
 Authors: Apache Thrift Developers <dev@thrift.apache.org>
diff --git a/tutorial/rs/Cargo.toml b/tutorial/rs/Cargo.toml
index e6e1d7c..6967984 100644
--- a/tutorial/rs/Cargo.toml
+++ b/tutorial/rs/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 name = "thrift-tutorial"
 version = "0.1.0"
-edition = "2018"
+edition = "2021"
 license = "Apache-2.0"
 authors = ["Apache Thrift Developers <dev@thrift.apache.org>"]
 exclude = ["Makefile*", "shared.rs", "tutorial.rs"]
diff --git a/tutorial/shared.thrift b/tutorial/shared.thrift
index 795e9cb..3c6a69d 100644
--- a/tutorial/shared.thrift
+++ b/tutorial/shared.thrift
@@ -22,6 +22,7 @@
  * these definitions.
  */
 
+namespace cl shared
 namespace cpp shared
 namespace d share // "shared" would collide with the eponymous D keyword.
 namespace dart shared
diff --git a/tutorial/swift/Makefile.am b/tutorial/swift/Makefile.am
new file mode 100644
index 0000000..f484560
--- /dev/null
+++ b/tutorial/swift/Makefile.am
@@ -0,0 +1,33 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+
+#
+# Common thrift code generation rules
+#
+gen_swift:
+	$(THRIFT) --gen swift -r -o Sources/Common $(top_srcdir)/tutorial/tutorial.thrift
+
+tutorial: gen_swift
+	swift run TutorialRunner
+
+tutorialserver: gen_swift
+	swift run TutorialServer
+
+tutorialclient: gen_swift
+	swift run TutorialClient
diff --git a/tutorial/swift/Package.swift b/tutorial/swift/Package.swift
new file mode 100644
index 0000000..ae3f530
--- /dev/null
+++ b/tutorial/swift/Package.swift
@@ -0,0 +1,53 @@
+// swift-tools-version:5.1
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import PackageDescription
+
+let thriftDependency: Target.Dependency = .product(name: "Thrift", package: "swift-dep")
+let package = Package(
+    name: "swift-tutorial",
+    platforms: [
+        .macOS(.v10_13)
+    ],
+    products: [
+        // Products define the executables and libraries a package produces, and make them visible to other packages.
+        .executable(name: "TutorialServer", targets: ["TutorialServer"]),
+        .executable(name: "TutorialClient", targets: ["TutorialClient"]),
+        .executable(name: "TutorialRunner", targets: ["TutorialRunner"])
+    ],
+    dependencies: [
+        // Dependencies declare other packages that this package depends on.
+        .package(path: "./swift-dep"),
+    ],
+    targets: [
+        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
+        // Targets can depend on other targets in this package, and on products in packages this package depends on.
+        .target(
+            name: "Common",
+            dependencies: [thriftDependency]),
+        .target(
+            name: "TutorialServer",
+            dependencies: [thriftDependency, "Common"]),
+        .target(
+            name: "TutorialClient",
+            dependencies: [thriftDependency, "Common"]),
+        .target(name: "TutorialRunner")
+    ]
+)
diff --git a/tutorial/swift/README.md b/tutorial/swift/README.md
new file mode 100644
index 0000000..18a1e7b
--- /dev/null
+++ b/tutorial/swift/README.md
@@ -0,0 +1,11 @@
+# Thrift Swift Tutorial
+==================================================
+
+## Run the tutorial code (client + server):
+`make tutorial`
+
+## Run the server only
+`make tutorialserver`
+
+## Run the client only
+`make tutorialclient`
diff --git a/tutorial/swift/Sources/TutorialClient/main.swift b/tutorial/swift/Sources/TutorialClient/main.swift
new file mode 100644
index 0000000..ea8720f
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialClient/main.swift
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import Foundation
+import Thrift
+import Common
+
+let transport = try TSocketTransport(hostname: "localhost", port: 9090)
+let inOutProto = TBinaryProtocol(on: transport)
+let client = CalculatorClient(inoutProtocol: inOutProto)
+
+try client.ping()
+print("1+1= \(try client.add(num1: 1, num2: 1))")
+
+let work = Work(num1: 1, num2: 0, op: .divide)
+do {
+    _ = try client.calculate(logid: 1, w: work)
+    assertionFailure("Hm... shouldn't be able to divide by zero")
+} catch let error as InvalidOperation {
+    print("Invalid operation: \(error.why)")
+}
+
+work.op = .subtract
+work.num1 = 15
+work.num2 = 10
+
+print("15-10= \(try client.calculate(logid: 1, w: work))")
+
+print("Done!")
diff --git a/tutorial/swift/Sources/TutorialRunner/main.swift b/tutorial/swift/Sources/TutorialRunner/main.swift
new file mode 100644
index 0000000..7d24391
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialRunner/main.swift
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import Foundation
+
+let swiftUrl = URL(fileURLWithPath: "/usr/bin/swift")
+let server = Process()
+server.executableURL = swiftUrl
+server.arguments = ["run", "TutorialServer"]
+try server.run()
+
+Thread.sleep(forTimeInterval: 2)
+
+let client = Process()
+client.executableURL = swiftUrl
+client.arguments = ["run", "TutorialClient"]
+try client.run()
+client.waitUntilExit()
+
+server.terminate()
diff --git a/tutorial/swift/Sources/TutorialServer/CalculatorService.swift b/tutorial/swift/Sources/TutorialServer/CalculatorService.swift
new file mode 100644
index 0000000..2021cfc
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialServer/CalculatorService.swift
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import Foundation
+import Common
+
+struct CalculatorError: Error {
+    
+}
+class CalculatorService: Calculator {
+    var resultMap = [Int32:SharedStruct]()
+    
+    func ping() throws {
+        print("ping()")
+    }
+    
+    func add(num1: Int32, num2: Int32) throws -> Int32 {
+        print("add(\(num1), \(num2))")
+        return num1 + num2
+    }
+    
+    func calculate(logid: Int32, w: Work) throws -> Int32 {
+        print("calculate(\(logid), \(w))")
+        let result: Int32 = try {
+        switch w.op {
+        case .add:
+            return w.num1 + w.num2
+        case .subtract:
+            return w.num1 - w.num2
+        case .multiply:
+            return w.num1 * w.num2
+        case .divide:
+            guard w.num2 != 0 else {
+                throw InvalidOperation(whatOp: w.op.rawValue, why: "Cannot divide by 0")
+            }
+            return w.num1 / w.num2
+        }
+        }()
+        
+        let resultEntry = SharedStruct(key: logid, value: "\(result)")
+        resultMap[logid] = resultEntry
+        
+        return result
+    }
+    
+    func zip() throws {
+        print("zip()")
+    }
+    
+    func getStruct(key: Int32) throws -> SharedStruct {
+        print("getStruct(\(key))")
+        guard let entry = resultMap[key] else {
+            throw CalculatorError()
+        }
+        return entry
+    }
+}
diff --git a/tutorial/swift/Sources/TutorialServer/main.swift b/tutorial/swift/Sources/TutorialServer/main.swift
new file mode 100644
index 0000000..517a8b1
--- /dev/null
+++ b/tutorial/swift/Sources/TutorialServer/main.swift
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.
+ */
+
+import Foundation
+import Common
+import Thrift
+
+let service = CalculatorService()
+let processor = CalculatorProcessor(service: service)
+let server = try TSocketServer(port: 9090, inProtocol: TBinaryProtocol.self, outProtocol: TBinaryProtocol.self, processor: processor)
+
+RunLoop.main.run()
diff --git a/tutorial/swift/swift-dep b/tutorial/swift/swift-dep
new file mode 120000
index 0000000..c757a77
--- /dev/null
+++ b/tutorial/swift/swift-dep
@@ -0,0 +1 @@
+../../lib/swift
\ No newline at end of file
diff --git a/tutorial/tutorial.thrift b/tutorial/tutorial.thrift
index 6e33130..f1e2912 100644
--- a/tutorial/tutorial.thrift
+++ b/tutorial/tutorial.thrift
@@ -63,6 +63,7 @@
  * target languages.
  */
 
+namespace cl tutorial
 namespace cpp tutorial
 namespace d tutorial
 namespace dart tutorial