528 lines
16 KiB
C++
528 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 <string>
|
|
#include <vector>
|
|
|
|
#include "base/basictypes.h"
|
|
#include "base/logging.h"
|
|
#include "base/memory/scoped_ptr.h"
|
|
#include "base/memory/scoped_vector.h"
|
|
#include "base/stl_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 ScopedVector 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(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 {
|
|
|
|
template <typename StructType>
|
|
class JSONValueConverter;
|
|
|
|
namespace internal {
|
|
|
|
template<typename StructType>
|
|
class FieldConverterBase {
|
|
public:
|
|
explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
|
|
virtual ~FieldConverterBase() {}
|
|
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() {}
|
|
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) {
|
|
}
|
|
|
|
virtual bool ConvertField(
|
|
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_;
|
|
DISALLOW_COPY_AND_ASSIGN(FieldConverter);
|
|
};
|
|
|
|
template <typename FieldType>
|
|
class BasicValueConverter;
|
|
|
|
template <>
|
|
class BasicValueConverter<int> : public ValueConverter<int> {
|
|
public:
|
|
BasicValueConverter() {}
|
|
|
|
virtual bool Convert(const base::Value& value, int* field) const OVERRIDE {
|
|
return value.GetAsInteger(field);
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
|
};
|
|
|
|
template <>
|
|
class BasicValueConverter<std::string> : public ValueConverter<std::string> {
|
|
public:
|
|
BasicValueConverter() {}
|
|
|
|
virtual bool Convert(
|
|
const base::Value& value, std::string* field) const OVERRIDE {
|
|
return value.GetAsString(field);
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
|
};
|
|
|
|
template <>
|
|
class BasicValueConverter<string16> : public ValueConverter<string16> {
|
|
public:
|
|
BasicValueConverter() {}
|
|
|
|
virtual bool Convert(
|
|
const base::Value& value, string16* field) const OVERRIDE {
|
|
return value.GetAsString(field);
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
|
};
|
|
|
|
template <>
|
|
class BasicValueConverter<double> : public ValueConverter<double> {
|
|
public:
|
|
BasicValueConverter() {}
|
|
|
|
virtual bool Convert(const base::Value& value, double* field) const OVERRIDE {
|
|
return value.GetAsDouble(field);
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
|
};
|
|
|
|
template <>
|
|
class BasicValueConverter<bool> : public ValueConverter<bool> {
|
|
public:
|
|
BasicValueConverter() {}
|
|
|
|
virtual bool Convert(const base::Value& value, bool* field) const OVERRIDE {
|
|
return value.GetAsBoolean(field);
|
|
}
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
|
|
};
|
|
|
|
template <typename FieldType>
|
|
class ValueFieldConverter : public ValueConverter<FieldType> {
|
|
public:
|
|
typedef bool(*ConvertFunc)(const base::Value* value, FieldType* field);
|
|
|
|
ValueFieldConverter(ConvertFunc convert_func)
|
|
: convert_func_(convert_func) {}
|
|
|
|
virtual 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)(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:
|
|
NestedValueConverter() {}
|
|
|
|
virtual 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<ScopedVector<Element> > {
|
|
public:
|
|
RepeatedValueConverter() {}
|
|
|
|
virtual bool Convert(
|
|
const base::Value& value, ScopedVector<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;
|
|
|
|
scoped_ptr<Element> e(new Element);
|
|
if (basic_converter_.Convert(*element, e.get())) {
|
|
field->push_back(e.release());
|
|
} else {
|
|
DVLOG(1) << "failure at " << i << "-th element";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
BasicValueConverter<Element> basic_converter_;
|
|
DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
|
|
};
|
|
|
|
template <typename NestedType>
|
|
class RepeatedMessageConverter
|
|
: public ValueConverter<ScopedVector<NestedType> > {
|
|
public:
|
|
RepeatedMessageConverter() {}
|
|
|
|
virtual bool Convert(const base::Value& value,
|
|
ScopedVector<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;
|
|
|
|
scoped_ptr<NestedType> nested(new NestedType);
|
|
if (converter_.Convert(*element, nested.get())) {
|
|
field->push_back(nested.release());
|
|
} else {
|
|
DVLOG(1) << "failure at " << i << "-th element";
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
JSONValueConverter<NestedType> converter_;
|
|
DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
|
|
};
|
|
|
|
template <typename NestedType>
|
|
class RepeatedCustomValueConverter
|
|
: public ValueConverter<ScopedVector<NestedType> > {
|
|
public:
|
|
typedef bool(*ConvertFunc)(const base::Value* value, NestedType* field);
|
|
|
|
RepeatedCustomValueConverter(ConvertFunc convert_func)
|
|
: convert_func_(convert_func) {}
|
|
|
|
virtual bool Convert(const base::Value& value,
|
|
ScopedVector<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;
|
|
|
|
scoped_ptr<NestedType> nested(new NestedType);
|
|
if ((*convert_func_)(element, nested.get())) {
|
|
field->push_back(nested.release());
|
|
} else {
|
|
DVLOG(1) << "failure at " << i << "-th element";
|
|
return false;
|
|
}
|
|
}
|
|
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(new 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(new 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(new internal::FieldConverter<StructType, string16>(
|
|
field_name, field, new internal::BasicValueConverter<string16>));
|
|
}
|
|
|
|
void RegisterBoolField(const std::string& field_name,
|
|
bool StructType::* field) {
|
|
fields_.push_back(new internal::FieldConverter<StructType, bool>(
|
|
field_name, field, new internal::BasicValueConverter<bool>));
|
|
}
|
|
|
|
void RegisterDoubleField(const std::string& field_name,
|
|
double StructType::* field) {
|
|
fields_.push_back(new 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(new 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)(const StringPiece&, FieldType*)) {
|
|
fields_.push_back(new 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(new internal::FieldConverter<StructType, FieldType>(
|
|
field_name,
|
|
field,
|
|
new internal::ValueFieldConverter<FieldType>(convert_func)));
|
|
}
|
|
|
|
void RegisterRepeatedInt(const std::string& field_name,
|
|
ScopedVector<int> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<int> >(
|
|
field_name, field, new internal::RepeatedValueConverter<int>));
|
|
}
|
|
|
|
void RegisterRepeatedString(const std::string& field_name,
|
|
ScopedVector<std::string> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<std::string> >(
|
|
field_name,
|
|
field,
|
|
new internal::RepeatedValueConverter<std::string>));
|
|
}
|
|
|
|
void RegisterRepeatedString(const std::string& field_name,
|
|
ScopedVector<string16> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<string16> >(
|
|
field_name,
|
|
field,
|
|
new internal::RepeatedValueConverter<string16>));
|
|
}
|
|
|
|
void RegisterRepeatedDouble(const std::string& field_name,
|
|
ScopedVector<double> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<double> >(
|
|
field_name, field, new internal::RepeatedValueConverter<double>));
|
|
}
|
|
|
|
void RegisterRepeatedBool(const std::string& field_name,
|
|
ScopedVector<bool> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<bool> >(
|
|
field_name, field, new internal::RepeatedValueConverter<bool>));
|
|
}
|
|
|
|
template <class NestedType>
|
|
void RegisterRepeatedCustomValue(
|
|
const std::string& field_name,
|
|
ScopedVector<NestedType> StructType::* field,
|
|
bool (*convert_func)(const base::Value*, NestedType*)) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<NestedType> >(
|
|
field_name,
|
|
field,
|
|
new internal::RepeatedCustomValueConverter<NestedType>(
|
|
convert_func)));
|
|
}
|
|
|
|
template <class NestedType>
|
|
void RegisterRepeatedMessage(const std::string& field_name,
|
|
ScopedVector<NestedType> StructType::* field) {
|
|
fields_.push_back(
|
|
new internal::FieldConverter<StructType, ScopedVector<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];
|
|
const 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();
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
ScopedVector<internal::FieldConverterBase<StructType> > fields_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
|
|
};
|
|
|
|
} // namespace base
|
|
|
|
#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_
|