summaryrefslogtreecommitdiffstats
path: root/base/json
diff options
context:
space:
mode:
authormukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-13 02:18:02 +0000
committermukai@chromium.org <mukai@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-01-13 02:18:02 +0000
commit6009ca9cf529d88a9fff4509dccb424a3ee0a57f (patch)
tree9275a9b1a3a502c7eb5eb4820cb11629cfaf66f4 /base/json
parent9060d8b0a094dbcf15d58fa3ce27e9ce9f7766ee (diff)
downloadchromium_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.h48
-rw-r--r--base/json/json_value_converter_unittest.cc37
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