On Wed, 6 Feb 2013, Yehuda Sadeh wrote: > The matter of json decoding was brought up as part of the discussion > of the ceph management api. I recently had to deal with it with the > rados gateway, as I wasn't too happy was the current mechanisms that > were used for this purpose. So I introduced a new decode_json() > functionality (now in common/ceph_json.* at the wip-json-decode > branch). It's very similar to the regular encode/decode stuff that we > use to encode/decode structures. Encoding is being done using the > already existing dump() method, and decoding will be done through the > new decode_json() method. > > As an example we'll define a new UserInfo structure: > > struct UserInfo { > string uid; > string display_name; > int max_buckets; > list<Key> keys; > > void dump(Formatter *f) const; > void decode_json(JSONObj *obj); > }; > > The dump() method will look like this: > > void UserInfo::dump(Formatter *f) const > { > f->open_object_section("user_info"); > f->dump_string("user_id", uid); > f->dump_string("display_name", display_name); > f->dump_int("max_buckets", (int)max_buckets); > > f->open_array_section("keys"); > for (list<Key>::iterator iter = keys.begin(); siter != keys.end(); ++iter) { > iter->dump(f); > } > f->close_section(); > > f->close_section(); > } > > It is recommended that every dump() method opens an object section and > puts everything within, so that every object could be easily embedded > within other objects. We can also probably create some template that The current loose convention is that the dump objects do not define the container they dump into. It's a bit weird, but it lets you do things like: map<Key, Value> foo; f->open_array_section("keys"); for (map<Key,Value>::iterator iter = keys.begin(); siter != keys.end(); ++iter) { f->open_object_section("thing"); f->dump_string("key", iter->first); iter->second.dump(f); f->close_section(); } f->close_section(); Admittedly that doesn't come up *that* often, but it happened enough when we first started doing the dump stuff that all/most of the dumpers work that way. How should we deal with that? sage > will remove the need of doing that inner loop, e.g.: > ... > f->dump_array("keys", keys); > ... > > In any case, the corresponding json decoding function looks like this: > > void UserInfo::decode_json(JSONObj *obj) { > JSONDecoder::decode_json("user_id", uid, obj); > JSONDecoder::decode_json("display_name", display_name, obj); > JSONDecoder::decode_json("max_buckets", max_buckets, obj); > JSONDecoder::decode_json("keys", keys, obj); > } > > > and we'll decode the structure like this: > > ... > > UserInfo user_info; > > JSONParser parser; > > if (!parser.parse(buf, len)) > return -EINVAL; > ... > try { > user_info.decode(&parser); > } catch (JSONDecoder::err& e) { > ... > } > > > The default behavior is that every field is optional, so that it just > ignores fields that are not found in the json structure. If a field is > set to be mandatory (by extra param to the decode_json()), then an > exception will be thrown. Note that all fields should be initialized > to the default value before decoding as passed json might not contain > any relevant field. > > > Yehuda > -- > To unsubscribe from this list: send the line "unsubscribe ceph-devel" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html > > -- To unsubscribe from this list: send the line "unsubscribe ceph-devel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html