diff options
author | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-13 02:18:02 +0000 |
---|---|---|
committer | mukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-01-13 02:18:02 +0000 |
commit | 6009ca9cf529d88a9fff4509dccb424a3ee0a57f (patch) | |
tree | 9275a9b1a3a502c7eb5eb4820cb11629cfaf66f4 /base/json | |
parent | 9060d8b0a094dbcf15d58fa3ce27e9ce9f7766ee (diff) | |
download | chromium_src-6009ca9cf529d88a9fff4509dccb424a3ee0a57f.zip chromium_src-6009ca9cf529d88a9fff4509dccb424a3ee0a57f.tar.gz chromium_src-6009ca9cf529d88a9fff4509dccb424a3ee0a57f.tar.bz2 |
Add custom field converter to JSONValueConverter.
In the real JSON results, sometimes string value does not literally
mean a string, but labels (enum), URLs, or timestamps. Custom
field accepts those string values and converting functions for
such fields.
See http://codereview.chromium.org/9147060 for the real use cases.
BUG=109375
TEST=passed
Review URL: http://codereview.chromium.org/9184002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@117580 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/json')
-rw-r--r-- | base/json/json_value_converter.h | 48 | ||||
-rw-r--r-- | base/json/json_value_converter_unittest.cc | 37 |
2 files changed, 85 insertions, 0 deletions
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h index e933dad..ea43dbb 100644 --- a/base/json/json_value_converter.h +++ b/base/json/json_value_converter.h @@ -15,6 +15,7 @@ #include "base/memory/scoped_ptr.h" #include "base/stl_util.h" #include "base/string16.h" +#include "base/string_piece.h" #include "base/values.h" // JSONValueConverter converts a JSON value into a C++ struct in a @@ -67,6 +68,21 @@ // and you can put RegisterRepeatedInt or some other types. Use // RegisterRepeatedMessage for nested repeated fields. // +// Sometimes JSON format uses string representations for other types such +// like enum, timestamp, or URL. You can use RegisterCustomField method +// and specify a function to convert a StringPiece to your type. +// bool ConvertFunc(const StringPiece& s, YourEnum* result) { +// // do something and return true if succeed... +// } +// struct Message { +// YourEnum ye; +// ... +// static void RegisterJSONConverter(...) { +// ... +// converter->RegsiterCustomField<YourEnum>( +// "your_enum", &Message::ye, &ConvertFunc); +// } +// }; namespace base { @@ -187,6 +203,27 @@ class BasicValueConverter<bool> : public ValueConverter<bool> { DISALLOW_COPY_AND_ASSIGN(BasicValueConverter); }; +template <typename FieldType> +class CustomFieldConverter : public ValueConverter<FieldType> { + public: + typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field); + + CustomFieldConverter(ConvertFunc convert_func) + : convert_func_(convert_func) {} + + virtual bool Convert(const base::Value& value, + FieldType* field) const OVERRIDE { + std::string string_value; + return value.GetAsString(&string_value) && + convert_func_(string_value, field); + } + + private: + ConvertFunc convert_func_; + + DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter); +}; + template <typename NestedType> class NestedValueConverter : public ValueConverter<NestedType> { public: @@ -320,6 +357,17 @@ class JSONValueConverter { new internal::NestedValueConverter<NestedType>)); } + template <typename FieldType> + void RegisterCustomField( + const std::string& field_name, + FieldType StructType::* field, + bool (*convert_func)(const StringPiece&, FieldType*)) { + fields_.push_back(new internal::FieldConverter<StructType, FieldType>( + field_name, + field, + new internal::CustomFieldConverter<FieldType>(convert_func))); + } + void RegisterRepeatedInt(const std::string& field_name, std::vector<int> StructType::* field) { fields_.push_back( diff --git a/base/json/json_value_converter_unittest.cc b/base/json/json_value_converter_unittest.cc index 73ed229..b91dd6f 100644 --- a/base/json/json_value_converter_unittest.cc +++ b/base/json/json_value_converter_unittest.cc @@ -10,6 +10,7 @@ #include "base/values.h" #include "base/json/json_reader.h" #include "base/memory/scoped_ptr.h" +#include "base/string_piece.h" #include "testing/gtest/include/gtest/gtest.h" namespace base { @@ -17,17 +18,34 @@ namespace { // Very simple messages. struct SimpleMessage { + enum SimpleEnum { + FOO, BAR, + }; int foo; std::string bar; bool baz; + SimpleEnum simple_enum; std::vector<int> ints; SimpleMessage() : foo(0), baz(false) {} + static bool ParseSimpleEnum(const StringPiece& value, SimpleEnum* field) { + if (value == "foo") { + *field = FOO; + return true; + } else if (value == "bar") { + *field = BAR; + return true; + } + return false; + } + static void RegisterJSONConverter( base::JSONValueConverter<SimpleMessage>* converter) { converter->RegisterIntField("foo", &SimpleMessage::foo); converter->RegisterStringField("bar", &SimpleMessage::bar); converter->RegisterBoolField("baz", &SimpleMessage::baz); + converter->RegisterCustomField<SimpleEnum>( + "simple_enum", &SimpleMessage::simple_enum, &ParseSimpleEnum); converter->RegisterRepeatedInt("ints", &SimpleMessage::ints); } }; @@ -56,6 +74,7 @@ TEST(JSONValueConverterTest, ParseSimpleMessage) { " \"foo\": 1,\n" " \"bar\": \"bar\",\n" " \"baz\": true,\n" + " \"simple_enum\": \"foo\"," " \"ints\": [1, 2]" "}\n"; @@ -67,6 +86,7 @@ TEST(JSONValueConverterTest, ParseSimpleMessage) { EXPECT_EQ(1, message.foo); EXPECT_EQ("bar", message.bar); EXPECT_TRUE(message.baz); + EXPECT_EQ(SimpleMessage::FOO, message.simple_enum); EXPECT_EQ(2, static_cast<int>(message.ints.size())); EXPECT_EQ(1, message.ints[0]); EXPECT_EQ(2, message.ints[1]); @@ -153,4 +173,21 @@ TEST(JSONValueConverterTest, ParseWithMissingFields) { EXPECT_EQ(2, message.ints[1]); } +TEST(JSONValueConverterTest, EnumParserFails) { + const char normal_data[] = + "{\n" + " \"foo\": 1,\n" + " \"bar\": \"bar\",\n" + " \"baz\": true,\n" + " \"simple_enum\": \"baz\"," + " \"ints\": [1, 2]" + "}\n"; + + scoped_ptr<Value> value(base::JSONReader::Read(normal_data, false)); + SimpleMessage message; + base::JSONValueConverter<SimpleMessage> converter; + EXPECT_FALSE(converter.Convert(*value.get(), &message)); + // No check the values as mentioned above. +} + } // namespace base |