sort_keys option for json
authorAnton Likhtarov <alikhtarov@fb.com>
Tue, 26 Nov 2013 02:26:29 +0000 (18:26 -0800)
committerJordan DeLong <jdelong@fb.com>
Fri, 20 Dec 2013 21:03:17 +0000 (13:03 -0800)
Summary:
A dumb&slow implementation. I just needed something that outputs keys in a sorted order.
No easy to use API to discourage the use due to perf implications.

Test Plan: unit test

Reviewed By: delong.j@fb.com

FB internal diff: D1073757

folly/json.cpp
folly/json.h
folly/test/JsonTest.cpp

index 5fe44a59b208ac8810f9e6d06851a1b2da4e3626..ab45d594ad275888bb0af54df6082ebd9c6480b9 100644 (file)
@@ -159,6 +159,16 @@ private:
     (*this)(p.second);
   }
 
+  template <typename Iterator>
+  void printKVPairs(Iterator begin, Iterator end) const {
+    printKV(*begin);
+    for (++begin; begin != end; ++begin) {
+      out_ += ',';
+      newline();
+      printKV(*begin);
+    }
+  }
+
   void printObject(dynamic const& o) const {
     if (o.empty()) {
       out_ += "{}";
@@ -168,12 +178,13 @@ private:
     out_ += '{';
     indent();
     newline();
-    auto it = o.items().begin();
-    printKV(*it);
-    for (++it; it != o.items().end(); ++it) {
-      out_ += ',';
-      newline();
-      printKV(*it);
+    if (opts_.sort_keys) {
+      std::vector<std::pair<dynamic, dynamic>> items(
+        o.items().begin(), o.items().end());
+      std::sort(items.begin(), items.end());
+      printKVPairs(items.begin(), items.end());
+    } else {
+      printKVPairs(o.items().begin(), o.items().end());
     }
     outdent();
     newline();
index 40f23f2a94402f825867358ee46dfc819d8ee1b9..149ca8ff58a73f19dc9d66869d888fe22aa96c02 100644 (file)
@@ -59,6 +59,7 @@ namespace json {
       , encode_non_ascii(false)
       , validate_utf8(false)
       , allow_trailing_comma(false)
+      , sort_keys(false)
     {}
 
     // If true, keys in an object can be non-strings.  (In strict
@@ -85,6 +86,9 @@ namespace json {
 
     // Allow trailing comma in lists of values / items
     bool allow_trailing_comma;
+
+    // Sort keys of all objects before printing out (potentially slow)
+    bool sort_keys;
   };
 
   /*
index cfa84f4c3ef5380af1c51bbcfc89a6a624b18646..6dfdcb48169c81859f5154ce880aee44ed408af2 100644 (file)
@@ -331,6 +331,37 @@ TEST(Json, ParseNonStringKeys) {
   EXPECT_EQ(1.5, dval.items().begin()->first.asDouble());
 }
 
+TEST(Json, SortKeys) {
+  folly::json::serialization_opts opts_on, opts_off;
+  opts_on.sort_keys = true;
+  opts_off.sort_keys = false;
+
+  dynamic value = dynamic::object
+    ("foo", "bar")
+    ("junk", 12)
+    ("another", 32.2)
+    ("a",
+      {
+        dynamic::object("a", "b")
+                       ("c", "d"),
+        12.5,
+        "Yo Dawg",
+        { "heh" },
+        nullptr
+      }
+    )
+    ;
+
+  std::string sorted_keys =
+    R"({"a":[{"a":"b","c":"d"},12.5,"Yo Dawg",["heh"],null],)"
+    R"("another":32.2,"foo":"bar","junk":12})";
+
+  EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_on)));
+  EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_off)));
+
+  EXPECT_EQ(sorted_keys, folly::json::serialize(value, opts_on));
+}
+
 BENCHMARK(jsonSerialize, iters) {
   folly::json::serialization_opts opts;
   for (int i = 0; i < iters; ++i) {