capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

json.h (24171B)


      1 // Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #pragma once
     23 
     24 #include <capnp/schema.h>
     25 #include <capnp/dynamic.h>
     26 #include <capnp/compat/json.capnp.h>
     27 
     28 namespace capnp {
     29 
     30 typedef json::Value JsonValue;
     31 // For backwards-compatibility.
     32 //
     33 // TODO(cleanup): Consider replacing all uses of JsonValue with json::Value?
     34 
     35 class JsonCodec {
     36   // Flexible class for encoding Cap'n Proto types as JSON, and decoding JSON back to Cap'n Proto.
     37   //
     38   // Typical usage:
     39   //
     40   //     JsonCodec json;
     41   //
     42   //     // encode
     43   //     kj::String encoded = json.encode(someStructReader);
     44   //
     45   //     // decode
     46   //     json.decode(encoded, someStructBuilder);
     47   //
     48   // Advanced users can do fancy things like override the way certain types or fields are
     49   // represented in JSON by registering handlers. See the unit test for an example.
     50   //
     51   // Notes:
     52   // - When encoding, all primitive fields are always encoded, even if default-valued. Pointer
     53   //   fields are only encoded if they are non-null.
     54   // - 64-bit integers are encoded as strings, since JSON "numbers" are double-precision floating
     55   //   points which cannot store a 64-bit integer without losing data.
     56   // - NaNs and infinite floating point numbers are not allowed by the JSON spec, and so are encoded
     57   //   as strings.
     58   // - Data is encoded as an array of numbers in the range [0,255]. You probably want to register
     59   //   a handler that does something better, like maybe base64 encoding, but there are a zillion
     60   //   different ways people do this.
     61   // - Encoding/decoding capabilities and AnyPointers requires registering a Handler, since there's
     62   //   no obvious default behavior.
     63   // - When decoding, fields with unknown names are ignored by default to allow schema evolution.
     64 
     65 public:
     66   JsonCodec();
     67   ~JsonCodec() noexcept(false);
     68 
     69   // ---------------------------------------------------------------------------
     70   // standard API
     71 
     72   void setPrettyPrint(bool enabled);
     73   // Enable to insert newlines, indentation, and other extra spacing into the output. The default
     74   // is to use minimal whitespace.
     75 
     76   void setMaxNestingDepth(size_t maxNestingDepth);
     77   // Set maximum nesting depth when decoding JSON to prevent highly nested input from overflowing
     78   // the call stack. The default is 64.
     79 
     80   void setHasMode(HasMode mode);
     81   // Normally, primitive field values are always included even if they are equal to the default
     82   // value (HasMode::NON_NULL -- only null pointers are omitted). You can use
     83   // setHasMode(HasMode::NON_DEFAULT) to specify that default-valued primitive fields should be
     84   // omitted as well.
     85 
     86   void setRejectUnknownFields(bool enable);
     87   // Choose whether decoding JSON with unknown fields should produce an error. You may trade
     88   // allowing schema evolution against a guarantee that all data is preserved when decoding JSON
     89   // by toggling this option. The default is to ignore unknown fields.
     90 
     91   template <typename T>
     92   kj::String encode(T&& value) const;
     93   // Encode any Cap'n Proto value to JSON, including primitives and
     94   // Dynamic{Enum,Struct,List,Capability}, but not DynamicValue (see below).
     95 
     96   kj::String encode(DynamicValue::Reader value, Type type) const;
     97   // Encode a DynamicValue to JSON. `type` is needed because `DynamicValue` itself does
     98   // not distinguish between e.g. int32 and int64, which in JSON are handled differently. Most
     99   // of the time, though, you can use the single-argument templated version of `encode()` instead.
    100 
    101   void decode(kj::ArrayPtr<const char> input, DynamicStruct::Builder output) const;
    102   // Decode JSON text directly into a struct builder. This only works for structs since lists
    103   // need to be allocated with the correct size in advance.
    104   //
    105   // (Remember that any Cap'n Proto struct reader type can be implicitly cast to
    106   // DynamicStruct::Reader.)
    107 
    108   template <typename T>
    109   Orphan<T> decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const;
    110   // Decode JSON text to any Cap'n Proto object (pointer value), allocated using the given
    111   // orphanage. T must be specified explicitly and cannot be dynamic, e.g.:
    112   //
    113   //     Orphan<MyType> orphan = json.decode<MyType>(text, orphanage);
    114 
    115   template <typename T>
    116   ReaderFor<T> decode(kj::ArrayPtr<const char> input) const;
    117   // Decode JSON text into a primitive or capability value. T must be specified explicitly and
    118   // cannot be dynamic, e.g.:
    119   //
    120   //     uint32_t n = json.decode<uint32_t>(text);
    121 
    122   Orphan<DynamicValue> decode(kj::ArrayPtr<const char> input, Type type, Orphanage orphanage) const;
    123   Orphan<DynamicList> decode(
    124       kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const;
    125   Orphan<DynamicStruct> decode(
    126       kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const;
    127   DynamicCapability::Client decode(kj::ArrayPtr<const char> input, InterfaceSchema type) const;
    128   DynamicEnum decode(kj::ArrayPtr<const char> input, EnumSchema type) const;
    129   // Decode to a dynamic value, specifying the type schema.
    130 
    131   // ---------------------------------------------------------------------------
    132   // layered API
    133   //
    134   // You can separate text <-> JsonValue from JsonValue <-> T. These are particularly useful
    135   // for calling from Handler implementations.
    136 
    137   kj::String encodeRaw(JsonValue::Reader value) const;
    138   void decodeRaw(kj::ArrayPtr<const char> input, JsonValue::Builder output) const;
    139   // Translate JsonValue <-> text.
    140 
    141   template <typename T>
    142   void encode(T&& value, JsonValue::Builder output) const;
    143   void encode(DynamicValue::Reader input, Type type, JsonValue::Builder output) const;
    144   void decode(JsonValue::Reader input, DynamicStruct::Builder output) const;
    145   template <typename T>
    146   Orphan<T> decode(JsonValue::Reader input, Orphanage orphanage) const;
    147   template <typename T>
    148   ReaderFor<T> decode(JsonValue::Reader input) const;
    149 
    150   Orphan<DynamicValue> decode(JsonValue::Reader input, Type type, Orphanage orphanage) const;
    151   Orphan<DynamicList> decode(JsonValue::Reader input, ListSchema type, Orphanage orphanage) const;
    152   Orphan<DynamicStruct> decode(
    153       JsonValue::Reader input, StructSchema type, Orphanage orphanage) const;
    154   DynamicCapability::Client decode(JsonValue::Reader input, InterfaceSchema type) const;
    155   DynamicEnum decode(JsonValue::Reader input, EnumSchema type) const;
    156 
    157   // ---------------------------------------------------------------------------
    158   // specializing particular types
    159 
    160   template <typename T, Style s = style<T>()>
    161   class Handler;
    162   // Implement this interface to specify a special encoding for a particular type or field.
    163   //
    164   // The templates are a bit ugly, but subclasses of this type essentially implement two methods,
    165   // one to encode values of this type and one to decode values of this type. `encode()` is simple:
    166   //
    167   //   void encode(const JsonCodec& codec, ReaderFor<T> input, JsonValue::Builder output) const;
    168   //
    169   // `decode()` is a bit trickier. When T is a struct (including DynamicStruct), it is:
    170   //
    171   //   void decode(const JsonCodec& codec, JsonValue::Reader input, BuilderFor<T> output) const;
    172   //
    173   // However, when T is a primitive, decode() is:
    174   //
    175   //   T decode(const JsonCodec& codec, JsonValue::Reader input) const;
    176   //
    177   // Or when T is any non-struct object (list, blob), decode() is:
    178   //
    179   //   Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input, Orphanage orphanage) const;
    180   //
    181   // Or when T is an interface:
    182   //
    183   //   T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const;
    184   //
    185   // Additionally, when T is a struct you can *optionally* also implement the orphan-returning form
    186   // of decode(), but it will only be called when the struct would be allocated as an individual
    187   // object, not as part of a list. This allows you to return "nullptr" in these cases to say that
    188   // the pointer value should be null. This does not apply to list elements because struct list
    189   // elements cannot ever be null (since Cap'n Proto encodes struct lists as a flat list rather
    190   // than list-of-pointers).
    191 
    192   template <typename T>
    193   void addTypeHandler(Handler<T>& handler);
    194   void addTypeHandler(Type type, Handler<DynamicValue>& handler);
    195   void addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler);
    196   void addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler);
    197   void addTypeHandler(ListSchema type, Handler<DynamicList>& handler);
    198   void addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler);
    199   // Arrange that whenever the type T appears in the message, your handler will be used to
    200   // encode/decode it.
    201   //
    202   // Note that if you register a handler for a capability type, it will also apply to subtypes.
    203   // Thus Handler<Capability> handles all capabilities.
    204 
    205   template <typename T>
    206   void addFieldHandler(StructSchema::Field field, Handler<T>& handler);
    207   // Matches only the specific field. T can be a dynamic type. T must match the field's type.
    208 
    209   void handleByAnnotation(Schema schema);
    210   template <typename T> void handleByAnnotation();
    211   // Inspects the given type (as specified by type parameter or dynamic schema) and all its
    212   // dependencies looking for JSON annotations (see json.capnp), building and registering Handlers
    213   // based on these annotations.
    214   //
    215   // If you'd like to use annotations to control JSON, you must call these functions before you
    216   // start using the codec. They are not loaded "on demand" because that would require mutex
    217   // locking.
    218 
    219   // ---------------------------------------------------------------------------
    220   // Hack to support string literal parameters
    221 
    222   template <size_t size, typename... Params>
    223   auto decode(const char (&input)[size], Params&&... params) const
    224       -> decltype(decode(kj::arrayPtr(input, size), kj::fwd<Params>(params)...)) {
    225     return decode(kj::arrayPtr(input, size - 1), kj::fwd<Params>(params)...);
    226   }
    227   template <size_t size, typename... Params>
    228   auto decodeRaw(const char (&input)[size], Params&&... params) const
    229       -> decltype(decodeRaw(kj::arrayPtr(input, size), kj::fwd<Params>(params)...)) {
    230     return decodeRaw(kj::arrayPtr(input, size - 1), kj::fwd<Params>(params)...);
    231   }
    232 
    233 private:
    234   class HandlerBase;
    235   class AnnotatedHandler;
    236   class AnnotatedEnumHandler;
    237   class Base64Handler;
    238   class HexHandler;
    239   class JsonValueHandler;
    240   struct Impl;
    241 
    242   kj::Own<Impl> impl;
    243 
    244   void encodeField(StructSchema::Field field, DynamicValue::Reader input,
    245                    JsonValue::Builder output) const;
    246   Orphan<DynamicList> decodeArray(List<JsonValue>::Reader input, ListSchema type, Orphanage orphanage) const;
    247   void decodeObject(JsonValue::Reader input, StructSchema type, Orphanage orphanage, DynamicStruct::Builder output) const;
    248   void decodeField(StructSchema::Field fieldSchema, JsonValue::Reader fieldValue,
    249                    Orphanage orphanage, DynamicStruct::Builder output) const;
    250   void addTypeHandlerImpl(Type type, HandlerBase& handler);
    251   void addFieldHandlerImpl(StructSchema::Field field, Type type, HandlerBase& handler);
    252 
    253   AnnotatedHandler& loadAnnotatedHandler(
    254       StructSchema schema,
    255       kj::Maybe<json::DiscriminatorOptions::Reader> discriminator,
    256       kj::Maybe<kj::StringPtr> unionDeclName,
    257       kj::Vector<Schema>& dependencies);
    258 };
    259 
    260 // =======================================================================================
    261 // inline implementation details
    262 
    263 template <bool isDynamic>
    264 struct EncodeImpl;
    265 
    266 template <typename T>
    267 kj::String JsonCodec::encode(T&& value) const {
    268   Type type = Type::from(value);
    269   typedef FromAny<kj::Decay<T>> Base;
    270   return encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), type);
    271 }
    272 
    273 template <typename T>
    274 inline Orphan<T> JsonCodec::decode(kj::ArrayPtr<const char> input, Orphanage orphanage) const {
    275   return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
    276 }
    277 
    278 template <typename T>
    279 inline ReaderFor<T> JsonCodec::decode(kj::ArrayPtr<const char> input) const {
    280   static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
    281                 "must specify an orphanage to decode an object type");
    282   return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
    283 }
    284 
    285 inline Orphan<DynamicList> JsonCodec::decode(
    286     kj::ArrayPtr<const char> input, ListSchema type, Orphanage orphanage) const {
    287   return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
    288 }
    289 inline Orphan<DynamicStruct> JsonCodec::decode(
    290     kj::ArrayPtr<const char> input, StructSchema type, Orphanage orphanage) const {
    291   return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
    292 }
    293 inline DynamicCapability::Client JsonCodec::decode(
    294     kj::ArrayPtr<const char> input, InterfaceSchema type) const {
    295   return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
    296 }
    297 inline DynamicEnum JsonCodec::decode(kj::ArrayPtr<const char> input, EnumSchema type) const {
    298   return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
    299 }
    300 
    301 // -----------------------------------------------------------------------------
    302 
    303 template <typename T>
    304 void JsonCodec::encode(T&& value, JsonValue::Builder output) const {
    305   typedef FromAny<kj::Decay<T>> Base;
    306   encode(DynamicValue::Reader(ReaderFor<Base>(kj::fwd<T>(value))), Type::from<Base>(), output);
    307 }
    308 
    309 template <>
    310 inline void JsonCodec::encode<DynamicStruct::Reader>(
    311       DynamicStruct::Reader&& value, JsonValue::Builder output) const {
    312   encode(DynamicValue::Reader(value), value.getSchema(), output);
    313 }
    314 
    315 template <typename T>
    316 inline Orphan<T> JsonCodec::decode(JsonValue::Reader input, Orphanage orphanage) const {
    317   return decode(input, Type::from<T>(), orphanage).template releaseAs<T>();
    318 }
    319 
    320 template <typename T>
    321 inline ReaderFor<T> JsonCodec::decode(JsonValue::Reader input) const {
    322   static_assert(style<T>() == Style::PRIMITIVE || style<T>() == Style::CAPABILITY,
    323                 "must specify an orphanage to decode an object type");
    324   return decode(input, Type::from<T>(), Orphanage()).getReader().template as<T>();
    325 }
    326 
    327 inline Orphan<DynamicList> JsonCodec::decode(
    328     JsonValue::Reader input, ListSchema type, Orphanage orphanage) const {
    329   return decode(input, Type(type), orphanage).releaseAs<DynamicList>();
    330 }
    331 inline Orphan<DynamicStruct> JsonCodec::decode(
    332     JsonValue::Reader input, StructSchema type, Orphanage orphanage) const {
    333   return decode(input, Type(type), orphanage).releaseAs<DynamicStruct>();
    334 }
    335 inline DynamicCapability::Client JsonCodec::decode(
    336     JsonValue::Reader input, InterfaceSchema type) const {
    337   return decode(input, Type(type), Orphanage()).getReader().as<DynamicCapability>();
    338 }
    339 inline DynamicEnum JsonCodec::decode(JsonValue::Reader input, EnumSchema type) const {
    340   return decode(input, Type(type), Orphanage()).getReader().as<DynamicEnum>();
    341 }
    342 
    343 // -----------------------------------------------------------------------------
    344 
    345 class JsonCodec::HandlerBase {
    346   // Internal helper; ignore.
    347 public:
    348   virtual void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    349                           JsonValue::Builder output) const = 0;
    350   virtual Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    351                                           Type type, Orphanage orphanage) const;
    352   virtual void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
    353                                 DynamicStruct::Builder output) const;
    354 };
    355 
    356 template <typename T>
    357 class JsonCodec::Handler<T, Style::POINTER>: private JsonCodec::HandlerBase {
    358 public:
    359   virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
    360                       JsonValue::Builder output) const = 0;
    361   virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
    362                            Orphanage orphanage) const = 0;
    363 
    364 private:
    365   void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    366                   JsonValue::Builder output) const override final {
    367     encode(codec, input.as<T>(), output);
    368   }
    369   Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    370                                   Type type, Orphanage orphanage) const override final {
    371     return decode(codec, input, orphanage);
    372   }
    373   friend class JsonCodec;
    374 };
    375 
    376 template <typename T>
    377 class JsonCodec::Handler<T, Style::STRUCT>: private JsonCodec::HandlerBase {
    378 public:
    379   virtual void encode(const JsonCodec& codec, ReaderFor<T> input,
    380                       JsonValue::Builder output) const = 0;
    381   virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
    382                       BuilderFor<T> output) const = 0;
    383   virtual Orphan<T> decode(const JsonCodec& codec, JsonValue::Reader input,
    384                            Orphanage orphanage) const {
    385     // If subclass does not override, fall back to regular version.
    386     auto result = orphanage.newOrphan<T>();
    387     decode(codec, input, result.get());
    388     return result;
    389   }
    390 
    391 private:
    392   void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    393                   JsonValue::Builder output) const override final {
    394     encode(codec, input.as<T>(), output);
    395   }
    396   Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    397                                   Type type, Orphanage orphanage) const override final {
    398     return decode(codec, input, orphanage);
    399   }
    400   void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
    401                         DynamicStruct::Builder output) const override final {
    402     decode(codec, input, output.as<T>());
    403   }
    404   friend class JsonCodec;
    405 };
    406 
    407 template <>
    408 class JsonCodec::Handler<DynamicStruct>: private JsonCodec::HandlerBase {
    409   // Almost identical to Style::STRUCT except that we pass the struct type to decode().
    410 
    411 public:
    412   virtual void encode(const JsonCodec& codec, DynamicStruct::Reader input,
    413                       JsonValue::Builder output) const = 0;
    414   virtual void decode(const JsonCodec& codec, JsonValue::Reader input,
    415                       DynamicStruct::Builder output) const = 0;
    416   virtual Orphan<DynamicStruct> decode(const JsonCodec& codec, JsonValue::Reader input,
    417                                        StructSchema type, Orphanage orphanage) const {
    418     // If subclass does not override, fall back to regular version.
    419     auto result = orphanage.newOrphan(type);
    420     decode(codec, input, result.get());
    421     return result;
    422   }
    423 
    424 private:
    425   void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    426                   JsonValue::Builder output) const override final {
    427     encode(codec, input.as<DynamicStruct>(), output);
    428   }
    429   Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    430                                   Type type, Orphanage orphanage) const override final {
    431     return decode(codec, input, type.asStruct(), orphanage);
    432   }
    433   void decodeStructBase(const JsonCodec& codec, JsonValue::Reader input,
    434                         DynamicStruct::Builder output) const override final {
    435     decode(codec, input, output.as<DynamicStruct>());
    436   }
    437   friend class JsonCodec;
    438 };
    439 
    440 template <typename T>
    441 class JsonCodec::Handler<T, Style::PRIMITIVE>: private JsonCodec::HandlerBase {
    442 public:
    443   virtual void encode(const JsonCodec& codec, T input, JsonValue::Builder output) const = 0;
    444   virtual T decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
    445 
    446 private:
    447   void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    448                   JsonValue::Builder output) const override final {
    449     encode(codec, input.as<T>(), output);
    450   }
    451   Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    452                                   Type type, Orphanage orphanage) const override final {
    453     return decode(codec, input);
    454   }
    455   friend class JsonCodec;
    456 };
    457 
    458 template <typename T>
    459 class JsonCodec::Handler<T, Style::CAPABILITY>: private JsonCodec::HandlerBase {
    460 public:
    461   virtual void encode(const JsonCodec& codec, typename T::Client input,
    462                       JsonValue::Builder output) const = 0;
    463   virtual typename T::Client decode(const JsonCodec& codec, JsonValue::Reader input) const = 0;
    464 
    465 private:
    466   void encodeBase(const JsonCodec& codec, DynamicValue::Reader input,
    467                   JsonValue::Builder output) const override final {
    468     encode(codec, input.as<T>(), output);
    469   }
    470   Orphan<DynamicValue> decodeBase(const JsonCodec& codec, JsonValue::Reader input,
    471                                   Type type, Orphanage orphanage) const override final {
    472     return orphanage.newOrphanCopy(decode(codec, input));
    473   }
    474   friend class JsonCodec;
    475 };
    476 
    477 template <typename T>
    478 inline void JsonCodec::addTypeHandler(Handler<T>& handler) {
    479   addTypeHandlerImpl(Type::from<T>(), handler);
    480 }
    481 inline void JsonCodec::addTypeHandler(Type type, Handler<DynamicValue>& handler) {
    482   addTypeHandlerImpl(type, handler);
    483 }
    484 inline void JsonCodec::addTypeHandler(EnumSchema type, Handler<DynamicEnum>& handler) {
    485   addTypeHandlerImpl(type, handler);
    486 }
    487 inline void JsonCodec::addTypeHandler(StructSchema type, Handler<DynamicStruct>& handler) {
    488   addTypeHandlerImpl(type, handler);
    489 }
    490 inline void JsonCodec::addTypeHandler(ListSchema type, Handler<DynamicList>& handler) {
    491   addTypeHandlerImpl(type, handler);
    492 }
    493 inline void JsonCodec::addTypeHandler(InterfaceSchema type, Handler<DynamicCapability>& handler) {
    494   addTypeHandlerImpl(type, handler);
    495 }
    496 
    497 template <typename T>
    498 inline void JsonCodec::addFieldHandler(StructSchema::Field field, Handler<T>& handler) {
    499   addFieldHandlerImpl(field, Type::from<T>(), handler);
    500 }
    501 
    502 template <> void JsonCodec::addTypeHandler(Handler<DynamicValue>& handler)
    503     KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
    504                    "try specifying a specific type schema as the first parameter");
    505 template <> void JsonCodec::addTypeHandler(Handler<DynamicEnum>& handler)
    506     KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
    507                    "try specifying a specific type schema as the first parameter");
    508 template <> void JsonCodec::addTypeHandler(Handler<DynamicStruct>& handler)
    509     KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
    510                    "try specifying a specific type schema as the first parameter");
    511 template <> void JsonCodec::addTypeHandler(Handler<DynamicList>& handler)
    512     KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
    513                    "try specifying a specific type schema as the first parameter");
    514 template <> void JsonCodec::addTypeHandler(Handler<DynamicCapability>& handler)
    515     KJ_UNAVAILABLE("JSON handlers for type sets (e.g. all structs, all lists) not implemented; "
    516                    "try specifying a specific type schema as the first parameter");
    517 // TODO(someday): Implement support for registering handlers that cover thinsg like "all structs"
    518 //   or "all lists". Currently you can only target a specific struct or list type.
    519 
    520 template <typename T>
    521 void JsonCodec::handleByAnnotation() {
    522   return handleByAnnotation(Schema::from<T>());
    523 }
    524 
    525 } // namespace capnp