| 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);
|
| };
|
|
|