blob: ea43dbb92adc7879d10304daa50e148c31b0061a [file] [log] [blame]
[email protected]261c877e2012-01-05 09:46:421// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]193f946b2011-12-22 18:31:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_JSON_JSON_VALUE_CONVERTER_H_
6#define BASE_JSON_JSON_VALUE_CONVERTER_H_
7#pragma once
8
9#include <string>
10#include <vector>
11
12#include "base/base_export.h"
13#include "base/basictypes.h"
14#include "base/logging.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/stl_util.h"
[email protected]261c877e2012-01-05 09:46:4217#include "base/string16.h"
[email protected]6009ca92012-01-13 02:18:0218#include "base/string_piece.h"
[email protected]193f946b2011-12-22 18:31:4719#include "base/values.h"
20
21// JSONValueConverter converts a JSON value into a C++ struct in a
22// lightweight way.
23//
24// Usage:
25// For real examples, you may want to refer to _unittest.cc file.
26//
27// Assume that you have a struct like this:
28// struct Message {
29// int foo;
30// std::string bar;
31// static void RegisterJSONConverter(
32// JSONValueConverter<Message>* converter);
33// };
34//
35// And you want to parse a json data into this struct. First, you
36// need to declare RegisterJSONConverter() method in your struct.
37// // static
38// void Message::RegisterJSONConverter(
39// JSONValueConverter<Message>* converter) {
40// converter->RegisterIntField("foo", &Message::foo);
41// converter->RegisterStringField("bar", &Message::bar);
42// }
43//
44// Then, you just instantiate your JSONValueConverter of your type and call
45// Convert() method.
46// Message message;
47// JSONValueConverter<Message> converter;
48// converter.Convert(json, &message);
49//
[email protected]261c877e2012-01-05 09:46:4250// Convert() returns false when it fails. Here "fail" means that the value is
51// structurally different from expected, such like a string value appears
52// for an int field. Do not report failures for missing fields.
53// Also note that Convert() will modify the passed |message| even when it
54// fails for performance reason.
55//
[email protected]193f946b2011-12-22 18:31:4756// For nested field, the internal message also has to implement the registration
57// method. Then, just use RegisterNestedField() from the containing struct's
58// RegisterJSONConverter method.
59// struct Nested {
60// Message foo;
[email protected]261c877e2012-01-05 09:46:4261// static void RegisterJSONConverter(...) {
[email protected]193f946b2011-12-22 18:31:4762// ...
63// converter->RegisterNestedField("foo", &Nested::foo);
64// }
65// };
66//
67// For repeated field, we just assume std::vector for its container
68// and you can put RegisterRepeatedInt or some other types. Use
69// RegisterRepeatedMessage for nested repeated fields.
70//
[email protected]6009ca92012-01-13 02:18:0271// Sometimes JSON format uses string representations for other types such
72// like enum, timestamp, or URL. You can use RegisterCustomField method
73// and specify a function to convert a StringPiece to your type.
74// bool ConvertFunc(const StringPiece& s, YourEnum* result) {
75// // do something and return true if succeed...
76// }
77// struct Message {
78// YourEnum ye;
79// ...
80// static void RegisterJSONConverter(...) {
81// ...
82// converter->RegsiterCustomField<YourEnum>(
83// "your_enum", &Message::ye, &ConvertFunc);
84// }
85// };
[email protected]193f946b2011-12-22 18:31:4786
87namespace base {
88
89template <typename StructType>
90class JSONValueConverter;
91
92namespace internal {
93
94class FieldConverterBase {
95 public:
96 BASE_EXPORT explicit FieldConverterBase(const std::string& path);
97 BASE_EXPORT virtual ~FieldConverterBase();
[email protected]261c877e2012-01-05 09:46:4298 virtual bool ConvertField(const base::Value& value, void* obj) const = 0;
[email protected]193f946b2011-12-22 18:31:4799 const std::string& field_path() const { return field_path_; }
100
101 private:
102 std::string field_path_;
103 DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
104};
105
106template <typename FieldType>
107class ValueConverter {
108 public:
109 virtual ~ValueConverter() {}
[email protected]261c877e2012-01-05 09:46:42110 virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
[email protected]193f946b2011-12-22 18:31:47111};
112
113template <typename StructType, typename FieldType>
114class FieldConverter : public FieldConverterBase {
115 public:
116 explicit FieldConverter(const std::string& path,
117 FieldType StructType::* field,
118 ValueConverter<FieldType>* converter)
119 : FieldConverterBase(path),
120 field_pointer_(field),
121 value_converter_(converter) {
122 }
123
[email protected]261c877e2012-01-05 09:46:42124 virtual bool ConvertField(
[email protected]193f946b2011-12-22 18:31:47125 const base::Value& value, void* obj) const OVERRIDE {
126 StructType* dst = reinterpret_cast<StructType*>(obj);
[email protected]261c877e2012-01-05 09:46:42127 return value_converter_->Convert(value, &(dst->*field_pointer_));
[email protected]193f946b2011-12-22 18:31:47128 }
129
130 private:
131 FieldType StructType::* field_pointer_;
132 scoped_ptr<ValueConverter<FieldType> > value_converter_;
133 DISALLOW_COPY_AND_ASSIGN(FieldConverter);
134};
135
136template <typename FieldType>
137class BasicValueConverter;
138
139template <>
140class BasicValueConverter<int> : public ValueConverter<int> {
141 public:
142 BasicValueConverter() {}
143
[email protected]261c877e2012-01-05 09:46:42144 virtual bool Convert(const base::Value& value, int* field) const OVERRIDE {
145 return value.GetAsInteger(field);
[email protected]193f946b2011-12-22 18:31:47146 }
147
148 private:
149 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
150};
151
152template <>
153class BasicValueConverter<std::string> : public ValueConverter<std::string> {
154 public:
155 BasicValueConverter() {}
156
[email protected]261c877e2012-01-05 09:46:42157 virtual bool Convert(
[email protected]193f946b2011-12-22 18:31:47158 const base::Value& value, std::string* field) const OVERRIDE {
[email protected]261c877e2012-01-05 09:46:42159 return value.GetAsString(field);
160 }
161
162 private:
163 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
164};
165
166template <>
167class BasicValueConverter<string16> : public ValueConverter<string16> {
168 public:
169 BasicValueConverter() {}
170
171 virtual bool Convert(
172 const base::Value& value, string16* field) const OVERRIDE {
173 return value.GetAsString(field);
[email protected]193f946b2011-12-22 18:31:47174 }
175
176 private:
177 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
178};
179
180template <>
181class BasicValueConverter<double> : public ValueConverter<double> {
182 public:
183 BasicValueConverter() {}
184
[email protected]261c877e2012-01-05 09:46:42185 virtual bool Convert(const base::Value& value, double* field) const OVERRIDE {
186 return value.GetAsDouble(field);
[email protected]193f946b2011-12-22 18:31:47187 }
188
189 private:
190 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
191};
192
193template <>
194class BasicValueConverter<bool> : public ValueConverter<bool> {
195 public:
196 BasicValueConverter() {}
197
[email protected]261c877e2012-01-05 09:46:42198 virtual bool Convert(const base::Value& value, bool* field) const OVERRIDE {
199 return value.GetAsBoolean(field);
[email protected]193f946b2011-12-22 18:31:47200 }
201
202 private:
203 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
204};
205
[email protected]6009ca92012-01-13 02:18:02206template <typename FieldType>
207class CustomFieldConverter : public ValueConverter<FieldType> {
208 public:
209 typedef bool(*ConvertFunc)(const StringPiece& value, FieldType* field);
210
211 CustomFieldConverter(ConvertFunc convert_func)
212 : convert_func_(convert_func) {}
213
214 virtual bool Convert(const base::Value& value,
215 FieldType* field) const OVERRIDE {
216 std::string string_value;
217 return value.GetAsString(&string_value) &&
218 convert_func_(string_value, field);
219 }
220
221 private:
222 ConvertFunc convert_func_;
223
224 DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
225};
226
[email protected]193f946b2011-12-22 18:31:47227template <typename NestedType>
228class NestedValueConverter : public ValueConverter<NestedType> {
229 public:
230 NestedValueConverter() {}
231
[email protected]261c877e2012-01-05 09:46:42232 virtual bool Convert(
[email protected]193f946b2011-12-22 18:31:47233 const base::Value& value, NestedType* field) const OVERRIDE {
[email protected]261c877e2012-01-05 09:46:42234 return converter_.Convert(value, field);
[email protected]193f946b2011-12-22 18:31:47235 }
236
237 private:
238 JSONValueConverter<NestedType> converter_;
239 DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
240};
241
242template <typename Element>
243class RepeatedValueConverter : public ValueConverter<std::vector<Element> > {
244 public:
245 RepeatedValueConverter() {}
246
[email protected]261c877e2012-01-05 09:46:42247 virtual bool Convert(
[email protected]193f946b2011-12-22 18:31:47248 const base::Value& value, std::vector<Element>* field) const OVERRIDE {
249 const base::ListValue* list = NULL;
250 if (!value.GetAsList(&list)) {
251 // The field is not a list.
[email protected]261c877e2012-01-05 09:46:42252 return false;
[email protected]193f946b2011-12-22 18:31:47253 }
254
255 field->reserve(list->GetSize());
256 for (size_t i = 0; i < list->GetSize(); ++i) {
257 base::Value* element = NULL;
258 if (!list->Get(i, &element))
259 continue;
260
261 Element e;
[email protected]261c877e2012-01-05 09:46:42262 if (!basic_converter_.Convert(*element, &e)) {
263 DVLOG(1) << "failure at " << i << "-th element";
264 return false;
265 }
[email protected]193f946b2011-12-22 18:31:47266 field->push_back(e);
267 }
[email protected]261c877e2012-01-05 09:46:42268 return true;
[email protected]193f946b2011-12-22 18:31:47269 }
270
271 private:
272 BasicValueConverter<Element> basic_converter_;
273 DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
274};
275
276template <typename NestedType>
277class RepeatedMessageConverter
278 : public ValueConverter<std::vector<NestedType> > {
279 public:
280 RepeatedMessageConverter() {}
281
[email protected]261c877e2012-01-05 09:46:42282 virtual bool Convert(
[email protected]193f946b2011-12-22 18:31:47283 const base::Value& value, std::vector<NestedType>* field) const OVERRIDE {
284 const base::ListValue* list = NULL;
285 if (!value.GetAsList(&list))
[email protected]261c877e2012-01-05 09:46:42286 return false;
[email protected]193f946b2011-12-22 18:31:47287
288 field->reserve(list->GetSize());
289 for (size_t i = 0; i < list->GetSize(); ++i) {
290 base::Value* element = NULL;
291 if (!list->Get(i, &element))
292 continue;
293
294 field->push_back(NestedType());
[email protected]261c877e2012-01-05 09:46:42295 if (!converter_.Convert(*element, &field->back())) {
296 DVLOG(1) << "failure at " << i << "-th element";
297 return false;
298 }
[email protected]193f946b2011-12-22 18:31:47299 }
[email protected]261c877e2012-01-05 09:46:42300 return true;
[email protected]193f946b2011-12-22 18:31:47301 }
302
303 private:
304 JSONValueConverter<NestedType> converter_;
305 DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
306};
307
308} // namespace internal
309
310template <class StructType>
311class JSONValueConverter {
312 public:
313 JSONValueConverter() {
314 StructType::RegisterJSONConverter(this);
315 }
316
317 ~JSONValueConverter() {
318 STLDeleteContainerPointers(fields_.begin(), fields_.end());
319 }
320
321 void RegisterIntField(const std::string& field_name,
322 int StructType::* field) {
323 fields_.push_back(new internal::FieldConverter<StructType, int>(
324 field_name, field, new internal::BasicValueConverter<int>));
325 }
326
327 void RegisterStringField(const std::string& field_name,
[email protected]261c877e2012-01-05 09:46:42328 std::string StructType::* field) {
[email protected]193f946b2011-12-22 18:31:47329 fields_.push_back(new internal::FieldConverter<StructType, std::string>(
330 field_name, field, new internal::BasicValueConverter<std::string>));
331 }
332
[email protected]261c877e2012-01-05 09:46:42333 void RegisterStringField(const std::string& field_name,
334 string16 StructType::* field) {
335 fields_.push_back(new internal::FieldConverter<StructType, string16>(
336 field_name, field, new internal::BasicValueConverter<string16>));
337 }
338
[email protected]193f946b2011-12-22 18:31:47339 void RegisterBoolField(const std::string& field_name,
340 bool StructType::* field) {
341 fields_.push_back(new internal::FieldConverter<StructType, bool>(
342 field_name, field, new internal::BasicValueConverter<bool>));
343 }
344
345 void RegisterDoubleField(const std::string& field_name,
346 double StructType::* field) {
347 fields_.push_back(new internal::FieldConverter<StructType, double>(
348 field_name, field, new internal::BasicValueConverter<double>));
349 }
350
351 template <class NestedType>
352 void RegisterNestedField(
353 const std::string& field_name, NestedType StructType::* field) {
354 fields_.push_back(new internal::FieldConverter<StructType, NestedType>(
355 field_name,
356 field,
357 new internal::NestedValueConverter<NestedType>));
358 }
359
[email protected]6009ca92012-01-13 02:18:02360 template <typename FieldType>
361 void RegisterCustomField(
362 const std::string& field_name,
363 FieldType StructType::* field,
364 bool (*convert_func)(const StringPiece&, FieldType*)) {
365 fields_.push_back(new internal::FieldConverter<StructType, FieldType>(
366 field_name,
367 field,
368 new internal::CustomFieldConverter<FieldType>(convert_func)));
369 }
370
[email protected]193f946b2011-12-22 18:31:47371 void RegisterRepeatedInt(const std::string& field_name,
372 std::vector<int> StructType::* field) {
373 fields_.push_back(
374 new internal::FieldConverter<StructType, std::vector<int> >(
375 field_name, field, new internal::RepeatedValueConverter<int>));
376 }
377
378 void RegisterRepeatedString(const std::string& field_name,
379 std::vector<std::string> StructType::* field) {
380 fields_.push_back(
381 new internal::FieldConverter<StructType, std::vector<std::string> >(
382 field_name,
383 field,
384 new internal::RepeatedValueConverter<std::string>));
385 }
386
[email protected]261c877e2012-01-05 09:46:42387 void RegisterRepeatedString(const std::string& field_name,
388 std::vector<string16> StructType::* field) {
389 fields_.push_back(
390 new internal::FieldConverter<StructType, std::vector<string16> >(
391 field_name,
392 field,
393 new internal::RepeatedValueConverter<string16>));
394 }
395
[email protected]193f946b2011-12-22 18:31:47396 void RegisterRepeatedDouble(const std::string& field_name,
397 std::vector<double> StructType::* field) {
398 fields_.push_back(
399 new internal::FieldConverter<StructType, std::vector<double> >(
400 field_name, field, new internal::RepeatedValueConverter<double>));
401 }
402
403 void RegisterRepeatedBool(const std::string& field_name,
404 std::vector<bool> StructType::* field) {
405 fields_.push_back(
406 new internal::FieldConverter<StructType, std::vector<bool> >(
407 field_name, field, new internal::RepeatedValueConverter<bool>));
408 }
409
410 template <class NestedType>
411 void RegisterRepeatedMessage(const std::string& field_name,
412 std::vector<NestedType> StructType::* field) {
413 fields_.push_back(
414 new internal::FieldConverter<StructType, std::vector<NestedType> >(
415 field_name,
416 field,
417 new internal::RepeatedMessageConverter<NestedType>));
418 }
419
[email protected]261c877e2012-01-05 09:46:42420 bool Convert(const base::Value& value, StructType* output) const {
[email protected]193f946b2011-12-22 18:31:47421 const DictionaryValue* dictionary_value = NULL;
422 if (!value.GetAsDictionary(&dictionary_value))
[email protected]261c877e2012-01-05 09:46:42423 return false;
[email protected]193f946b2011-12-22 18:31:47424
425 for(std::vector<internal::FieldConverterBase*>::const_iterator it =
426 fields_.begin(); it != fields_.end(); ++it) {
427 base::Value* field = NULL;
428 if (dictionary_value->Get((*it)->field_path(), &field)) {
[email protected]261c877e2012-01-05 09:46:42429 if (!(*it)->ConvertField(*field, output)) {
430 DVLOG(1) << "failure at field " << (*it)->field_path();
431 return false;
432 }
[email protected]193f946b2011-12-22 18:31:47433 }
434 }
[email protected]261c877e2012-01-05 09:46:42435 return true;
[email protected]193f946b2011-12-22 18:31:47436 }
437
438 private:
439 std::vector<internal::FieldConverterBase*> fields_;
440
441 DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
442};
443
444} // namespace base
445
446#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_