blob: f3030f2c949c1450f662add85d23b56d75fd26b9 [file] [log] [blame]
Scott Graham66962112018-06-08 12:42:08 -07001// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// 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
8#include <stddef.h>
9
10#include <memory>
11#include <string>
Brett Wilsonad9e4422019-09-07 13:33:06 -070012#include <string_view>
Scott Graham66962112018-06-08 12:42:08 -070013#include <vector>
14
Scott Graham66962112018-06-08 12:42:08 -070015#include "base/logging.h"
16#include "base/macros.h"
17#include "base/memory/ptr_util.h"
Scott Graham66962112018-06-08 12:42:08 -070018#include "base/values.h"
19
20// JSONValueConverter converts a JSON value into a C++ struct in a
21// lightweight way.
22//
23// Usage:
24// For real examples, you may want to refer to _unittest.cc file.
25//
26// Assume that you have a struct like this:
27// struct Message {
28// int foo;
29// std::string bar;
30// static void RegisterJSONConverter(
31// JSONValueConverter<Message>* converter);
32// };
33//
34// And you want to parse a json data into this struct. First, you
35// need to declare RegisterJSONConverter() method in your struct.
36// // static
37// void Message::RegisterJSONConverter(
38// JSONValueConverter<Message>* converter) {
39// converter->RegisterIntField("foo", &Message::foo);
40// converter->RegisterStringField("bar", &Message::bar);
41// }
42//
43// Then, you just instantiate your JSONValueConverter of your type and call
44// Convert() method.
45// Message message;
46// JSONValueConverter<Message> converter;
47// converter.Convert(json, &message);
48//
49// Convert() returns false when it fails. Here "fail" means that the value is
50// structurally different from expected, such like a string value appears
51// for an int field. Do not report failures for missing fields.
52// Also note that Convert() will modify the passed |message| even when it
53// fails for performance reason.
54//
55// For nested field, the internal message also has to implement the registration
56// method. Then, just use RegisterNestedField() from the containing struct's
57// RegisterJSONConverter method.
58// struct Nested {
59// Message foo;
60// static void RegisterJSONConverter(...) {
61// ...
62// converter->RegisterNestedField("foo", &Nested::foo);
63// }
64// };
65//
66// For repeated field, we just assume std::vector<std::unique_ptr<ElementType>>
67// for its container and you can put RegisterRepeatedInt or some other types.
68// Use RegisterRepeatedMessage for nested repeated fields.
69//
70// Sometimes JSON format uses string representations for other types such
71// like enum, timestamp, or URL. You can use RegisterCustomField method
Brett Wilsonad9e4422019-09-07 13:33:06 -070072// and specify a function to convert a std::string_view to your type.
73// bool ConvertFunc(std::string_view s, YourEnum* result) {
Scott Graham66962112018-06-08 12:42:08 -070074// // do something and return true if succeed...
75// }
76// struct Message {
77// YourEnum ye;
78// ...
79// static void RegisterJSONConverter(...) {
80// ...
81// converter->RegsiterCustomField<YourEnum>(
82// "your_enum", &Message::ye, &ConvertFunc);
83// }
84// };
85
86namespace base {
87
88template <typename StructType>
89class JSONValueConverter;
90
91namespace internal {
92
Scott Graham98cd3ca2018-06-14 22:26:55 -070093template <typename StructType>
Scott Graham66962112018-06-08 12:42:08 -070094class FieldConverterBase {
95 public:
96 explicit FieldConverterBase(const std::string& path) : field_path_(path) {}
97 virtual ~FieldConverterBase() = default;
Scott Graham98cd3ca2018-06-14 22:26:55 -070098 virtual bool ConvertField(const base::Value& value,
99 StructType* obj) const = 0;
Scott Graham66962112018-06-08 12:42:08 -0700100 const std::string& field_path() const { return field_path_; }
101
102 private:
103 std::string field_path_;
104 DISALLOW_COPY_AND_ASSIGN(FieldConverterBase);
105};
106
107template <typename FieldType>
108class ValueConverter {
109 public:
110 virtual ~ValueConverter() = default;
111 virtual bool Convert(const base::Value& value, FieldType* field) const = 0;
112};
113
114template <typename StructType, typename FieldType>
115class FieldConverter : public FieldConverterBase<StructType> {
116 public:
117 explicit FieldConverter(const std::string& path,
Scott Graham98cd3ca2018-06-14 22:26:55 -0700118 FieldType StructType::*field,
Scott Graham66962112018-06-08 12:42:08 -0700119 ValueConverter<FieldType>* converter)
120 : FieldConverterBase<StructType>(path),
121 field_pointer_(field),
Scott Graham98cd3ca2018-06-14 22:26:55 -0700122 value_converter_(converter) {}
Scott Graham66962112018-06-08 12:42:08 -0700123
124 bool ConvertField(const base::Value& value, StructType* dst) const override {
125 return value_converter_->Convert(value, &(dst->*field_pointer_));
126 }
127
128 private:
Scott Graham98cd3ca2018-06-14 22:26:55 -0700129 FieldType StructType::*field_pointer_;
Scott Graham66962112018-06-08 12:42:08 -0700130 std::unique_ptr<ValueConverter<FieldType>> value_converter_;
131 DISALLOW_COPY_AND_ASSIGN(FieldConverter);
132};
133
134template <typename FieldType>
135class BasicValueConverter;
136
137template <>
Scott Graham44598072018-06-14 22:01:37 -0700138class BasicValueConverter<int> : public ValueConverter<int> {
Scott Graham66962112018-06-08 12:42:08 -0700139 public:
140 BasicValueConverter() = default;
141
142 bool Convert(const base::Value& value, int* field) const override;
143
144 private:
145 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
146};
147
148template <>
Scott Graham98cd3ca2018-06-14 22:26:55 -0700149class BasicValueConverter<std::string> : public ValueConverter<std::string> {
Scott Graham66962112018-06-08 12:42:08 -0700150 public:
151 BasicValueConverter() = default;
152
153 bool Convert(const base::Value& value, std::string* field) const override;
154
155 private:
156 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
157};
158
159template <>
Brett Wilsonad9e4422019-09-07 13:33:06 -0700160class BasicValueConverter<std::u16string>
161 : public ValueConverter<std::u16string> {
Scott Graham66962112018-06-08 12:42:08 -0700162 public:
163 BasicValueConverter() = default;
164
Brett Wilsonad9e4422019-09-07 13:33:06 -0700165 bool Convert(const base::Value& value, std::u16string* field) const override;
Scott Graham66962112018-06-08 12:42:08 -0700166
167 private:
168 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
169};
170
171template <>
Scott Graham44598072018-06-14 22:01:37 -0700172class BasicValueConverter<double> : public ValueConverter<double> {
Scott Graham66962112018-06-08 12:42:08 -0700173 public:
174 BasicValueConverter() = default;
175
176 bool Convert(const base::Value& value, double* field) const override;
177
178 private:
179 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
180};
181
182template <>
Scott Graham44598072018-06-14 22:01:37 -0700183class BasicValueConverter<bool> : public ValueConverter<bool> {
Scott Graham66962112018-06-08 12:42:08 -0700184 public:
185 BasicValueConverter() = default;
186
187 bool Convert(const base::Value& value, bool* field) const override;
188
189 private:
190 DISALLOW_COPY_AND_ASSIGN(BasicValueConverter);
191};
192
193template <typename FieldType>
194class ValueFieldConverter : public ValueConverter<FieldType> {
195 public:
Scott Graham98cd3ca2018-06-14 22:26:55 -0700196 typedef bool (*ConvertFunc)(const base::Value* value, FieldType* field);
Scott Graham66962112018-06-08 12:42:08 -0700197
198 explicit ValueFieldConverter(ConvertFunc convert_func)
199 : convert_func_(convert_func) {}
200
201 bool Convert(const base::Value& value, FieldType* field) const override {
202 return convert_func_(&value, field);
203 }
204
205 private:
206 ConvertFunc convert_func_;
207
208 DISALLOW_COPY_AND_ASSIGN(ValueFieldConverter);
209};
210
211template <typename FieldType>
212class CustomFieldConverter : public ValueConverter<FieldType> {
213 public:
Brett Wilsonad9e4422019-09-07 13:33:06 -0700214 typedef bool (*ConvertFunc)(std::string_view value, FieldType* field);
Scott Graham66962112018-06-08 12:42:08 -0700215
216 explicit CustomFieldConverter(ConvertFunc convert_func)
217 : convert_func_(convert_func) {}
218
219 bool Convert(const base::Value& value, FieldType* field) const override {
220 std::string string_value;
221 return value.GetAsString(&string_value) &&
Scott Graham98cd3ca2018-06-14 22:26:55 -0700222 convert_func_(string_value, field);
Scott Graham66962112018-06-08 12:42:08 -0700223 }
224
225 private:
226 ConvertFunc convert_func_;
227
228 DISALLOW_COPY_AND_ASSIGN(CustomFieldConverter);
229};
230
231template <typename NestedType>
232class NestedValueConverter : public ValueConverter<NestedType> {
233 public:
234 NestedValueConverter() = default;
235
236 bool Convert(const base::Value& value, NestedType* field) const override {
237 return converter_.Convert(value, field);
238 }
239
240 private:
241 JSONValueConverter<NestedType> converter_;
242 DISALLOW_COPY_AND_ASSIGN(NestedValueConverter);
243};
244
245template <typename Element>
246class RepeatedValueConverter
247 : public ValueConverter<std::vector<std::unique_ptr<Element>>> {
248 public:
249 RepeatedValueConverter() = default;
250
251 bool Convert(const base::Value& value,
252 std::vector<std::unique_ptr<Element>>* field) const override {
253 const base::ListValue* list = NULL;
254 if (!value.GetAsList(&list)) {
255 // The field is not a list.
256 return false;
257 }
258
259 field->reserve(list->GetSize());
260 for (size_t i = 0; i < list->GetSize(); ++i) {
261 const base::Value* element = NULL;
262 if (!list->Get(i, &element))
263 continue;
264
265 std::unique_ptr<Element> e(new Element);
266 if (basic_converter_.Convert(*element, e.get())) {
267 field->push_back(std::move(e));
268 } else {
Scott Graham66962112018-06-08 12:42:08 -0700269 return false;
270 }
271 }
272 return true;
273 }
274
275 private:
276 BasicValueConverter<Element> basic_converter_;
277 DISALLOW_COPY_AND_ASSIGN(RepeatedValueConverter);
278};
279
280template <typename NestedType>
281class RepeatedMessageConverter
282 : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> {
283 public:
284 RepeatedMessageConverter() = default;
285
286 bool Convert(const base::Value& value,
287 std::vector<std::unique_ptr<NestedType>>* field) const override {
288 const base::ListValue* list = NULL;
289 if (!value.GetAsList(&list))
290 return false;
291
292 field->reserve(list->GetSize());
293 for (size_t i = 0; i < list->GetSize(); ++i) {
294 const base::Value* element = NULL;
295 if (!list->Get(i, &element))
296 continue;
297
298 std::unique_ptr<NestedType> nested(new NestedType);
299 if (converter_.Convert(*element, nested.get())) {
300 field->push_back(std::move(nested));
301 } else {
Scott Graham66962112018-06-08 12:42:08 -0700302 return false;
303 }
304 }
305 return true;
306 }
307
308 private:
309 JSONValueConverter<NestedType> converter_;
310 DISALLOW_COPY_AND_ASSIGN(RepeatedMessageConverter);
311};
312
313template <typename NestedType>
314class RepeatedCustomValueConverter
315 : public ValueConverter<std::vector<std::unique_ptr<NestedType>>> {
316 public:
Scott Graham98cd3ca2018-06-14 22:26:55 -0700317 typedef bool (*ConvertFunc)(const base::Value* value, NestedType* field);
Scott Graham66962112018-06-08 12:42:08 -0700318
319 explicit RepeatedCustomValueConverter(ConvertFunc convert_func)
320 : convert_func_(convert_func) {}
321
322 bool Convert(const base::Value& value,
323 std::vector<std::unique_ptr<NestedType>>* field) const override {
324 const base::ListValue* list = NULL;
325 if (!value.GetAsList(&list))
326 return false;
327
328 field->reserve(list->GetSize());
329 for (size_t i = 0; i < list->GetSize(); ++i) {
330 const base::Value* element = NULL;
331 if (!list->Get(i, &element))
332 continue;
333
334 std::unique_ptr<NestedType> nested(new NestedType);
335 if ((*convert_func_)(element, nested.get())) {
336 field->push_back(std::move(nested));
337 } else {
Scott Graham66962112018-06-08 12:42:08 -0700338 return false;
339 }
340 }
341 return true;
342 }
343
344 private:
345 ConvertFunc convert_func_;
346 DISALLOW_COPY_AND_ASSIGN(RepeatedCustomValueConverter);
347};
348
Scott Graham66962112018-06-08 12:42:08 -0700349} // namespace internal
350
351template <class StructType>
352class JSONValueConverter {
353 public:
Scott Graham98cd3ca2018-06-14 22:26:55 -0700354 JSONValueConverter() { StructType::RegisterJSONConverter(this); }
Scott Graham66962112018-06-08 12:42:08 -0700355
Scott Graham98cd3ca2018-06-14 22:26:55 -0700356 void RegisterIntField(const std::string& field_name, int StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700357 fields_.push_back(
358 std::make_unique<internal::FieldConverter<StructType, int>>(
359 field_name, field, new internal::BasicValueConverter<int>));
360 }
361
362 void RegisterStringField(const std::string& field_name,
Scott Graham98cd3ca2018-06-14 22:26:55 -0700363 std::string StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700364 fields_.push_back(
365 std::make_unique<internal::FieldConverter<StructType, std::string>>(
366 field_name, field, new internal::BasicValueConverter<std::string>));
367 }
368
369 void RegisterStringField(const std::string& field_name,
Brett Wilsonad9e4422019-09-07 13:33:06 -0700370 std::u16string StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700371 fields_.push_back(
Brett Wilsonad9e4422019-09-07 13:33:06 -0700372 std::make_unique<internal::FieldConverter<StructType, std::u16string>>(
373 field_name, field,
374 new internal::BasicValueConverter<std::u16string>));
Scott Graham66962112018-06-08 12:42:08 -0700375 }
376
377 void RegisterBoolField(const std::string& field_name,
Scott Graham98cd3ca2018-06-14 22:26:55 -0700378 bool StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700379 fields_.push_back(
380 std::make_unique<internal::FieldConverter<StructType, bool>>(
381 field_name, field, new internal::BasicValueConverter<bool>));
382 }
383
384 void RegisterDoubleField(const std::string& field_name,
Scott Graham98cd3ca2018-06-14 22:26:55 -0700385 double StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700386 fields_.push_back(
387 std::make_unique<internal::FieldConverter<StructType, double>>(
388 field_name, field, new internal::BasicValueConverter<double>));
389 }
390
391 template <class NestedType>
Scott Graham98cd3ca2018-06-14 22:26:55 -0700392 void RegisterNestedField(const std::string& field_name,
393 NestedType StructType::*field) {
Scott Graham66962112018-06-08 12:42:08 -0700394 fields_.push_back(
395 std::make_unique<internal::FieldConverter<StructType, NestedType>>(
396 field_name, field, new internal::NestedValueConverter<NestedType>));
397 }
398
399 template <typename FieldType>
400 void RegisterCustomField(const std::string& field_name,
401 FieldType StructType::*field,
Brett Wilsonad9e4422019-09-07 13:33:06 -0700402 bool (*convert_func)(std::string_view, FieldType*)) {
Scott Graham66962112018-06-08 12:42:08 -0700403 fields_.push_back(
404 std::make_unique<internal::FieldConverter<StructType, FieldType>>(
405 field_name, field,
406 new internal::CustomFieldConverter<FieldType>(convert_func)));
407 }
408
409 template <typename FieldType>
Scott Graham98cd3ca2018-06-14 22:26:55 -0700410 void RegisterCustomValueField(const std::string& field_name,
411 FieldType StructType::*field,
412 bool (*convert_func)(const base::Value*,
413 FieldType*)) {
Scott Graham66962112018-06-08 12:42:08 -0700414 fields_.push_back(
415 std::make_unique<internal::FieldConverter<StructType, FieldType>>(
416 field_name, field,
417 new internal::ValueFieldConverter<FieldType>(convert_func)));
418 }
419
420 void RegisterRepeatedInt(
421 const std::string& field_name,
422 std::vector<std::unique_ptr<int>> StructType::*field) {
423 fields_.push_back(std::make_unique<internal::FieldConverter<
424 StructType, std::vector<std::unique_ptr<int>>>>(
425 field_name, field, new internal::RepeatedValueConverter<int>));
426 }
427
428 void RegisterRepeatedString(
429 const std::string& field_name,
430 std::vector<std::unique_ptr<std::string>> StructType::*field) {
431 fields_.push_back(
432 std::make_unique<internal::FieldConverter<
433 StructType, std::vector<std::unique_ptr<std::string>>>>(
434 field_name, field,
435 new internal::RepeatedValueConverter<std::string>));
436 }
437
438 void RegisterRepeatedString(
439 const std::string& field_name,
Brett Wilsonad9e4422019-09-07 13:33:06 -0700440 std::vector<std::unique_ptr<std::u16string>> StructType::*field) {
441 fields_.push_back(
442 std::make_unique<internal::FieldConverter<
443 StructType, std::vector<std::unique_ptr<std::u16string>>>>(
444 field_name, field,
445 new internal::RepeatedValueConverter<std::u16string>));
Scott Graham66962112018-06-08 12:42:08 -0700446 }
447
448 void RegisterRepeatedDouble(
449 const std::string& field_name,
450 std::vector<std::unique_ptr<double>> StructType::*field) {
451 fields_.push_back(std::make_unique<internal::FieldConverter<
452 StructType, std::vector<std::unique_ptr<double>>>>(
453 field_name, field, new internal::RepeatedValueConverter<double>));
454 }
455
456 void RegisterRepeatedBool(
457 const std::string& field_name,
458 std::vector<std::unique_ptr<bool>> StructType::*field) {
459 fields_.push_back(std::make_unique<internal::FieldConverter<
460 StructType, std::vector<std::unique_ptr<bool>>>>(
461 field_name, field, new internal::RepeatedValueConverter<bool>));
462 }
463
464 template <class NestedType>
465 void RegisterRepeatedCustomValue(
466 const std::string& field_name,
467 std::vector<std::unique_ptr<NestedType>> StructType::*field,
468 bool (*convert_func)(const base::Value*, NestedType*)) {
469 fields_.push_back(
470 std::make_unique<internal::FieldConverter<
471 StructType, std::vector<std::unique_ptr<NestedType>>>>(
472 field_name, field,
473 new internal::RepeatedCustomValueConverter<NestedType>(
474 convert_func)));
475 }
476
477 template <class NestedType>
478 void RegisterRepeatedMessage(
479 const std::string& field_name,
480 std::vector<std::unique_ptr<NestedType>> StructType::*field) {
481 fields_.push_back(
482 std::make_unique<internal::FieldConverter<
483 StructType, std::vector<std::unique_ptr<NestedType>>>>(
484 field_name, field,
485 new internal::RepeatedMessageConverter<NestedType>));
486 }
487
488 bool Convert(const base::Value& value, StructType* output) const {
489 const DictionaryValue* dictionary_value = NULL;
490 if (!value.GetAsDictionary(&dictionary_value))
491 return false;
492
493 for (size_t i = 0; i < fields_.size(); ++i) {
494 const internal::FieldConverterBase<StructType>* field_converter =
495 fields_[i].get();
496 const base::Value* field = NULL;
497 if (dictionary_value->Get(field_converter->field_path(), &field)) {
498 if (!field_converter->ConvertField(*field, output)) {
Scott Graham66962112018-06-08 12:42:08 -0700499 return false;
500 }
501 }
502 }
503 return true;
504 }
505
506 private:
507 std::vector<std::unique_ptr<internal::FieldConverterBase<StructType>>>
508 fields_;
509
510 DISALLOW_COPY_AND_ASSIGN(JSONValueConverter);
511};
512
513} // namespace base
514
515#endif // BASE_JSON_JSON_VALUE_CONVERTER_H_