// 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_