diff --git a/src/core/json/json.c b/src/core/json/json.c
index e7fcec31ffcd742a107ef306cd2a408993d8947f..1cff4fa19514bbdab2e6587b2a061450995841e9 100644
--- a/src/core/json/json.c
+++ b/src/core/json/json.c
@@ -31,23 +31,23 @@
  *
  */
 
+#include <string.h>
+
 #include <grpc/support/alloc.h>
 
 #include "src/core/json/json.h"
 
-grpc_json *grpc_json_new(grpc_json_type type) {
+grpc_json *grpc_json_create(grpc_json_type type) {
   grpc_json *json = gpr_malloc(sizeof(grpc_json));
-  json->parent = json->child = json->next = json->prev = NULL;
+  memset(json, 0, sizeof(grpc_json));
   json->type = type;
 
-  json->value = json->key = NULL;
-
   return json;
 }
 
-void grpc_json_delete(grpc_json *json) {
+void grpc_json_destroy(grpc_json *json) {
   while (json->child) {
-    grpc_json_delete(json->child);
+    grpc_json_destroy(json->child);
   }
 
   if (json->next) {
diff --git a/src/core/json/json.h b/src/core/json/json.h
index 433ba225867beeba34a0f2e8312c9fc094a369c3..6676744ff7ee81fdd2b6597f2dae6f38b40d8d54 100644
--- a/src/core/json/json.h
+++ b/src/core/json/json.h
@@ -63,7 +63,7 @@ typedef struct grpc_json {
  * All the keys and values in the grpc_json_t objects will be strings
  * pointing at your input buffer.
  *
- * Delete the allocated tree afterward using grpc_json_delete().
+ * Delete the allocated tree afterward using grpc_json_destroy().
  */
 grpc_json* grpc_json_parse_string_with_len(char* input, size_t size);
 grpc_json* grpc_json_parse_string(char* input);
@@ -82,7 +82,7 @@ char* grpc_json_dump_to_string(grpc_json* json, int indent);
  * Deletion is recursive. We will not attempt to free any of the strings
  * in any of the objects of that tree.
  */
-grpc_json* grpc_json_new(grpc_json_type type);
-void grpc_json_delete(grpc_json* json);
+grpc_json* grpc_json_create(grpc_json_type type);
+void grpc_json_destroy(grpc_json* json);
 
 #endif /* __GRPC_SRC_CORE_JSON_JSON_H__ */
diff --git a/src/core/json/json_reader.c b/src/core/json/json_reader.c
index 7f52bf2b6d8d30d897f588fbef19a1e1e185b20f..304da2a26b74b6fced931bfa8b7e6900995b10bf 100644
--- a/src/core/json/json_reader.c
+++ b/src/core/json/json_reader.c
@@ -31,69 +31,72 @@
  *
  */
 
+#include <string.h>
+
 #include <grpc/support/port_platform.h>
+
 #include "src/core/json/json_reader.h"
 
-static void grpc_json_reader_string_clear(grpc_json_reader* reader) {
-  reader->string_clear(reader);
+static void json_reader_string_clear(grpc_json_reader* reader) {
+  reader->vtable->string_clear(reader->userdata);
 }
 
-static void grpc_json_reader_string_add_char(grpc_json_reader* reader,
+static void json_reader_string_add_char(grpc_json_reader* reader,
                                              gpr_uint32 c) {
-  reader->string_add_char(reader, c);
+  reader->vtable->string_add_char(reader->userdata, c);
 }
 
-static void grpc_json_reader_string_add_utf32(grpc_json_reader* reader,
+static void json_reader_string_add_utf32(grpc_json_reader* reader,
                                               gpr_uint32 utf32) {
-  reader->string_add_utf32(reader, utf32);
+  reader->vtable->string_add_utf32(reader->userdata, utf32);
 }
 
 static gpr_uint32
     grpc_json_reader_read_char(grpc_json_reader* reader) {
-  return reader->read_char(reader);
+  return reader->vtable->read_char(reader->userdata);
 }
 
-static void grpc_json_reader_container_begins(grpc_json_reader* reader,
+static void json_reader_container_begins(grpc_json_reader* reader,
                                               grpc_json_type type) {
-  reader->container_begins(reader, type);
+  reader->vtable->container_begins(reader->userdata, type);
 }
 
 static grpc_json_type
     grpc_json_reader_container_ends(grpc_json_reader* reader) {
-  return reader->container_ends(reader);
+  return reader->vtable->container_ends(reader->userdata);
 }
 
-static void grpc_json_reader_set_key(grpc_json_reader* reader) {
-  reader->set_key(reader);
+static void json_reader_set_key(grpc_json_reader* reader) {
+  reader->vtable->set_key(reader->userdata);
 }
 
-static void grpc_json_reader_set_string(grpc_json_reader* reader) {
-  reader->set_string(reader);
+static void json_reader_set_string(grpc_json_reader* reader) {
+  reader->vtable->set_string(reader->userdata);
 }
 
-static int grpc_json_reader_set_number(grpc_json_reader* reader) {
-  return reader->set_number(reader);
+static int json_reader_set_number(grpc_json_reader* reader) {
+  return reader->vtable->set_number(reader->userdata);
 }
 
-static void grpc_json_reader_set_true(grpc_json_reader* reader) {
-  reader->set_true(reader);
+static void json_reader_set_true(grpc_json_reader* reader) {
+  reader->vtable->set_true(reader->userdata);
 }
 
-static void grpc_json_reader_set_false(grpc_json_reader* reader) {
-  reader->set_false(reader);
+static void json_reader_set_false(grpc_json_reader* reader) {
+  reader->vtable->set_false(reader->userdata);
 }
 
-static void grpc_json_reader_set_null(grpc_json_reader* reader) {
-  reader->set_null(reader);
+static void json_reader_set_null(grpc_json_reader* reader) {
+  reader->vtable->set_null(reader->userdata);
 }
 
 /* Call this function to initialize the reader structure. */
-void grpc_json_reader_init(grpc_json_reader* reader) {
-  reader->depth = 0;
-  reader->in_object = 0;
-  reader->in_array = 0;
-  reader->unicode_high_surrogate = 0;
-  grpc_json_reader_string_clear(reader);
+void grpc_json_reader_init(grpc_json_reader* reader,
+                           grpc_json_reader_vtable* vtable, void* userdata) {
+  memset(reader, 0, sizeof(grpc_json_reader));
+  reader->vtable = vtable;
+  reader->userdata = userdata;
+  json_reader_string_clear(reader);
   reader->state = GRPC_JSON_STATE_VALUE_BEGIN;
 }
 
@@ -102,7 +105,7 @@ int grpc_json_reader_is_complete(grpc_json_reader* reader) {
           (reader->state == GRPC_JSON_STATE_VALUE_END)));
 }
 
-grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
+grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader) {
   gpr_uint32 c, success;
 
   /* This state-machine is a strict implementation of ECMA-404 */
@@ -140,17 +143,17 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
           case GRPC_JSON_STATE_OBJECT_KEY_STRING:
           case GRPC_JSON_STATE_VALUE_STRING:
             if (c != ' ') return GRPC_JSON_PARSE_ERROR;
-            if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_add_char(reader, c);
+            if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, c);
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER:
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = grpc_json_reader_set_number(reader);
+            success = json_reader_set_number(reader);
             if (!success) return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_clear(reader);
+            json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
             break;
 
@@ -166,17 +169,17 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
         switch (reader->state) {
           case GRPC_JSON_STATE_OBJECT_KEY_STRING:
           case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_add_char(reader, c);
+            if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, c);
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER:
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            success = grpc_json_reader_set_number(reader);
+            success = json_reader_set_number(reader);
             if (!success) return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_clear(reader);
+            json_reader_string_clear(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
           /* The missing break here is intentional. */
 
@@ -250,8 +253,8 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
           /* This is the \\ case. */
           case GRPC_JSON_STATE_STRING_ESCAPE:
-            if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_add_char(reader, '\\');
+            if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
+            json_reader_string_add_char(reader, '\\');
             if (reader->escaped_string_was_key) {
               reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
             } else {
@@ -273,26 +276,26 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             break;
 
           case GRPC_JSON_STATE_OBJECT_KEY_STRING:
-            if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
+            if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
             if (c == '"') {
               reader->state = GRPC_JSON_STATE_OBJECT_KEY_END;
-              grpc_json_reader_set_key(reader);
-              grpc_json_reader_string_clear(reader);
+              json_reader_set_key(reader);
+              json_reader_string_clear(reader);
             } else {
-              if (c < 32) return GRPC_JSON_PARSE_ERROR;
-              grpc_json_reader_string_add_char(reader, c);
+              if (c <= 0x001f) return GRPC_JSON_PARSE_ERROR;
+              json_reader_string_add_char(reader, c);
             }
             break;
 
           case GRPC_JSON_STATE_VALUE_STRING:
-            if (reader->unicode_high_surrogate) return GRPC_JSON_PARSE_ERROR;
+            if (reader->unicode_high_surrogate != 0) return GRPC_JSON_PARSE_ERROR;
             if (c == '"') {
               reader->state = GRPC_JSON_STATE_VALUE_END;
-              grpc_json_reader_set_string(reader);
-              grpc_json_reader_string_clear(reader);
+              json_reader_set_string(reader);
+              json_reader_string_clear(reader);
             } else {
               if (c < 32) return GRPC_JSON_PARSE_ERROR;
-              grpc_json_reader_string_add_char(reader, c);
+              json_reader_string_add_char(reader, c);
             }
             break;
 
@@ -333,13 +336,13 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
               case '8':
               case '9':
               case '-':
-                grpc_json_reader_string_add_char(reader, c);
+                json_reader_string_add_char(reader, c);
                 reader->state = GRPC_JSON_STATE_VALUE_NUMBER;
                 break;
 
               case '{':
                 reader->container_just_begun = 1;
-                grpc_json_reader_container_begins(reader, GRPC_JSON_OBJECT);
+                json_reader_container_begins(reader, GRPC_JSON_OBJECT);
                 reader->depth++;
                 reader->state = GRPC_JSON_STATE_OBJECT_KEY_BEGIN;
                 reader->in_object = 1;
@@ -348,7 +351,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
               case '[':
                 reader->container_just_begun = 1;
-                grpc_json_reader_container_begins(reader, GRPC_JSON_ARRAY);
+                json_reader_container_begins(reader, GRPC_JSON_ARRAY);
                 reader->depth++;
                 reader->in_object = 0;
                 reader->in_array = 1;
@@ -367,22 +370,22 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             switch (c) {
               case '"':
               case '/':
-                grpc_json_reader_string_add_char(reader, c);
+                json_reader_string_add_char(reader, c);
                 break;
               case 'b':
-                grpc_json_reader_string_add_char(reader, '\b');
+                json_reader_string_add_char(reader, '\b');
                 break;
               case 'f':
-                grpc_json_reader_string_add_char(reader, '\f');
+                json_reader_string_add_char(reader, '\f');
                 break;
               case 'n':
-                grpc_json_reader_string_add_char(reader, '\n');
+                json_reader_string_add_char(reader, '\n');
                 break;
               case 'r':
-                grpc_json_reader_string_add_char(reader, '\r');
+                json_reader_string_add_char(reader, '\r');
                 break;
               case 't':
-                grpc_json_reader_string_add_char(reader, '\t');
+                json_reader_string_add_char(reader, '\t');
                 break;
               case 'u':
                 reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U1;
@@ -420,26 +423,29 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
                 reader->state = GRPC_JSON_STATE_STRING_ESCAPE_U4;
                 break;
               case GRPC_JSON_STATE_STRING_ESCAPE_U4:
+                /* See grpc_json_writer_escape_string to have a description
+                 * of what's going on here.
+                 */
                 if ((reader->unicode_char & 0xfc00) == 0xd800) {
                   /* high surrogate utf-16 */
-                  if (reader->unicode_high_surrogate)
+                  if (reader->unicode_high_surrogate != 0)
                     return GRPC_JSON_PARSE_ERROR;
                   reader->unicode_high_surrogate = reader->unicode_char;
                 } else if ((reader->unicode_char & 0xfc00) == 0xdc00) {
                   /* low surrogate utf-16 */
                   gpr_uint32 utf32;
-                  if (!reader->unicode_high_surrogate)
+                  if (reader->unicode_high_surrogate == 0)
                     return GRPC_JSON_PARSE_ERROR;
                   utf32 = 0x10000;
                   utf32 += (reader->unicode_high_surrogate - 0xd800) * 0x400;
                   utf32 += reader->unicode_char - 0xdc00;
-                  grpc_json_reader_string_add_utf32(reader, utf32);
+                  json_reader_string_add_utf32(reader, utf32);
                   reader->unicode_high_surrogate = 0;
                 } else {
                   /* anything else */
-                  if (reader->unicode_high_surrogate)
+                  if (reader->unicode_high_surrogate != 0)
                     return GRPC_JSON_PARSE_ERROR;
-                  grpc_json_reader_string_add_utf32(reader, reader->unicode_char);
+                  json_reader_string_add_utf32(reader, reader->unicode_char);
                 }
                 if (reader->escaped_string_was_key) {
                   reader->state = GRPC_JSON_STATE_OBJECT_KEY_STRING;
@@ -453,7 +459,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER:
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             switch (c) {
               case '0':
               case '1':
@@ -475,7 +481,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER_WITH_DECIMAL:
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             switch (c) {
               case '0':
               case '1':
@@ -499,12 +505,12 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
           case GRPC_JSON_STATE_VALUE_NUMBER_ZERO:
             if (c != '.') return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             reader->state = GRPC_JSON_STATE_VALUE_NUMBER_DOT;
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER_DOT:
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             switch (c) {
               case '0':
               case '1':
@@ -524,7 +530,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             break;
 
           case GRPC_JSON_STATE_VALUE_NUMBER_E:
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             switch (c) {
               case '0':
               case '1':
@@ -545,7 +551,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
             }
 
           case GRPC_JSON_STATE_VALUE_NUMBER_EPM:
-            grpc_json_reader_string_add_char(reader, c);
+            json_reader_string_add_char(reader, c);
             switch (c) {
               case '0':
               case '1':
@@ -574,7 +580,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
           case GRPC_JSON_STATE_VALUE_TRUE_E:
             if (c != 'e') return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_set_true(reader);
+            json_reader_set_true(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
             break;
 
@@ -595,7 +601,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
           case GRPC_JSON_STATE_VALUE_FALSE_E:
             if (c != 'e') return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_set_false(reader);
+            json_reader_set_false(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
             break;
 
@@ -611,7 +617,7 @@ grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader) {
 
           case GRPC_JSON_STATE_VALUE_NULL_L2:
             if (c != 'l') return GRPC_JSON_PARSE_ERROR;
-            grpc_json_reader_set_null(reader);
+            json_reader_set_null(reader);
             reader->state = GRPC_JSON_STATE_VALUE_END;
             break;
 
diff --git a/src/core/json/json_reader.h b/src/core/json/json_reader.h
index d71f0b8e6634e200ad45ecaad3e37a6f96de33e1..388ee3633fb4812daf76e848502fd9e7baeaf366 100644
--- a/src/core/json/json_reader.h
+++ b/src/core/json/json_reader.h
@@ -78,39 +78,40 @@ enum {
   GRPC_JSON_READ_CHAR_ERROR
 };
 
-typedef struct grpc_json_reader {
-  /* You are responsible for your own opaque userdata.
-   * Among other things, it needs to hold a string scratchpad.
-   */
-  void* userdata;
-
-  /* You also need to set up these callbacks. */
+struct grpc_json_reader;
 
+typedef struct grpc_json_reader_vtable {
   /* Clears your internal string scratchpad. */
-  void (*string_clear)(struct grpc_json_reader*);
+  void (*string_clear)(void* userdata);
   /* Adds a char to the string scratchpad. */
-  void (*string_add_char)(struct grpc_json_reader*, gpr_uint32 c);
+  void (*string_add_char)(void* userdata, gpr_uint32 c);
   /* Adds a utf32 char to the string scratchpad. */
-  void (*string_add_utf32)(struct grpc_json_reader*, gpr_uint32 c);
+  void (*string_add_utf32)(void* userdata, gpr_uint32 c);
   /* Reads a character from your input. May be utf-8, 16 or 32. */
-  gpr_uint32 (*read_char)(struct grpc_json_reader*);
+  gpr_uint32 (*read_char)(void* userdata);
   /* Starts a container of type GRPC_JSON_ARRAY or GRPC_JSON_OBJECT. */
-  void (*container_begins)(struct grpc_json_reader*, grpc_json_type type);
+  void (*container_begins)(void* userdata, grpc_json_type type);
   /* Ends the current container. Must return the type of its parent. */
-  grpc_json_type (*container_ends)(struct grpc_json_reader*);
+  grpc_json_type (*container_ends)(void* userdata);
   /* Your internal string scratchpad is an object's key. */
-  void (*set_key)(struct grpc_json_reader*);
+  void (*set_key)(void* userdata);
   /* Your internal string scratchpad is a string value. */
-  void (*set_string)(struct grpc_json_reader*);
+  void (*set_string)(void* userdata);
   /* Your internal string scratchpad is a numerical value. Return 1 if valid. */
-  int (*set_number)(struct grpc_json_reader*);
+  int (*set_number)(void* userdata);
   /* Sets the values true, false or null. */
-  void (*set_true)(struct grpc_json_reader*);
-  void (*set_false)(struct grpc_json_reader*);
-  void (*set_null)(struct grpc_json_reader*);
+  void (*set_true)(void* userdata);
+  void (*set_false)(void* userdata);
+  void (*set_null)(void* userdata);
+} grpc_json_reader_vtable;
 
-  /* Everything down here is private,
-     and initialized by grpc_json_reader_init. */
+typedef struct grpc_json_reader {
+  /* That structure is fully private, and initialized by grpc_json_reader_init.
+   * The definition is public so you can put it on your stack.
+   */
+
+  void* userdata;
+  grpc_json_reader_vtable* vtable;
   int depth;
   int in_object;
   int in_array;
@@ -127,7 +128,7 @@ typedef enum {
   GRPC_JSON_READ_ERROR,    /* The parser passes through a read error. */
   GRPC_JSON_PARSE_ERROR,   /* The parser found an error in the json stream. */
   GRPC_JSON_INTERNAL_ERROR /* The parser got an internal error. */
-} grpc_json_reader_ret;
+} grpc_json_reader_status;
 
 /* Call this function to start parsing the input. It will return the following:
  *    . GRPC_JSON_DONE if the input got eof, and the parsing finished
@@ -143,10 +144,11 @@ typedef enum {
  *    . GRPC_JSON_INTERNAL_ERROR if the parser somehow ended into an invalid
  *      internal state.
  */
-grpc_json_reader_ret grpc_json_reader_run(grpc_json_reader* reader);
+grpc_json_reader_status grpc_json_reader_run(grpc_json_reader* reader);
 
 /* Call this function to initialize the reader structure. */
-void grpc_json_reader_init(grpc_json_reader* reader);
+void grpc_json_reader_init(grpc_json_reader* reader,
+                           grpc_json_reader_vtable* vtable, void* userdata);
 
 /* You may call this from the read_char callback if you don't know where is the
  * end of your input stream, and you'd like the json reader to hint you that it
diff --git a/src/core/json/json_string.c b/src/core/json/json_string.c
index 12309c4dbc701ff5f121ad585283c6ffe6442be3..d016f07c5a5ad605393f6b9ca7951f94d3d5e108 100644
--- a/src/core/json/json_string.c
+++ b/src/core/json/json_string.c
@@ -61,24 +61,25 @@ typedef struct {
   char* string;
   char* string_ptr;
   size_t remaining_input;
-} grpc_json_reader_opaque;
+} json_reader_userdata;
 
 /* This json writer will put everything in a big string.
  * The point is that we allocate that string in chunks of 256 bytes.
  */
 typedef struct {
   char* output;
-  size_t free_space, string_len, allocated;
-} grpc_json_writer_opaque;
+  size_t free_space;
+  size_t string_len;
+  size_t allocated;
+} json_writer_userdata;
 
 
 /* This function checks if there's enough space left in the output buffer,
  * and will enlarge it if necessary. We're only allocating chunks of 256
  * bytes at a time (or multiples thereof).
  */
-static void grpc_json_writer_output_check(grpc_json_writer* writer,
-                                          size_t needed) {
-  grpc_json_writer_opaque* state = writer->userdata;
+static void json_writer_output_check(void* userdata, size_t needed) {
+  json_writer_userdata* state = userdata;
   if (state->free_space >= needed) return;
   needed -= state->free_space;
   /* Round up by 256 bytes. */
@@ -89,34 +90,33 @@ static void grpc_json_writer_output_check(grpc_json_writer* writer,
 }
 
 /* These are needed by the writer's implementation. */
-static void grpc_json_writer_output_char(grpc_json_writer* writer,
-                                         char c) {
-  grpc_json_writer_opaque* state = writer->userdata;
-  grpc_json_writer_output_check(writer, 1);
+static void json_writer_output_char(void* userdata, char c) {
+  json_writer_userdata* state = userdata;
+  json_writer_output_check(userdata, 1);
   state->output[state->string_len++] = c;
   state->free_space--;
 }
 
-static void grpc_json_writer_output_string_with_len(
-    grpc_json_writer* writer, const char* str, size_t len) {
-  grpc_json_writer_opaque* state = writer->userdata;
-  grpc_json_writer_output_check(writer, len);
+static void json_writer_output_string_with_len(void* userdata,
+                                               const char* str, size_t len) {
+  json_writer_userdata* state = userdata;
+  json_writer_output_check(userdata, len);
   memcpy(state->output + state->string_len, str, len);
   state->string_len += len;
   state->free_space -= len;
 }
 
-static void grpc_json_writer_output_string(grpc_json_writer* writer,
+static void json_writer_output_string(void* userdata,
                                            const char* str) {
   size_t len = strlen(str);
-  grpc_json_writer_output_string_with_len(writer, str, len);
+  json_writer_output_string_with_len(userdata, str, len);
 }
 
 /* The reader asks us to clear our scratchpad. In our case, we'll simply mark
  * the end of the current string, and advance our output pointer.
  */
-static void grpc_json_reader_string_clear(grpc_json_reader* reader) {
-  grpc_json_reader_opaque* state = reader->userdata;
+static void json_reader_string_clear(void* userdata) {
+  json_reader_userdata* state = userdata;
   if (state->string) {
     GPR_ASSERT(state->string_ptr < state->input);
     *state->string_ptr++ = 0;
@@ -124,47 +124,49 @@ static void grpc_json_reader_string_clear(grpc_json_reader* reader) {
   state->string = state->string_ptr;
 }
 
-static void grpc_json_reader_string_add_char(grpc_json_reader* reader, gpr_uint32 c) {
-  grpc_json_reader_opaque* state = reader->userdata;
+static void json_reader_string_add_char(void* userdata, gpr_uint32 c) {
+  json_reader_userdata* state = userdata;
   GPR_ASSERT(state->string_ptr < state->input);
   GPR_ASSERT(c <= 0xff);
   *state->string_ptr++ = (char)c;
 }
 
-/* We are converting a UTF-32 character into UTF-8 here. */
-static void grpc_json_reader_string_add_utf32(grpc_json_reader* reader, gpr_uint32 c) {
+/* We are converting a UTF-32 character into UTF-8 here,
+ * as described by RFC3629.
+ */
+static void json_reader_string_add_utf32(void* userdata, gpr_uint32 c) {
   if (c <= 0x7f) {
-    grpc_json_reader_string_add_char(reader, c);
+    json_reader_string_add_char(userdata, c);
   } else if (c <= 0x7ff) {
     int b1 = 0xc0 | ((c >> 6) & 0x1f);
     int b2 = 0x80 | (c & 0x3f);
-    grpc_json_reader_string_add_char(reader, b1);
-    grpc_json_reader_string_add_char(reader, b2);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
   } else if (c <= 0xffff) {
     int b1 = 0xe0 | ((c >> 12) & 0x0f);
     int b2 = 0x80 | ((c >> 6) & 0x3f);
     int b3 = 0x80 | (c & 0x3f);
-    grpc_json_reader_string_add_char(reader, b1);
-    grpc_json_reader_string_add_char(reader, b2);
-    grpc_json_reader_string_add_char(reader, b3);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+    json_reader_string_add_char(userdata, b3);
   } else if (c <= 0x1fffff) {
     int b1 = 0xf0 | ((c >> 18) & 0x07);
     int b2 = 0x80 | ((c >> 12) & 0x3f);
     int b3 = 0x80 | ((c >> 6) & 0x3f);
     int b4 = 0x80 | (c & 0x3f);
-    grpc_json_reader_string_add_char(reader, b1);
-    grpc_json_reader_string_add_char(reader, b2);
-    grpc_json_reader_string_add_char(reader, b3);
-    grpc_json_reader_string_add_char(reader, b4);
+    json_reader_string_add_char(userdata, b1);
+    json_reader_string_add_char(userdata, b2);
+    json_reader_string_add_char(userdata, b3);
+    json_reader_string_add_char(userdata, b4);
   }
 }
 
 /* We consider that the input may be a zero-terminated string. So we
  * can end up hitting eof before the end of the alleged string length.
  */
-static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) {
+static gpr_uint32 json_reader_read_char(void* userdata) {
   gpr_uint32 r;
-  grpc_json_reader_opaque* state = reader->userdata;
+  json_reader_userdata* state = userdata;
 
   if (state->remaining_input == 0) return GRPC_JSON_READ_CHAR_EOF;
 
@@ -182,10 +184,10 @@ static gpr_uint32 grpc_json_reader_read_char(grpc_json_reader* reader) {
 /* Helper function to create a new grpc_json object and link it into
  * our tree-in-progress inside our opaque structure.
  */
-static grpc_json* grpc_json_new_and_link(grpc_json_reader* reader,
-                                         grpc_json_type type) {
-  grpc_json_reader_opaque* state = reader->userdata;
-  grpc_json* json = grpc_json_new(type);
+static grpc_json* json_create_and_link(void* userdata,
+                                       grpc_json_type type) {
+  json_reader_userdata* state = userdata;
+  grpc_json* json = grpc_json_create(type);
 
   json->parent = state->current_container;
   json->prev = state->current_value;
@@ -209,14 +211,13 @@ static grpc_json* grpc_json_new_and_link(grpc_json_reader* reader,
   return json;
 }
 
-static void grpc_json_reader_container_begins(grpc_json_reader* reader,
-                                              grpc_json_type type) {
-  grpc_json_reader_opaque* state = reader->userdata;
+static void json_reader_container_begins(void* userdata, grpc_json_type type) {
+  json_reader_userdata* state = userdata;
   grpc_json* container;
 
   GPR_ASSERT(type == GRPC_JSON_ARRAY || type == GRPC_JSON_OBJECT);
 
-  container = grpc_json_new_and_link(reader, type);
+  container = json_create_and_link(userdata, type);
   state->current_container = container;
   state->current_value = NULL;
 }
@@ -230,10 +231,9 @@ static void grpc_json_reader_container_begins(grpc_json_reader* reader,
  * Also note that if we're at the top of the tree, and the last container
  * ends, we have to return GRPC_JSON_TOP_LEVEL.
  */
-static grpc_json_type grpc_json_reader_container_ends(
-    grpc_json_reader* reader) {
+static grpc_json_type json_reader_container_ends(void* userdata) {
   grpc_json_type container_type = GRPC_JSON_TOP_LEVEL;
-  grpc_json_reader_opaque* state = reader->userdata;
+  json_reader_userdata* state = userdata;
 
   GPR_ASSERT(state->current_container);
 
@@ -253,22 +253,20 @@ static grpc_json_type grpc_json_reader_container_ends(
  * Note that in the set_number case, we're not going to try interpreting it.
  * We'll keep it as a string, and leave it to the caller to evaluate it.
  */
-static void grpc_json_reader_set_key(grpc_json_reader* reader) {
-  grpc_json_reader_opaque* state = reader->userdata;
+static void json_reader_set_key(void* userdata) {
+  json_reader_userdata* state = userdata;
   state->key = state->string;
 }
 
-static void grpc_json_reader_set_string(
-    grpc_json_reader* reader) {
-  grpc_json_reader_opaque* state = reader->userdata;
-  grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_STRING);
+static void json_reader_set_string(void* userdata) {
+  json_reader_userdata* state = userdata;
+  grpc_json* json = json_create_and_link(userdata, GRPC_JSON_STRING);
   json->value = state->string;
 }
 
-static int grpc_json_reader_set_number(
-    grpc_json_reader* reader) {
-  grpc_json_reader_opaque* state = reader->userdata;
-  grpc_json* json = grpc_json_new_and_link(reader, GRPC_JSON_NUMBER);
+static int json_reader_set_number(void* userdata) {
+  json_reader_userdata* state = userdata;
+  grpc_json* json = json_create_and_link(userdata, GRPC_JSON_NUMBER);
   json->value = state->string;
   return 1;
 }
@@ -276,27 +274,39 @@ static int grpc_json_reader_set_number(
 /* The object types true, false and null are self-sufficient, and don't need
  * any more information beside their type.
  */
-static void grpc_json_reader_set_true(
-    grpc_json_reader *reader) {
-  grpc_json_new_and_link(reader, GRPC_JSON_TRUE);
+static void json_reader_set_true(void* userdata) {
+  json_create_and_link(userdata, GRPC_JSON_TRUE);
 }
 
-static void grpc_json_reader_set_false(
-    grpc_json_reader *reader) {
-  grpc_json_new_and_link(reader, GRPC_JSON_FALSE);
+static void json_reader_set_false(void* userdata) {
+  json_create_and_link(userdata, GRPC_JSON_FALSE);
 }
 
-static void grpc_json_reader_set_null(
-    grpc_json_reader *reader) {
-  grpc_json_new_and_link(reader, GRPC_JSON_NULL);
+static void json_reader_set_null(void* userdata) {
+  json_create_and_link(userdata, GRPC_JSON_NULL);
 }
 
+static grpc_json_reader_vtable reader_vtable = {
+  json_reader_string_clear,
+  json_reader_string_add_char,
+  json_reader_string_add_utf32,
+  json_reader_read_char,
+  json_reader_container_begins,
+  json_reader_container_ends,
+  json_reader_set_key,
+  json_reader_set_string,
+  json_reader_set_number,
+  json_reader_set_true,
+  json_reader_set_false,
+  json_reader_set_null
+};
+
 /* And finally, let's define our public API. */
 grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
   grpc_json_reader reader;
-  grpc_json_reader_opaque state;
+  json_reader_userdata state;
   grpc_json *json = NULL;
-  grpc_json_reader_ret status;
+  grpc_json_reader_status status;
 
   if (!input) return NULL;
 
@@ -304,26 +314,13 @@ grpc_json* grpc_json_parse_string_with_len(char* input, size_t size) {
   state.string = state.key = NULL;
   state.string_ptr = state.input = input;
   state.remaining_input = size;
-  reader.userdata = &state;
-  reader.string_clear = grpc_json_reader_string_clear;
-  reader.string_add_char = grpc_json_reader_string_add_char;
-  reader.string_add_utf32 = grpc_json_reader_string_add_utf32;
-  reader.read_char = grpc_json_reader_read_char;
-  reader.container_begins = grpc_json_reader_container_begins;
-  reader.container_ends = grpc_json_reader_container_ends;
-  reader.set_key = grpc_json_reader_set_key;
-  reader.set_string = grpc_json_reader_set_string;
-  reader.set_number = grpc_json_reader_set_number;
-  reader.set_true = grpc_json_reader_set_true;
-  reader.set_false = grpc_json_reader_set_false;
-  reader.set_null = grpc_json_reader_set_null;
-  grpc_json_reader_init(&reader);
+  grpc_json_reader_init(&reader, &reader_vtable, &state);
 
   status = grpc_json_reader_run(&reader);
   json = state.top;
 
   if ((status != GRPC_JSON_DONE) && json) {
-    grpc_json_delete(json);
+    grpc_json_destroy(json);
     json = NULL;
   }
 
@@ -336,8 +333,8 @@ grpc_json* grpc_json_parse_string(char* input) {
   return grpc_json_parse_string_with_len(input, UNBOUND_JSON_STRING_LENGTH);
 }
 
-static void grpc_json_dump_recursive(grpc_json_writer* writer,
-                                     grpc_json* json, int in_object) {
+static void json_dump_recursive(grpc_json_writer* writer,
+                                grpc_json* json, int in_object) {
   while (json) {
     if (in_object) grpc_json_writer_object_key(writer, json->key);
 
@@ -346,8 +343,8 @@ static void grpc_json_dump_recursive(grpc_json_writer* writer,
       case GRPC_JSON_ARRAY:
         grpc_json_writer_container_begins(writer, json->type);
         if (json->child)
-          grpc_json_dump_recursive(writer, json->child,
-                                   json->type == GRPC_JSON_OBJECT);
+          json_dump_recursive(writer, json->child,
+                              json->type == GRPC_JSON_OBJECT);
         grpc_json_writer_container_ends(writer, json->type);
         break;
       case GRPC_JSON_STRING:
@@ -372,20 +369,23 @@ static void grpc_json_dump_recursive(grpc_json_writer* writer,
   }
 }
 
+static grpc_json_writer_vtable writer_vtable = {
+  json_writer_output_char,
+  json_writer_output_string,
+  json_writer_output_string_with_len
+};
+
 char* grpc_json_dump_to_string(grpc_json* json, int indent) {
   grpc_json_writer writer;
-  grpc_json_writer_opaque state;
+  json_writer_userdata state;
+
   state.output = NULL;
   state.free_space = state.string_len = state.allocated = 0;
-  writer.userdata = &state;
-  writer.output_char = grpc_json_writer_output_char;
-  writer.output_string = grpc_json_writer_output_string;
-  writer.output_string_with_len = grpc_json_writer_output_string_with_len;
-  grpc_json_writer_init(&writer, indent);
+  grpc_json_writer_init(&writer, indent, &writer_vtable, &state);
 
-  grpc_json_dump_recursive(&writer, json, 0);
+  json_dump_recursive(&writer, json, 0);
 
-  grpc_json_writer_output_char(&writer, 0);
+  json_writer_output_char(&state, 0);
 
   return state.output;
 }
diff --git a/src/core/json/json_writer.c b/src/core/json/json_writer.c
index 9fc65aa83c338ccf7937f30437887100864d4006..5e7b107a03657ff5fd54794284887120f98451bb 100644
--- a/src/core/json/json_writer.c
+++ b/src/core/json/json_writer.c
@@ -31,30 +31,34 @@
  *
  */
 
+#include <string.h>
+
 #include <grpc/support/port_platform.h>
+
 #include "src/core/json/json_writer.h"
 
-static void grpc_json_writer_output_char(grpc_json_writer* writer, char c) {
-  writer->output_char(writer, c);
+static void json_writer_output_char(grpc_json_writer* writer, char c) {
+  writer->vtable->output_char(writer->userdata, c);
 }
 
-static void grpc_json_writer_output_string(grpc_json_writer* writer, const char* str) {
-  writer->output_string(writer, str);
+static void json_writer_output_string(grpc_json_writer* writer, const char* str) {
+  writer->vtable->output_string(writer->userdata, str);
 }
 
-static void grpc_json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) {
-  writer->output_string_with_len(writer, str, len);
+static void json_writer_output_string_with_len(grpc_json_writer* writer, const char* str, size_t len) {
+  writer->vtable->output_string_with_len(writer->userdata, str, len);
 }
 
-/* Call this function to initialize the writer structure. */
-void grpc_json_writer_init(grpc_json_writer* writer, int indent) {
-  writer->depth = 0;
+void grpc_json_writer_init(grpc_json_writer* writer, int indent,
+                           grpc_json_writer_vtable* vtable, void* userdata) {
+  memset(writer, 0, sizeof(grpc_json_writer));
   writer->container_empty = 1;
-  writer->got_key = 0;
   writer->indent = indent;
+  writer->vtable = vtable;
+  writer->userdata = userdata;
 }
 
-static void grpc_json_writer_output_indent(
+static void json_writer_output_indent(
     grpc_json_writer* writer) {
   static const char spacesstr[] =
       "                "
@@ -64,77 +68,78 @@ static void grpc_json_writer_output_indent(
 
   int spaces = writer->depth * writer->indent;
 
+  if (writer->indent == 0) return;
+
   if (writer->got_key) {
-    grpc_json_writer_output_char(writer, ' ');
+    json_writer_output_char(writer, ' ');
     return;
   }
 
   while (spaces >= (sizeof(spacesstr) - 1)) {
-    grpc_json_writer_output_string_with_len(writer, spacesstr,
+    json_writer_output_string_with_len(writer, spacesstr,
                                             sizeof(spacesstr) - 1);
     spaces -= (sizeof(spacesstr) - 1);
   }
 
-  if (!spaces) return;
+  if (spaces == 0) return;
 
-  grpc_json_writer_output_string_with_len(
+  json_writer_output_string_with_len(
       writer, spacesstr + sizeof(spacesstr) - 1 - spaces, spaces);
 }
 
-static void grpc_json_writer_value_end(
-    grpc_json_writer* writer) {
+static void json_writer_value_end(grpc_json_writer* writer) {
   if (writer->container_empty) {
     writer->container_empty = 0;
-    if (!writer->indent || !writer->depth) return;
-    grpc_json_writer_output_char(writer, '\n');
+    if ((writer->indent == 0) || (writer->depth == 0)) return;
+    json_writer_output_char(writer, '\n');
   } else {
-    grpc_json_writer_output_char(writer, ',');
-    if (!writer->indent) return;
-    grpc_json_writer_output_char(writer, '\n');
+    json_writer_output_char(writer, ',');
+    if (writer->indent == 0) return;
+    json_writer_output_char(writer, '\n');
   }
 }
 
-static void grpc_json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) {
+static void json_writer_escape_utf16(grpc_json_writer* writer, gpr_uint16 utf16) {
   static const char hex[] = "0123456789abcdef";
 
-  grpc_json_writer_output_string_with_len(writer, "\\u", 2);
-  grpc_json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
-  grpc_json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
-  grpc_json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
-  grpc_json_writer_output_char(writer, hex[(utf16) & 0x0f]);
+  json_writer_output_string_with_len(writer, "\\u", 2);
+  json_writer_output_char(writer, hex[(utf16 >> 12) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16 >> 8) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16 >> 4) & 0x0f]);
+  json_writer_output_char(writer, hex[(utf16) & 0x0f]);
 }
 
-static void grpc_json_writer_escape_string(
-    grpc_json_writer* writer, const char* string) {
-  grpc_json_writer_output_char(writer, '"');
+static void json_writer_escape_string(grpc_json_writer* writer,
+                                      const char* string) {
+  json_writer_output_char(writer, '"');
 
   for (;;) {
-    unsigned char c = (unsigned char)*string++;
-    if (!c) {
+    gpr_uint8 c = (gpr_uint8)*string++;
+    if (c == 0) {
       break;
     } else if ((c >= 32) && (c <= 127)) {
-      if ((c == '\\') || (c == '"')) grpc_json_writer_output_char(writer, '\\');
-      grpc_json_writer_output_char(writer, c);
+      if ((c == '\\') || (c == '"')) json_writer_output_char(writer, '\\');
+      json_writer_output_char(writer, c);
     } else if (c < 32) {
-      grpc_json_writer_output_char(writer, '\\');
+      json_writer_output_char(writer, '\\');
       switch (c) {
         case '\b':
-          grpc_json_writer_output_char(writer, 'b');
+          json_writer_output_char(writer, 'b');
           break;
         case '\f':
-          grpc_json_writer_output_char(writer, 'f');
+          json_writer_output_char(writer, 'f');
           break;
         case '\n':
-          grpc_json_writer_output_char(writer, 'n');
+          json_writer_output_char(writer, 'n');
           break;
         case '\r':
-          grpc_json_writer_output_char(writer, 'r');
+          json_writer_output_char(writer, 'r');
           break;
         case '\t':
-          grpc_json_writer_output_char(writer, 't');
+          json_writer_output_char(writer, 't');
           break;
         default:
-          grpc_json_writer_escape_utf16(writer, c);
+          json_writer_escape_utf16(writer, c);
           break;
       }
     } else {
@@ -188,21 +193,21 @@ static void grpc_json_writer_escape_string(
          * That range is exactly 20 bits.
          */
         utf32 -= 0x10000;
-        grpc_json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10));
-        grpc_json_writer_escape_utf16(writer, 0xdc00 | (utf32 && 0x3ff));
+        json_writer_escape_utf16(writer, 0xd800 | (utf32 >> 10));
+        json_writer_escape_utf16(writer, 0xdc00 | (utf32 && 0x3ff));
       } else {
-        grpc_json_writer_escape_utf16(writer, utf32);
+        json_writer_escape_utf16(writer, utf32);
       }
     }
   }
 
-  grpc_json_writer_output_char(writer, '"');
+  json_writer_output_char(writer, '"');
 }
 
 void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type) {
-  if (!writer->got_key) grpc_json_writer_value_end(writer);
-  grpc_json_writer_output_indent(writer);
-  grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '{' : '[');
   writer->container_empty = 1;
   writer->got_key = 0;
   writer->depth++;
@@ -210,39 +215,39 @@ void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type
 
 void grpc_json_writer_container_ends(grpc_json_writer* writer, grpc_json_type type) {
   if (writer->indent && !writer->container_empty)
-    grpc_json_writer_output_char(writer, '\n');
+    json_writer_output_char(writer, '\n');
   writer->depth--;
-  if (!writer->container_empty) grpc_json_writer_output_indent(writer);
-  grpc_json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
+  if (!writer->container_empty) json_writer_output_indent(writer);
+  json_writer_output_char(writer, type == GRPC_JSON_OBJECT ? '}' : ']');
   writer->container_empty = 0;
   writer->got_key = 0;
 }
 
 void grpc_json_writer_object_key(grpc_json_writer* writer, const char* string) {
-  grpc_json_writer_value_end(writer);
-  grpc_json_writer_output_indent(writer);
-  grpc_json_writer_escape_string(writer, string);
-  grpc_json_writer_output_char(writer, ':');
+  json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_escape_string(writer, string);
+  json_writer_output_char(writer, ':');
   writer->got_key = 1;
 }
 
 void grpc_json_writer_value_raw(grpc_json_writer* writer, const char* string) {
-  if (!writer->got_key) grpc_json_writer_value_end(writer);
-  grpc_json_writer_output_indent(writer);
-  grpc_json_writer_output_string(writer, string);
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_string(writer, string);
   writer->got_key = 0;
 }
 
 void grpc_json_writer_value_raw_with_len(grpc_json_writer* writer, const char* string, size_t len) {
-  if (!writer->got_key) grpc_json_writer_value_end(writer);
-  grpc_json_writer_output_indent(writer);
-  grpc_json_writer_output_string_with_len(writer, string, len);
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_output_string_with_len(writer, string, len);
   writer->got_key = 0;
 }
 
 void grpc_json_writer_value_string(grpc_json_writer* writer, const char* string) {
-  if (!writer->got_key) grpc_json_writer_value_end(writer);
-  grpc_json_writer_output_indent(writer);
-  grpc_json_writer_escape_string(writer, string);
+  if (!writer->got_key) json_writer_value_end(writer);
+  json_writer_output_indent(writer);
+  json_writer_escape_string(writer, string);
   writer->got_key = 0;
 }
diff --git a/src/core/json/json_writer.h b/src/core/json/json_writer.h
index f0baa1eab9c0cf677988fcf08b09566e2bb984f0..0568401590181631c6aee132aa97ac4833922aa6 100644
--- a/src/core/json/json_writer.h
+++ b/src/core/json/json_writer.h
@@ -50,19 +50,19 @@
 
 #include "src/core/json/json_common.h"
 
-typedef struct grpc_json_writer {
-  /* You are responsible for your own opaque userdata. */
-  void* userdata;
-
-  /* The rest are your own callbacks. Define them. */
-
+typedef struct grpc_json_writer_vtable {
   /* Adds a character to the output stream. */
-  void (*output_char)(struct grpc_json_writer*, char);
+  void (*output_char)(void* userdata, char);
   /* Adds a zero-terminated string to the output stream. */
-  void (*output_string)(struct grpc_json_writer*, const char* str);
+  void (*output_string)(void* userdata, const char* str);
   /* Adds a fixed-length string to the output stream. */
-  void (*output_string_with_len)(struct grpc_json_writer*, const char* str, size_t len);
+  void (*output_string_with_len)(void* userdata, const char* str, size_t len);
 
+} grpc_json_writer_vtable;
+
+typedef struct grpc_json_writer {
+  void* userdata;
+  grpc_json_writer_vtable* vtable;
   int indent;
   int depth;
   int container_empty;
@@ -74,7 +74,8 @@ typedef struct grpc_json_writer {
  * use indent=0, then the output will not have any newlines either, thus
  * emitting a condensed json output.
  */
-void grpc_json_writer_init(grpc_json_writer* writer, int indent);
+void grpc_json_writer_init(grpc_json_writer* writer, int indent,
+                           grpc_json_writer_vtable* vtable, void* userdata);
 
 /* Signals the beginning of a container. */
 void grpc_json_writer_container_begins(grpc_json_writer* writer, grpc_json_type type);
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 28adf1ef3fd5f97d6e0d8ced0fa16fa4600961ad..5d06f142158d22b4b61917a0c1e7f4875ad87632 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -407,7 +407,7 @@ end:
   }
   if (null_terminated_body != NULL) gpr_free(null_terminated_body);
   if (new_access_token != NULL) gpr_free(new_access_token);
-  if (json != NULL) grpc_json_delete(json);
+  if (json != NULL) grpc_json_destroy(json);
   return status;
 }
 
diff --git a/src/core/security/json_token.c b/src/core/security/json_token.c
index 6462375f35de1cf8bcbc6ec9432ce792e5a6bb20..0548fd407f605a86f648172a01504241011515cc 100644
--- a/src/core/security/json_token.c
+++ b/src/core/security/json_token.c
@@ -140,7 +140,7 @@ grpc_auth_json_key grpc_auth_json_key_create_from_string(
 
 end:
   if (bio != NULL) BIO_free(bio);
-  if (json != NULL) grpc_json_delete(json);
+  if (json != NULL) grpc_json_destroy(json);
   if (!success) grpc_auth_json_key_destruct(&result);
   gpr_free(scratchpad);
   return result;
@@ -172,7 +172,7 @@ void grpc_auth_json_key_destruct(grpc_auth_json_key *json_key) {
 static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
                          const char *key, const char *value,
                          grpc_json_type type) {
-  grpc_json *child = grpc_json_new(type);
+  grpc_json *child = grpc_json_create(type);
   if (brother) brother->next = child;
   if (!parent->child) parent->child = child;
   child->parent = parent;
@@ -182,7 +182,7 @@ static grpc_json *create_child(grpc_json *brother, grpc_json *parent,
 }
 
 static char *encoded_jwt_header(const char *algorithm) {
-  grpc_json *json = grpc_json_new(GRPC_JSON_OBJECT);
+  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
   grpc_json *child = NULL;
   char *json_str = NULL;
   char *result = NULL;
@@ -193,13 +193,13 @@ static char *encoded_jwt_header(const char *algorithm) {
   json_str = grpc_json_dump_to_string(json, 0);
   result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
   gpr_free(json_str);
-  grpc_json_delete(json);
+  grpc_json_destroy(json);
   return result;
 }
 
 static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
                                const char *scope, gpr_timespec token_lifetime) {
-  grpc_json *json = grpc_json_new(GRPC_JSON_OBJECT);
+  grpc_json *json = grpc_json_create(GRPC_JSON_OBJECT);
   grpc_json *child = NULL;
   char *json_str = NULL;
   char *result = NULL;
@@ -225,7 +225,7 @@ static char *encoded_jwt_claim(const grpc_auth_json_key *json_key,
   json_str = grpc_json_dump_to_string(json, 0);
   result = grpc_base64_encode(json_str, strlen(json_str), 1, 0);
   gpr_free(json_str);
-  grpc_json_delete(json);
+  grpc_json_destroy(json);
   return result;
 }
 
diff --git a/test/core/security/json_token_test.c b/test/core/security/json_token_test.c
index 1eddfc1a582ac7613be2178d427ebb099d8463d5..2a9c8f88b24e3f7f3188cdcf266ef3d48696bc45 100644
--- a/test/core/security/json_token_test.c
+++ b/test/core/security/json_token_test.c
@@ -341,7 +341,7 @@ static void test_jwt_encode_and_sign(void) {
   GPR_ASSERT(parsed_header != NULL);
   check_jwt_header(parsed_header);
   offset = dot - jwt + 1;
-  grpc_json_delete(parsed_header);
+  grpc_json_destroy(parsed_header);
   gpr_free(scratchpad);
 
   dot = strchr(jwt + offset, '.');
@@ -350,7 +350,7 @@ static void test_jwt_encode_and_sign(void) {
   GPR_ASSERT(parsed_claim != NULL);
   check_jwt_claim(parsed_claim);
   offset = dot - jwt + 1;
-  grpc_json_delete(parsed_claim);
+  grpc_json_destroy(parsed_claim);
   gpr_free(scratchpad);
 
   dot = strchr(jwt + offset, '.');