Index: base/json/json_value_converter.h |
diff --git a/base/json/json_value_converter.h b/base/json/json_value_converter.h |
index ff4271d476b4752ad1794dc1fe4565e58881ea04..034d80142eb63a5b21d6157667e815eaed8bf460 100644 |
--- a/base/json/json_value_converter.h |
+++ b/base/json/json_value_converter.h |
@@ -68,9 +68,9 @@ |
// 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. |
+// Sometimes JSON format uses string representations for other types such like |
+// enum, timestamp, or URL. You can use RegisterCustomField() 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... |
// } |
@@ -79,10 +79,19 @@ |
// ... |
// static void RegisterJSONConverter(...) { |
// ... |
-// converter->RegsiterCustomField<YourEnum>( |
+// converter->RegisterCustomField<YourEnum>( |
// "your_enum", &Message::ye, &ConvertFunc); |
// } |
// }; |
+// |
+// If you want to perform an arbitrary action in response to a particular field |
+// (e.g. perhaps it's a dictionary and you want to conditionally save one of its |
+// fields to your message depending on the value of another of its fields), |
+// RegisterCustomAction() can be used. If the field contains a list, |
+// RegisterRepeatedCustomAction() can be used to specify that the handler |
+// function should be invoked for each value in the list. Note that the handler |
+// should still return true even if it takes no action; false should only be |
+// returned if the data is malformed and conversion has failed. |
namespace base { |
@@ -91,54 +100,102 @@ class JSONValueConverter; |
namespace internal { |
-template<typename StructType> |
-class FieldConverterBase { |
+// Interface for classes that handle a base::Value located at a particular path. |
+template <typename StructType> |
+class FieldHandlerBase { |
public: |
- explicit FieldConverterBase(const std::string& path) : field_path_(path) {} |
- virtual ~FieldConverterBase() {} |
- virtual bool ConvertField(const base::Value& value, StructType* obj) |
+ explicit FieldHandlerBase(const std::string& path) : field_path_(path) {} |
+ virtual ~FieldHandlerBase() {} |
+ virtual bool HandleField(const base::Value& value, StructType* obj) |
const = 0; |
const std::string& field_path() const { return field_path_; } |
private: |
std::string field_path_; |
- DISALLOW_COPY_AND_ASSIGN(FieldConverterBase); |
+ DISALLOW_COPY_AND_ASSIGN(FieldHandlerBase); |
}; |
+// Interface for classes that convert base::Values as needed and write them to |
+// passed-in fields. |
template <typename FieldType> |
-class ValueConverter { |
+class ValueConverterBase { |
public: |
- virtual ~ValueConverter() {} |
+ virtual ~ValueConverterBase() {} |
virtual bool Convert(const base::Value& value, FieldType* field) const = 0; |
}; |
+// FieldHandlerBase implementation that uses a ValueConverterBase to convert a |
+// base::Value and write it to a passed-in field. |
template <typename StructType, typename FieldType> |
-class FieldConverter : public FieldConverterBase<StructType> { |
+class FieldConverter : public FieldHandlerBase<StructType> { |
public: |
- explicit FieldConverter(const std::string& path, |
- FieldType StructType::* field, |
- ValueConverter<FieldType>* converter) |
- : FieldConverterBase<StructType>(path), |
+ FieldConverter(const std::string& path, |
+ FieldType StructType::* field, |
+ ValueConverterBase<FieldType>* converter) |
+ : FieldHandlerBase<StructType>(path), |
field_pointer_(field), |
value_converter_(converter) { |
} |
- virtual bool ConvertField( |
+ virtual bool HandleField( |
const base::Value& value, StructType* dst) const OVERRIDE { |
return value_converter_->Convert(value, &(dst->*field_pointer_)); |
} |
private: |
FieldType StructType::* field_pointer_; |
- scoped_ptr<ValueConverter<FieldType> > value_converter_; |
+ scoped_ptr<ValueConverterBase<FieldType> > value_converter_; |
DISALLOW_COPY_AND_ASSIGN(FieldConverter); |
}; |
+// FieldHandlerBase implementation that passes the bare base::Value and the |
+// destination object (as opposed to a field within the object) to a function |
+// that can process and apply the value however it wants. |
+template <typename StructType> |
+class FieldActionRunner : public FieldHandlerBase<StructType> { |
+ public: |
+ typedef bool(*ActionFunc)(const base::Value* value, StructType* obj); |
+ |
+ // If |repeated| is true, the field is expected to contain a list. |
+ // |action_func| will be invoked with each of its elements. |
+ FieldActionRunner(const std::string& path, |
+ bool repeated, |
+ ActionFunc action_func) |
+ : FieldHandlerBase<StructType>(path), |
+ repeated_(repeated), |
+ action_func_(action_func) { |
+ } |
+ |
+ virtual bool HandleField(const base::Value& value, |
+ StructType* obj) const OVERRIDE { |
+ if (!repeated_) { |
+ return action_func_(&value, obj); |
+ } else { |
+ const base::ListValue* list = NULL; |
+ if (!value.GetAsList(&list)) |
+ return false; |
+ |
+ for (size_t i = 0; i < list->GetSize(); ++i) { |
+ base::Value* element = NULL; |
+ CHECK(list->Get(i, &element)); |
+ if (!action_func_(element, obj)) |
+ return false; |
+ } |
+ return true; |
+ } |
+ } |
+ |
+ private: |
+ bool repeated_; |
+ ActionFunc action_func_; |
+ DISALLOW_COPY_AND_ASSIGN(FieldActionRunner); |
+}; |
+ |
template <typename FieldType> |
class BasicValueConverter; |
template <> |
-class BasicValueConverter<int> : public ValueConverter<int> { |
+class BasicValueConverter<int> : public ValueConverterBase<int> { |
public: |
BasicValueConverter() {} |
@@ -151,7 +208,8 @@ class BasicValueConverter<int> : public ValueConverter<int> { |
}; |
template <> |
-class BasicValueConverter<std::string> : public ValueConverter<std::string> { |
+class BasicValueConverter<std::string> |
+ : public ValueConverterBase<std::string> { |
public: |
BasicValueConverter() {} |
@@ -165,7 +223,7 @@ class BasicValueConverter<std::string> : public ValueConverter<std::string> { |
}; |
template <> |
-class BasicValueConverter<string16> : public ValueConverter<string16> { |
+class BasicValueConverter<string16> : public ValueConverterBase<string16> { |
public: |
BasicValueConverter() {} |
@@ -179,7 +237,7 @@ class BasicValueConverter<string16> : public ValueConverter<string16> { |
}; |
template <> |
-class BasicValueConverter<double> : public ValueConverter<double> { |
+class BasicValueConverter<double> : public ValueConverterBase<double> { |
public: |
BasicValueConverter() {} |
@@ -192,7 +250,7 @@ class BasicValueConverter<double> : public ValueConverter<double> { |
}; |
template <> |
-class BasicValueConverter<bool> : public ValueConverter<bool> { |
+class BasicValueConverter<bool> : public ValueConverterBase<bool> { |
public: |
BasicValueConverter() {} |
@@ -205,7 +263,7 @@ class BasicValueConverter<bool> : public ValueConverter<bool> { |
}; |
template <typename FieldType> |
-class ValueFieldConverter : public ValueConverter<FieldType> { |
+class ValueFieldConverter : public ValueConverterBase<FieldType> { |
public: |
typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field); |
@@ -224,7 +282,7 @@ class ValueFieldConverter : public ValueConverter<FieldType> { |
}; |
template <typename FieldType> |
-class CustomFieldConverter : public ValueConverter<FieldType> { |
+class CustomFieldConverter : public ValueConverterBase<FieldType> { |
public: |
typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field); |
@@ -245,7 +303,7 @@ class CustomFieldConverter : public ValueConverter<FieldType> { |
}; |
template <typename NestedType> |
-class NestedValueConverter : public ValueConverter<NestedType> { |
+class NestedValueConverter : public ValueConverterBase<NestedType> { |
public: |
NestedValueConverter() {} |
@@ -260,7 +318,8 @@ class NestedValueConverter : public ValueConverter<NestedType> { |
}; |
template <typename Element> |
-class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > { |
+class RepeatedValueConverter |
+ : public ValueConverterBase<ScopedVector<Element> > { |
public: |
RepeatedValueConverter() {} |
@@ -275,8 +334,7 @@ class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > { |
field->reserve(list->GetSize()); |
for (size_t i = 0; i < list->GetSize(); ++i) { |
base::Value* element = NULL; |
- if (!list->Get(i, &element)) |
- continue; |
+ CHECK(list->Get(i, &element)); |
scoped_ptr<Element> e(new Element); |
if (basic_converter_.Convert(*element, e.get())) { |
@@ -296,7 +354,7 @@ class RepeatedValueConverter : public ValueConverter<ScopedVector<Element> > { |
template <typename NestedType> |
class RepeatedMessageConverter |
- : public ValueConverter<ScopedVector<NestedType> > { |
+ : public ValueConverterBase<ScopedVector<NestedType> > { |
public: |
RepeatedMessageConverter() {} |
@@ -309,8 +367,7 @@ class RepeatedMessageConverter |
field->reserve(list->GetSize()); |
for (size_t i = 0; i < list->GetSize(); ++i) { |
base::Value* element = NULL; |
- if (!list->Get(i, &element)) |
- continue; |
+ CHECK(list->Get(i, &element)); |
scoped_ptr<NestedType> nested(new NestedType); |
if (converter_.Convert(*element, nested.get())) { |
@@ -330,7 +387,7 @@ class RepeatedMessageConverter |
template <typename NestedType> |
class RepeatedCustomValueConverter |
- : public ValueConverter<ScopedVector<NestedType> > { |
+ : public ValueConverterBase<ScopedVector<NestedType> > { |
public: |
typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field); |
@@ -346,8 +403,7 @@ class RepeatedCustomValueConverter |
field->reserve(list->GetSize()); |
for (size_t i = 0; i < list->GetSize(); ++i) { |
base::Value* element = NULL; |
- if (!list->Get(i, &element)) |
- continue; |
+ CHECK(list->Get(i, &element)); |
scoped_ptr<NestedType> nested(new NestedType); |
if ((*convert_func_)(element, nested.get())) { |
@@ -436,6 +492,15 @@ class JSONValueConverter { |
new internal::ValueFieldConverter<FieldType>(convert_func))); |
} |
+ void RegisterCustomAction( |
+ const std::string& field_name, |
+ bool (*action_func)(const base::Value*, StructType*)) { |
+ fields_.push_back(new internal::FieldActionRunner<StructType>( |
+ field_name, |
+ false, // repeated |
+ action_func)); |
+ } |
+ |
void RegisterRepeatedInt(const std::string& field_name, |
ScopedVector<int> StructType::* field) { |
fields_.push_back( |
@@ -498,18 +563,26 @@ class JSONValueConverter { |
new internal::RepeatedMessageConverter<NestedType>)); |
} |
+ void RegisterRepeatedCustomAction( |
+ const std::string& field_name, |
+ bool (*action_func)(const base::Value*, StructType*)) { |
+ fields_.push_back(new internal::FieldActionRunner<StructType>( |
+ field_name, |
+ true, // repeated |
+ action_func)); |
+ } |
+ |
bool Convert(const base::Value& value, StructType* output) const { |
const DictionaryValue* dictionary_value = NULL; |
if (!value.GetAsDictionary(&dictionary_value)) |
return false; |
for(size_t i = 0; i < fields_.size(); ++i) { |
- const internal::FieldConverterBase<StructType>* field_converter = |
- fields_[i]; |
+ const internal::FieldHandlerBase<StructType>* field_handler = fields_[i]; |
base::Value* field = NULL; |
- if (dictionary_value->Get(field_converter->field_path(), &field)) { |
- if (!field_converter->ConvertField(*field, output)) { |
- DVLOG(1) << "failure at field " << field_converter->field_path(); |
+ if (dictionary_value->Get(field_handler->field_path(), &field)) { |
+ if (!field_handler->HandleField(*field, output)) { |
+ DVLOG(1) << "failure at field " << field_handler->field_path(); |
return false; |
} |
} |
@@ -518,7 +591,7 @@ class JSONValueConverter { |
} |
private: |
- ScopedVector<internal::FieldConverterBase<StructType> > fields_; |
+ ScopedVector<internal::FieldHandlerBase<StructType> > fields_; |
DISALLOW_COPY_AND_ASSIGN(JSONValueConverter); |
}; |