| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_ | |
| #define BASE_JSON_JSON_VALUE_CONVERTER_H_ | |
| #include <stddef.h> | |
| #include <memory> | |
| #include <string> | |
| #include <string_view> | |
| #include <vector> | |
| #include "base/logging.h" | |
| #include "base/memory/ptr_util.h" | |
| #include "base/values.h" | |
| // JSONValueConverter converts a JSON value into a C++ struct in a | |
| // lightweight way. | |
| // | |
| // Usage: | |
| // For real examples, you may want to refer to _unittest.cc file. | |
| // | |
| // Assume that you have a struct like this: | |
| // struct Message { | |
| // int foo; | |
| // std::string bar; | |
| // static void RegisterJSONConverter( | |
| // JSONValueConverter<Message>* converter); | |
| // }; | |
| // | |
| // And you want to parse a json data into this struct. First, you | |
| // need to declare RegisterJSONConverter() method in your struct. | |
| // // static | |
| // void Message::RegisterJSONConverter( | |
| // JSONValueConverter<Message>* converter) { | |
| // converter->RegisterIntField("foo", &Message::foo); | |
| // converter->RegisterStringField("bar", &Message::bar); | |
| // } | |
| // | |
| // Then, you just instantiate your JSONValueConverter of your type and call | |
| // Convert() method. | |
| // Message message; | |
| // JSONValueConverter<Message> converter; | |
| // converter.Convert(json, &message); | |
| // | |
| // Convert() returns false when it fails. Here "fail" means that the value is | |
| // structurally different from expected, such like a string value appears | |
| // for an int field. Do not report failures for missing fields. | |
| // Also note that Convert() will modify the passed |message| even when it | |
| // fails for performance reason. | |
| // | |
| // For nested field, the internal message also has to implement the registration | |
| // method. Then, just use RegisterNestedField() from the containing struct's | |
| // RegisterJSONConverter method. | |
| // struct Nested { | |
| // Message foo; | |
| // static void RegisterJSONConverter(...) { | |
| // ... | |
| // converter->RegisterNestedField("foo", &Nested::foo); | |
| // } | |
| // }; | |
| // | |
| // For repeated field, we just assume std::vector<std::unique_ptr<ElementType>> | |
| // for its container 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 std::string_view to your type. | |
| // bool ConvertFunc(std::string_view 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 { | |
| template <typename StructType> | |
| class JSONValueConverter; | |
| namespace internal { | |
| template <typename StructType> | |
| class FieldConverterBase { | |
| public: | |
| explicit FieldConverterBase(const std::string& path) : field_path_(path) {} | |
| virtual ~FieldConverterBase() = default; | |
| virtual bool ConvertField(const base::Value& value, | |
| StructType* obj) const = 0; | |
| const std::string& field_path() const { return field_path_; } | |
| private: | |
| std::string field_path_; | |
| FieldConverterBase(const FieldConverterBase&) = delete; | |
| FieldConverterBase& operator=(const FieldConverterBase&) = delete; | |
| }; | |
| template <typename FieldType> | |
| class ValueConverter { | |
| public: | |
| virtual ~ValueConverter() = default; | |
| virtual bool Convert(const base::Value& value, FieldType* field) const = 0; | |
| }; | |
| template <typename StructType, typename FieldType> | |
| class FieldConverter : public FieldConverterBase<StructType> { | |
| public: | |
| explicit FieldConverter(const std::string& path, | |
| FieldType StructType::* field, | |
| ValueConverter<FieldType>* converter) | |
| : FieldConverterBase<StructType>(path), | |
| field_pointer_(field), | |
| value_converter_(converter) {} | |
| bool ConvertField(const base::Value& value, StructType* dst) const override { | |
| return value_converter_->Convert(value, &(dst->*field_pointer_)); | |
| } | |
| private: | |
| FieldType StructType::* field_pointer_; | |
| std::unique_ptr<ValueConverter<FieldType>> value_converter_; | |
| FieldConverter(const FieldConverter&) = delete; | |
| FieldConverter& operator=(const FieldConverter&) = delete; | |
| }; | |
| template <typename FieldType> | |
| class BasicValueConverter; | |
| template <> | |
| class BasicValueConverter<int> : public ValueConverter<int> { | |
| public: | |
| BasicValueConverter() = default; | |
| bool Convert(const base::Value& value, int* field) const override; | |
| private: | |
| BasicValueConverter(const BasicValueConverter&) = delete; | |
| BasicValueConverter& operator=(const BasicValueConverter&) = delete; | |
| }; | |
| template <> | |
| class BasicValueConverter<std::string> : public ValueConverter<std::string> { | |
| public: | |
| BasicValueConverter() = default; | |
| bool Convert(const base::Value& value, std::string* field) const override; | |
| private: | |
| BasicValueConverter(const BasicValueConverter&) = delete; | |
| BasicValueConverter& operator=(const BasicValueConverter&) = delete; | |
| }; | |
| template <> | |
| class BasicValueConverter<std::u16string> | |
| : public ValueConverter<std::u16string> { | |
| public: | |
| BasicValueConverter() = default; | |
| bool Convert(const base::Value& value, std::u16string* field) const override; | |
| private: | |
| BasicValueConverter(const BasicValueConverter&) = delete; | |
| BasicValueConverter& operator=(const BasicValueConverter&) = delete; | |
| }; | |
| template <> | |
| class BasicValueConverter<double> : public ValueConverter<double> { | |
| public: | |
| BasicValueConverter() = default; | |
| bool Convert(const base::Value& value, double* field) const override; | |
| private: | |
| BasicValueConverter(const BasicValueConverter&) = delete; | |
| BasicValueConverter& operator=(const BasicValueConverter&) = delete; | |
| }; | |
| template <> | |
| class BasicValueConverter<bool> : public ValueConverter<bool> { | |
| public: | |
| BasicValueConverter() = default; | |
| bool Convert(const base::Value& value, bool* field) const override; | |
| private: | |
| BasicValueConverter(const BasicValueConverter&) = delete; | |
| BasicValueConverter& operator=(const BasicValueConverter&) = delete; | |
| }; | |
| template <typename FieldType> | |
| class ValueFieldConverter : public ValueConverter<FieldType> { | |
| public: | |
| typedef bool (*ConvertFunc)(const base::Value* value, FieldType* field); | |
| explicit ValueFieldConverter(ConvertFunc convert_func) | |
| : convert_func_(convert_func) {} | |
| bool Convert(const base::Value& value, FieldType* field) const override { | |
| return convert_func_(&value, field); | |
| } | |
| private: | |
| ConvertFunc convert_func_; | |
| ValueFieldConverter(const ValueFieldConverter&) = delete; | |
| ValueFieldConverter& operator=(const ValueFieldConverter&) = delete; | |
| }; | |
| template <typename FieldType> | |
| class CustomFieldConverter : public ValueConverter<FieldType> { | |
| public: | |
| typedef bool (*ConvertFunc)(std::string_view value, FieldType* field); | |
| explicit CustomFieldConverter(ConvertFunc convert_func) | |
| : convert_func_(convert_func) {} | |
| 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_; | |
| CustomFieldConverter(const CustomFieldConverter&) = delete; | |
| CustomFieldConverter& operator=(const CustomFieldConverter&) = delete; | |
| }; | |
| template <typename NestedType> | |
| class NestedValueConverter : public ValueConverter<NestedType> { | |
| public: | |
| NestedValueConverter() = default; | |
| bool Convert(const base::Value& value, NestedType* field) const override { | |
| return converter_.Convert(value, field); | |
| } | |
| private: | |
| JSONValueConverter<NestedType> converter_; | |
| NestedValueConverter(const NestedValueConverter&) = delete; | |
| NestedValueConverter& operator=(const NestedValueConverter&) = delete; | |
| }; | |
| template <typename Element> | |
| class RepeatedValueConverter | |
| : public ValueConverter<std::vector<std::unique_ptr<Element>>> { | |
| public: | |
| RepeatedValueConverter() = default; | |
| bool Convert(const base::Value& value, | |
| std::vector<std::unique_ptr<Element>>* field) const override { | |
| const base::ListValue* list = NULL; | |
| if (!value.GetAsList(&list)) { | |
| // The field is not a list. | |
| return false; | |
| } | |
| field->reserve(list->GetSize()); | |
| for (size_t i = 0; i < list->GetSize(); ++i) { | |
| const base::Value* element = NULL; | |
| if (!list->Get(i, &element)) | |
| continue; | |
| std::unique_ptr<Element> e(new Element); | |
| if (basic_converter_.Convert(*element, e.get())) { | |
| field->push_back(std::move(e)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| private: | |
| BasicValueConverter<Element> basic_converter_; | |
| RepeatedValueConverter(const RepeatedValueConverter&) = delete; | |
| RepeatedValueConverter& operator=(const RepeatedValueConverter&) = delete; | |
| }; | |
| template <typename NestedType> | |
| class RepeatedMessageConverter | |
| : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { | |
| public: | |
| RepeatedMessageConverter() = default; | |
| bool Convert(const base::Value& value, | |
| std::vector<std::unique_ptr<NestedType>>* field) const override { | |
| const base::ListValue* list = NULL; | |
| if (!value.GetAsList(&list)) | |
| return false; | |
| field->reserve(list->GetSize()); | |
| for (size_t i = 0; i < list->GetSize(); ++i) { | |
| const base::Value* element = NULL; | |
| if (!list->Get(i, &element)) | |
| continue; | |
| std::unique_ptr<NestedType> nested(new NestedType); | |
| if (converter_.Convert(*element, nested.get())) { | |
| field->push_back(std::move(nested)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| private: | |
| JSONValueConverter<NestedType> converter_; | |
| RepeatedMessageConverter(const RepeatedMessageConverter&) = delete; | |
| RepeatedMessageConverter& operator=(const RepeatedMessageConverter&) = delete; | |
| }; | |
| template <typename NestedType> | |
| class RepeatedCustomValueConverter | |
| : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> { | |
| public: | |
| typedef bool (*ConvertFunc)(const base::Value* value, NestedType* field); | |
| explicit RepeatedCustomValueConverter(ConvertFunc convert_func) | |
| : convert_func_(convert_func) {} | |
| bool Convert(const base::Value& value, | |
| std::vector<std::unique_ptr<NestedType>>* field) const override { | |
| const base::ListValue* list = NULL; | |
| if (!value.GetAsList(&list)) | |
| return false; | |
| field->reserve(list->GetSize()); | |
| for (size_t i = 0; i < list->GetSize(); ++i) { | |
| const base::Value* element = NULL; | |
| if (!list->Get(i, &element)) | |
| continue; | |
| std::unique_ptr<NestedType> nested(new NestedType); | |
| if ((*convert_func_)(element, nested.get())) { | |
| field->push_back(std::move(nested)); | |
| } else { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| private: | |
| ConvertFunc convert_func_; | |
| RepeatedCustomValueConverter(const RepeatedCustomValueConverter&) = delete; | |
| RepeatedCustomValueConverter& operator=(const RepeatedCustomValueConverter&) = | |
| delete; | |
| }; | |
| } // namespace internal | |
| template <class StructType> | |
| class JSONValueConverter { | |
| public: | |
| JSONValueConverter() { StructType::RegisterJSONConverter(this); } | |
| void RegisterIntField(const std::string& field_name, | |
| int StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, int>>( | |
| field_name, field, new internal::BasicValueConverter<int>)); | |
| } | |
| void RegisterStringField(const std::string& field_name, | |
| std::string StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, std::string>>( | |
| field_name, field, new internal::BasicValueConverter<std::string>)); | |
| } | |
| void RegisterStringField(const std::string& field_name, | |
| std::u16string StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, std::u16string>>( | |
| field_name, field, | |
| new internal::BasicValueConverter<std::u16string>)); | |
| } | |
| void RegisterBoolField(const std::string& field_name, | |
| bool StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, bool>>( | |
| field_name, field, new internal::BasicValueConverter<bool>)); | |
| } | |
| void RegisterDoubleField(const std::string& field_name, | |
| double StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, double>>( | |
| field_name, field, new internal::BasicValueConverter<double>)); | |
| } | |
| template <class NestedType> | |
| void RegisterNestedField(const std::string& field_name, | |
| NestedType StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, NestedType>>( | |
| field_name, field, new internal::NestedValueConverter<NestedType>)); | |
| } | |
| template <typename FieldType> | |
| void RegisterCustomField(const std::string& field_name, | |
| FieldType StructType::* field, | |
| bool (*convert_func)(std::string_view, FieldType*)) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, FieldType>>( | |
| field_name, field, | |
| new internal::CustomFieldConverter<FieldType>(convert_func))); | |
| } | |
| template <typename FieldType> | |
| void RegisterCustomValueField(const std::string& field_name, | |
| FieldType StructType::* field, | |
| bool (*convert_func)(const base::Value*, | |
| FieldType*)) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter<StructType, FieldType>>( | |
| field_name, field, | |
| new internal::ValueFieldConverter<FieldType>(convert_func))); | |
| } | |
| void RegisterRepeatedInt( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<int>> StructType::* field) { | |
| fields_.push_back(std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<int>>>>( | |
| field_name, field, new internal::RepeatedValueConverter<int>)); | |
| } | |
| void RegisterRepeatedString( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<std::string>> StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<std::string>>>>( | |
| field_name, field, | |
| new internal::RepeatedValueConverter<std::string>)); | |
| } | |
| void RegisterRepeatedString( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<std::u16string>> StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<std::u16string>>>>( | |
| field_name, field, | |
| new internal::RepeatedValueConverter<std::u16string>)); | |
| } | |
| void RegisterRepeatedDouble( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<double>> StructType::* field) { | |
| fields_.push_back(std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<double>>>>( | |
| field_name, field, new internal::RepeatedValueConverter<double>)); | |
| } | |
| void RegisterRepeatedBool( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<bool>> StructType::* field) { | |
| fields_.push_back(std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<bool>>>>( | |
| field_name, field, new internal::RepeatedValueConverter<bool>)); | |
| } | |
| template <class NestedType> | |
| void RegisterRepeatedCustomValue( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<NestedType>> StructType::* field, | |
| bool (*convert_func)(const base::Value*, NestedType*)) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<NestedType>>>>( | |
| field_name, field, | |
| new internal::RepeatedCustomValueConverter<NestedType>( | |
| convert_func))); | |
| } | |
| template <class NestedType> | |
| void RegisterRepeatedMessage( | |
| const std::string& field_name, | |
| std::vector<std::unique_ptr<NestedType>> StructType::* field) { | |
| fields_.push_back( | |
| std::make_unique<internal::FieldConverter< | |
| StructType, std::vector<std::unique_ptr<NestedType>>>>( | |
| field_name, field, | |
| new internal::RepeatedMessageConverter<NestedType>)); | |
| } | |
| 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].get(); | |
| const base::Value* field = NULL; | |
| if (dictionary_value->Get(field_converter->field_path(), &field)) { | |
| if (!field_converter->ConvertField(*field, output)) { | |
| return false; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| private: | |
| std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>> | |
| fields_; | |
| JSONValueConverter(const JSONValueConverter&) = delete; | |
| JSONValueConverter& operator=(const JSONValueConverter&) = delete; | |
| }; | |
| } // namespace base | |
| #endif // BASE_JSON_JSON_VALUE_CONVERTER_H_ |