From 43a79f74cfdeac62198fc4dbdda7a04d4d14ece6 Mon Sep 17 00:00:00 2001 From: Dylan Yudaken Date: Tue, 28 Mar 2017 08:02:42 -0700 Subject: [PATCH] Allow custom sorting function for JSON serializer Summary: In some situations it is useful to be able to sort the JSON keys according to some different scheme for readability, so allow the sorting function to be changed by the serializer_opts Reviewed By: yfeldblum Differential Revision: D4782077 fbshipit-source-id: 032fa60a38804452bd1c22c67ba897521cb2cd1d --- folly/json.cpp | 11 ++++++++--- folly/json.h | 9 ++++++++- folly/test/JsonTest.cpp | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/folly/json.cpp b/folly/json.cpp index 48ef486e..867392f4 100644 --- a/folly/json.cpp +++ b/folly/json.cpp @@ -113,12 +113,17 @@ private: out_ += '{'; indent(); newline(); - if (opts_.sort_keys) { + if (opts_.sort_keys || opts_.sort_keys_by) { using ref = std::reference_wrapper; std::vector refs(o.items().begin(), o.items().end()); - std::sort(refs.begin(), refs.end(), [](ref a, ref b) { + + using SortByRef = FunctionRef; + auto const& sort_keys_by = opts_.sort_keys_by + ? SortByRef(opts_.sort_keys_by) + : SortByRef(std::less()); + std::sort(refs.begin(), refs.end(), [&](ref a, ref b) { // Only compare keys. No ordering among identical keys. - return a.get().first < b.get().first; + return sort_keys_by(a.get().first, b.get().first); }); printKVPairs(refs.cbegin(), refs.cend()); } else { diff --git a/folly/json.h b/folly/json.h index 87a90788..788587a8 100644 --- a/folly/json.h +++ b/folly/json.h @@ -43,8 +43,9 @@ #include #include -#include +#include #include +#include namespace folly { @@ -95,8 +96,14 @@ namespace json { bool allow_trailing_comma; // Sort keys of all objects before printing out (potentially slow) + // using dynamic::operator<. + // Has no effect if sort_keys_by is set. bool sort_keys; + // Sort keys of all objects before printing out (potentially slow) + // using the provided less functor. + Function sort_keys_by; + // Replace invalid utf8 characters with U+FFFD and continue bool skip_invalid_utf8; diff --git a/folly/test/JsonTest.cpp b/folly/test/JsonTest.cpp index df283134..f6dfc354 100644 --- a/folly/test/JsonTest.cpp +++ b/folly/test/JsonTest.cpp @@ -438,10 +438,17 @@ TEST(Json, ParseNumbersAsStrings) { } TEST(Json, SortKeys) { - folly::json::serialization_opts opts_on, opts_off; + folly::json::serialization_opts opts_on, opts_off, opts_custom_sort; opts_on.sort_keys = true; opts_off.sort_keys = false; + opts_custom_sort.sort_keys = false; // should not be required + opts_custom_sort.sort_keys_by = []( + folly::dynamic const& a, folly::dynamic const& b) { + // just an inverse sort + return b < a; + }; + dynamic value = dynamic::object ("foo", "bar") ("junk", 12) @@ -462,10 +469,18 @@ TEST(Json, SortKeys) { R"({"a":[{"a":"b","c":"d"},12.5,"Yo Dawg",["heh"],null],)" R"("another":32.2,"foo":"bar","junk":12})"; + std::string inverse_sorted_keys = + R"({"junk":12,"foo":"bar","another":32.2,)" + R"("a":[{"c":"d","a":"b"},12.5,"Yo Dawg",["heh"],null]})"; + EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_on))); EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_off))); + EXPECT_EQ(value, parseJson(folly::json::serialize(value, opts_custom_sort))); EXPECT_EQ(sorted_keys, folly::json::serialize(value, opts_on)); + EXPECT_NE(sorted_keys, folly::json::serialize(value, opts_off)); + EXPECT_EQ( + inverse_sorted_keys, folly::json::serialize(value, opts_custom_sort)); } TEST(Json, PrintTo) { -- 2.34.1