515 lines
16 KiB
C
515 lines
16 KiB
C
|
// 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 <vector>
|
||
|
|
||
|
#include "base/base_export.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "base/macros.h"
|
||
|
#include "base/memory/ptr_util.h"
|
||
|
#include "base/strings/string16.h"
|
||
|
#include "base/strings/string_piece.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 StringPiece to your type.
|
||
|
// bool ConvertFunc(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 {
|
||
|
|
||
|
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_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
|
||
|
};
|
||
|
|
||
|
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_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(FieldConverter);
|
||
|
};
|
||
|
|
||
|
template <typename FieldType>
|
||
|
class BasicValueConverter;
|
||
|
|
||
|
template <>
|
||
|
class BASE_EXPORT BasicValueConverter<int> : public ValueConverter<int> {
|
||
|
public:
|
||
|
BasicValueConverter() = default;
|
||
|
|
||
|
bool Convert(const base::Value& value, int* field) const override;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
class BASE_EXPORT BasicValueConverter<std::string>
|
||
|
: public ValueConverter<std::string> {
|
||
|
public:
|
||
|
BasicValueConverter() = default;
|
||
|
|
||
|
bool Convert(const base::Value& value, std::string* field) const override;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
class BASE_EXPORT BasicValueConverter<string16>
|
||
|
: public ValueConverter<string16> {
|
||
|
public:
|
||
|
BasicValueConverter() = default;
|
||
|
|
||
|
bool Convert(const base::Value& value, string16* field) const override;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
class BASE_EXPORT BasicValueConverter<double> : public ValueConverter<double> {
|
||
|
public:
|
||
|
BasicValueConverter() = default;
|
||
|
|
||
|
bool Convert(const base::Value& value, double* field) const override;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
||
|
};
|
||
|
|
||
|
template <>
|
||
|
class BASE_EXPORT BasicValueConverter<bool> : public ValueConverter<bool> {
|
||
|
public:
|
||
|
BasicValueConverter() = default;
|
||
|
|
||
|
bool Convert(const base::Value& value, bool* field) const override;
|
||
|
|
||
|
private:
|
||
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
||
|
};
|
||
|
|
||
|
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_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
|
||
|
};
|
||
|
|
||
|
template <typename FieldType>
|
||
|
class CustomFieldConverter : public ValueConverter<FieldType> {
|
||
|
public:
|
||
|
typedef bool (*ConvertFunc)(StringPiece 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_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
|
||
|
};
|
||
|
|
||
|
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_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
|
||
|
};
|
||
|
|
||
|
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 {
|
||
|
if (!value.is_list()) {
|
||
|
// The field is not a list.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
field->reserve(value.GetList().size());
|
||
|
size_t i = 0;
|
||
|
for (const Value& element : value.GetList()) {
|
||
|
auto e = std::make_unique<Element>();
|
||
|
if (basic_converter_.Convert(element, e.get())) {
|
||
|
field->push_back(std::move(e));
|
||
|
} else {
|
||
|
DVLOG(1) << "failure at " << i << "-th element";
|
||
|
return false;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
BasicValueConverter<Element> basic_converter_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
|
||
|
};
|
||
|
|
||
|
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 {
|
||
|
if (!value.is_list())
|
||
|
return false;
|
||
|
|
||
|
field->reserve(value.GetList().size());
|
||
|
size_t i = 0;
|
||
|
for (const Value& element : value.GetList()) {
|
||
|
auto nested = std::make_unique<NestedType>();
|
||
|
if (converter_.Convert(element, nested.get())) {
|
||
|
field->push_back(std::move(nested));
|
||
|
} else {
|
||
|
DVLOG(1) << "failure at " << i << "-th element";
|
||
|
return false;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
JSONValueConverter<NestedType> converter_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
|
||
|
};
|
||
|
|
||
|
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 {
|
||
|
if (!value.is_list())
|
||
|
return false;
|
||
|
|
||
|
field->reserve(value.GetList().size());
|
||
|
size_t i = 0;
|
||
|
for (const Value& element : value.GetList()) {
|
||
|
auto nested = std::make_unique<NestedType>();
|
||
|
if ((*convert_func_)(&element, nested.get())) {
|
||
|
field->push_back(std::move(nested));
|
||
|
} else {
|
||
|
DVLOG(1) << "failure at " << i << "-th element";
|
||
|
return false;
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
ConvertFunc convert_func_;
|
||
|
DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
|
||
|
};
|
||
|
|
||
|
|
||
|
} // 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,
|
||
|
string16 StructType::* field) {
|
||
|
fields_.push_back(
|
||
|
std::make_unique<internal::FieldConverter<StructType, string16>>(
|
||
|
field_name, field, new internal::BasicValueConverter<string16>));
|
||
|
}
|
||
|
|
||
|
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)(StringPiece, 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<string16>> StructType::*field) {
|
||
|
fields_.push_back(std::make_unique<internal::FieldConverter<
|
||
|
StructType, std::vector<std::unique_ptr<string16>>>>(
|
||
|
field_name, field, new internal::RepeatedValueConverter<string16>));
|
||
|
}
|
||
|
|
||
|
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 {
|
||
|
if (!value.is_dict())
|
||
|
return false;
|
||
|
|
||
|
for (size_t i = 0; i < fields_.size(); ++i) {
|
||
|
const internal::FieldConverterBase<StructType>* field_converter =
|
||
|
fields_[i].get();
|
||
|
const base::Value* field = value.FindPath(field_converter->field_path());
|
||
|
if (field) {
|
||
|
if (!field_converter->ConvertField(*field, output)) {
|
||
|
DVLOG(1) << "failure at field " << field_converter->field_path();
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>>
|
||
|
fields_;
|
||
|
|
||
|
DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
|
||
|
};
|
||
|
|
||
|
} // namespace base
|
||
|
|
||
|
#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_
|