Fix for wrong behavior of Json codec when record schema has no fields (#2833)

Co-authored-by: Thiruvalluvan M G <thiru@afer.com>
diff --git a/lang/c++/impl/parsing/JsonCodec.cc b/lang/c++/impl/parsing/JsonCodec.cc
index 4fd0481..a33fd39 100644
--- a/lang/c++/impl/parsing/JsonCodec.cc
+++ b/lang/c++/impl/parsing/JsonCodec.cc
@@ -496,6 +496,7 @@
 template<typename P, typename F>
 void JsonEncoder<P, F>::init(OutputStream &os) {
     out_.init(os);
+    parser_.reset();
 }
 
 template<typename P, typename F>
diff --git a/lang/c++/impl/parsing/Symbol.hh b/lang/c++/impl/parsing/Symbol.hh
index 21e46a8..c8760c3 100644
--- a/lang/c++/impl/parsing/Symbol.hh
+++ b/lang/c++/impl/parsing/Symbol.hh
@@ -363,6 +363,10 @@
 class SimpleParser {
     Decoder *decoder_;
     Handler &handler_;
+    /*
+     * parsingStack always has root at the bottom of it.
+     * So it is safe to call top() on it.
+     */
     std::stack<Symbol> parsingStack;
 
     static void throwMismatch(Symbol::Kind actual, Symbol::Kind expected) {
@@ -742,6 +746,14 @@
             } else if (s.kind() == Symbol::Kind::SkipStart) {
                 parsingStack.pop();
                 skip(*decoder_);
+            } else if (s.kind() == Symbol::Kind::Indirect) {
+                ProductionPtr pp = s.extra<ProductionPtr>();
+                parsingStack.pop();
+                append(pp);
+            } else if (s.kind() == Symbol::Kind::Symbolic) {
+                ProductionPtr pp(s.extra<std::weak_ptr<Production>>());
+                parsingStack.pop();
+                append(pp);
             } else {
                 break;
             }
@@ -756,6 +768,8 @@
         while (parsingStack.size() > 1) {
             parsingStack.pop();
         }
+        Symbol &s = parsingStack.top();
+        append(boost::tuples::get<0>(*s.extrap<RootInfo>()));
     }
 };
 
diff --git a/lang/c++/test/CodecTests.cc b/lang/c++/test/CodecTests.cc
index f24af3a..9c281c5 100644
--- a/lang/c++/test/CodecTests.cc
+++ b/lang/c++/test/CodecTests.cc
@@ -963,6 +963,11 @@
     {R"({"type":"map", "values": "boolean"})",
      "{c1sK5Bc2sK5BsK5B}", 2},
 
+    // Record with no fields
+    {"{\"type\":\"record\",\"name\":\"empty\",\"fields\":[]}",
+     "", 1},
+
+    // Single-field records
     {"{\"type\":\"record\",\"name\":\"r\",\"fields\":["
      "{\"name\":\"f\", \"type\":\"boolean\"}]}",
      "B", 1},
@@ -1002,6 +1007,16 @@
      "{\"name\":\"f7\", \"type\":\"bytes\"}]}",
      "NBILFDS10b25", 1},
     // record of records
+    {"{\"type\":\"record\",\"name\":\"r\",\"fields\":["
+     "{\"name\":\"f1\",\"type\":\"boolean\"},"
+     "{\"name\":\"f2\", \"type\":{\"type\":\"record\","
+     "\"name\":\"inner\",\"fields\":[]}}]}",
+     "B", 1},
+    {"{\"type\":\"record\",\"name\":\"r\",\"fields\":["
+     "{\"name\":\"f1\",\"type\":\"boolean\"},"
+     "{\"name\":\"f2\", \"type\":{\"type\":\"array\","
+     "\"items\":\"r\"}}]}",
+     "B[]", 1},
     {"{\"type\":\"record\",\"name\":\"outer\",\"fields\":["
      "{\"name\":\"f1\", \"type\":{\"type\":\"record\", "
      "\"name\":\"inner\", \"fields\":["