BDE 4.39.x Production Release
Loading...
Searching...
No Matches
baljsn_jsonconverter.h
Go to the documentation of this file.
1/// @file baljsn_jsonconverter.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// baljsn_jsonconverter.h -*-C++-*-
8#ifndef INCLUDED_BALJSN_JSONCONVERTER
9#define INCLUDED_BALJSN_JSONCONVERTER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup baljsn_jsonconverter baljsn_jsonconverter
15/// @brief Provide conversions between JSON and `bdlat`-compatible types.
16/// @addtogroup bal
17/// @{
18/// @addtogroup baljsn
19/// @{
20/// @addtogroup baljsn_jsonconverter
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#baljsn_jsonconverter-purpose"> Purpose</a>
25/// * <a href="#baljsn_jsonconverter-classes"> Classes </a>
26/// * <a href="#baljsn_jsonconverter-description"> Description </a>
27/// * <a href="#baljsn_jsonconverter-type-mapping"> Type Mapping </a>
28/// * <a href="#baljsn_jsonconverter-usage"> Usage </a>
29/// * <a href="#baljsn_jsonconverter-example-1-encoding-a-bas_codegen-pl-generated-object-into-json"> Example 1: Encoding a bas_codegen.pl-generated object into JSON </a>
30///
31/// # Purpose {#baljsn_jsonconverter-purpose}
32/// Provide conversions between JSON and `bdlat`-compatible types.
33///
34/// # Classes {#baljsn_jsonconverter-classes}
35///
36/// - baljsn::JsonConverter: converts between JSON and `bdlat`-compliant types
37///
38/// @see baljsn_convertfromjsonoptions, baljsn_converttojsonoptions,
39/// baljsn_encoder, bsljsn_decoder
40///
41/// # Description {#baljsn_jsonconverter-description}
42/// This component provides a mechanism, baljsn::JsonConverter, to
43/// convert from a `bdlat`-compatible object (see @ref bdlat ) to a corresponding
44/// `bdljsn::Json` object, and also to convert back from a `bdljsn::Json` object
45/// to a `bdlat` object.
46///
47/// The conversion to a `bdljsn::Json` object produces the same result as
48/// encoding the `bdlat` object to a JSON document using `baljsn::Encoder` and
49/// then using `bdljsn::JsonUtil::read` to construct a `bdljsn::Json` object
50/// from that JSON document -- however, using `baljsn::JsonConverter` avoids the
51/// creation of that intermediate document. Conversely, a `bdljsn::Json` object
52/// could be printed as a JSON document (see `bdljsn::JsonUtil::write`) that is
53/// decoded into a `bdlat` object (see `baljsn::Decoder`) -- but
54/// `baljsn::JsonConverter` does so directly.
55///
56/// ## Type Mapping {#baljsn_jsonconverter-type-mapping}
57///
58///
59/// `bdlat` and JSON provide different type systems that are not entirely
60/// congruent. Notably, several `bdlat` values are converted to JSON strings:
61///
62/// * BDE date and time types are represented as JSON strings in ISO 8601
63/// format.
64///
65/// * Enumerations are converted to a JSON string formatted as their symbolic
66/// (programmatic) representation, not their numeric value.
67///
68/// * Floating point values for INF/-INF/Nan are converted to the strings
69/// "+inf"/"-inf"/"nan".
70///
71/// ## Usage {#baljsn_jsonconverter-usage}
72///
73///
74/// This section illustrates intended use of this component.
75///
76/// ## Example 1: Encoding a bas_codegen.pl-generated object into JSON {#baljsn_jsonconverter-example-1-encoding-a-bas_codegen-pl-generated-object-into-json}
77///
78///
79/// Consider that we want to exchange an employee's information between two
80/// processes. To allow this information exchange we will define the XML schema
81/// representation for that class, use `bas_codegen.pl` to create the `Employee`
82/// `class` for storing that information, populate an `Employee` object, and
83/// encode that object using the `baljsn` encoder.
84///
85/// First, we will define the XML schema inside a file called `employee.xsd`:
86/// @code
87/// <?xml version='1.0' encoding='UTF-8'?>
88/// <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
89/// xmlns:test='http://bloomberg.com/schemas/test'
90/// targetNamespace='http://bloomberg.com/schemas/test'
91/// elementFormDefault='unqualified'>
92///
93/// <xs:complexType name='Address'>
94/// <xs:sequence>
95/// <xs:element name='street' type='xs:string'/>
96/// <xs:element name='city' type='xs:string'/>
97/// <xs:element name='state' type='xs:string'/>
98/// </xs:sequence>
99/// </xs:complexType>
100///
101/// <xs:complexType name='Employee'>
102/// <xs:sequence>
103/// <xs:element name='name' type='xs:string'/>
104/// <xs:element name='homeAddress' type='test:Address'/>
105/// <xs:element name='age' type='xs:int'/>
106/// </xs:sequence>
107/// </xs:complexType>
108///
109/// <xs:element name='Employee' type='test:Employee'/>
110///
111/// </xs:schema>
112/// @endcode
113/// Then, we will use the `bas_codegen.pl` tool, to generate the C++ classes for
114/// this schema. The following command will generate the header and
115/// implementation files for the all the classes in the @ref test_messages
116/// components in the current directory:
117/// @code
118/// $ bas_codegen.pl -m msg -p test xsdfile.xsd
119/// @endcode
120/// Next, we will populate a `test::Employee` object:
121/// @code
122/// test::Employee employee;
123/// employee.name() = "Bob";
124/// employee.homeAddress().street() = "Lexington Ave";
125/// employee.homeAddress().city() = "New York City";
126/// employee.homeAddress().state() = "New York";
127/// employee.age() = 21;
128/// @endcode
129/// Then, we will create a `baljsn::JsonConverter` object:
130/// @code
131/// baljsn::JsonConverter converter;
132/// @endcode
133/// Now, we will create a `bdljsn::Json` object having elements that match the
134/// respective elements of `employee`.
135/// @code
136/// bdljsn::Json json;
137/// int rc = converter.convert(&json, employee);
138/// assert(0 == rc);
139/// assert("" == converter.loggedMessages());
140/// @endcode
141/// Next, we verify that the `json` object has the expected elements, each
142/// containing the expected value, and having the expected type.
143/// @code
144/// assert(employee.name() == json["name"].theString());
145/// assert(employee.homeAddress().street() == json["homeAddress"]["street"]
146/// .theString());
147/// assert(employee.homeAddress().city() == json["homeAddress"]["city"]
148/// .theString());
149/// assert(employee.homeAddress().state() == json["homeAddress"]["state"]
150/// .theString());
151/// int intValue; rc = json["age"]
152/// .theNumber().asInt(&intValue);
153/// assert(0 == rc);
154/// assert("" == converter.loggedMessages());
155/// assert(employee.age() == intValue);
156/// @endcode
157/// Finally, we verify that the `json` object can be converted back to an
158/// `Employee` object having the same value as the original:
159/// @code
160/// test::Employee employeeFromJson;
161/// rc = converter.convert(&employeeFromJson, json);
162/// assert(0 == rc);
163/// assert("" == converter.loggedMessages());
164/// assert(employee == employeeFromJson);
165/// @endcode
166/// @}
167/** @} */
168/** @} */
169
170/** @addtogroup bal
171 * @{
172 */
173/** @addtogroup baljsn
174 * @{
175 */
176/** @addtogroup baljsn_jsonconverter
177 * @{
178 */
179
180#include <balscm_version.h>
181
186#include <baljsn_jsonformatter.h>
188#include <baljsn_jsontokenizer.h>
189#include <baljsn_parserutil.h>
190
191#include <bdlde_base64decoder.h>
192
193#include <bdljsn_json.h>
194
195#include <bdlat_enumutil.h>
196#include <bdlat_typecategory.h>
197
198#include <bslma_aatypeutil.h>
199#include <bslma_allocatorutil.h>
200
201#include <bsla_fallthrough.h>
202
203#include <bsls_assert.h>
204
205#include <bsl_iosfwd.h>
206#include <bsl_sstream.h> // `bsl::ostringstream`
207#include <bsl_string.h> // `bsl::string`, `bslstl::StringRef`
208#include <bsl_vector.h>
209
210
211namespace baljsn {
212
213struct JsonConverter_ElementVisitor;
214
215 // ===================
216 // class JsonConverter
217 // ===================
218
219/// This class provides a mechanism for copying the constituent values of
220/// certain `bdlat`-compatible objects to `bdljsn::Json` objects, and vice
221/// versa. In each case, the resulting object is a different representation of
222/// the data in the original. This conversion is analogous to the encoding and
223/// decoding operations provided elsewhere in this package; however, the
224/// `convert` methods here avoid the creation of any textual representation of
225/// the data.
226///
227/// The `bdlat` objects must meet the requirements of a sequence, choice, or
228/// array as defined in @ref bdlat_sequencefunctions , @ref bdlat_choicefunctions , and
229/// @ref bdlat_arrayfunctions components, respectively.
230///
231/// See @ref baljsn_jsonconverter
233
234 // PRIVATE TYPES
235 typedef JsonTokenizer Tokenizer;
236
237 // DATA
238 bsl::ostringstream d_logStream; // stream used for logging
239 Tokenizer d_tokenizer; // mechanism to examine a `Json`
240 bsl::string d_elementName; // current element name
241 int d_maxDepth; // max decoding depth
242 int d_currentDepth; // current decoding depth
243 bool d_skipUnknownElements; // skip unknown elements flag
244
245 // FRIENDS
247
248 // PRIVATE MANIPULATORS
249
250 /// Log the latest tokenizer error to `d_logStream`. If the tokenizer did
251 /// not have an error, log the specified `alternateString`. Return a
252 /// reference to `d_logStream`.
253 bsl::ostream& logTokenizerError(const char *alternateString);
254
255 /// Skip the unknown element specified by `elementName` by discarding all
256 /// the data associated with it and advancing the parser to the next
257 /// element. Return 0 on success and a non-zero value otherwise.
258 int skipUnknownElement(const bsl::string_view& elementName);
259
260 /// Decode into the specified `value`, of a (template parameter) `TYPE`
261 /// corresponding to the specified `bdeat` `category`, the JSON data
262 /// currently referred to by the tokenizer owned by this object, using the
263 /// specified formatting `mode`. Return 0 on success and a non-zero value otherwise.
264 ///
265 /// \pre The behavior is undefined unless `value` corresponds to the
266 /// specified `bdeat` category and `mode` is a valid formatting mode as specified in `bdlat_FormattingMode`.
267 ///
268 /// \note Note that `ANY_CATEGORY` shall
269 /// be a tag-type defined in `bdlat_TypeCategory`.
270 template <class TYPE>
271 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::DynamicType );
272 template <class TYPE>
273 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Sequence );
274 template <class TYPE>
275 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Choice );
276 template <class TYPE>
277 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Enumeration );
278 template <class TYPE>
279 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::CustomizedType );
280 template <class TYPE>
281 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Simple );
282 template <class TYPE>
283 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Array );
284 template <class TYPE>
285 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::NullableValue );
286 int decodeImp(bsl::vector<char> *value,
287 int mode,
289 template <class TYPE, class ANY_CATEGORY>
290 int decodeImp(TYPE *value, ANY_CATEGORY category );
291
292 private:
293 // NOT IMPLEMENTED
294 JsonConverter(const JsonConverter&); // = delete;
295 JsonConverter& operator=(const JsonConverter&); // = delete
296
297 public:
298 // TYPES
299
301
302 // CREATORS
303
304 /// Create a `JsonConverter` object. Optionally specify an `allocator`
305 /// (e.g., the address of a `bslma::Allocator` object) to supply memory;
306 /// otherwise, the default allocator is used.
308 explicit JsonConverter(const allocator_type& allocator);
309
310 /// Destroy this object.
311 ~JsonConverter() = default;
312
313 // MANIPULATORS
314
315 /// Load into the specified `json` the specified `value` of (template
316 /// parameter) `TYPE` using the specified `options`. Return 0 on success,
317 /// and a non-zero value otherwise. An error is returned if `TYPE` is not
318 /// a top-level `Sequence`, `Choice`, or `Array`. The prior value of
319 /// `json` is reset.
320 template <class TYPE>
321 int convert(bdljsn::Json *json,
322 const TYPE& value,
323 const ConvertToJsonOptions& options = ConvertToJsonOptions());
324
325 /// Load to the specified `value` of (template parameter) `TYPE` the value
326 /// of the specified `json` using the specified `options`. Return 0 on
327 /// success and a non-zero value otherwise. An error is returned if `TYPE`
328 /// is not a top-level `Sequence`, `Choice`, or `Array`. The prior value of
329 /// `value` is reset.
330 template <class TYPE>
331 int convert(
332 TYPE *value,
333 const bdljsn::Json& json,
335
336 // ACCESSORS
337
338 /// Return a string containing any error, warning, or trace messages that
339 /// were logged during the last call to the `convert` method. The log is
340 /// reset each time `convert` is called.
342
343 // Aspects
344
345 /// Return the allocator used by this object to supply memory.
346 ///
347 /// \note Note that if no allocator was supplied at construction the default allocator in
348 /// effect at construction is used.
350};
351
352 // ===================================
353 // struct JsonConverter_ElementVisitor
354 // ===================================
355
356/// This `class` implements a visitor for decoding elements within a sequence,
357/// choice, or array type. This is a component-private class and should not be used outside of this component.
358///
359/// \note Note that the operators provided in this
360/// `class` match the function signatures required of visitors decoding into
361/// elements of compatible types.
362///
363/// See @ref baljsn_jsonconverter
365
366 // DATA
367 JsonConverter *d_decoder_p; // converter (held, not owned)
368 int d_mode; // formatting mode
369
370 // CREATORS
371
372 // Creators have been omitted to allow simple static initialization of this
373 // struct.
374
375 // MANIPULATORS
376
377 /// Decode into the specified `value` the data in the JSON format. Return
378 /// 0 on success and a non-zero value otherwise.
379 template <class TYPE>
380 int operator()(TYPE *value);
381
382 /// Decode into the specified `value` using the specified `info` the data
383 /// in the JSON format. Return 0 on success and a non-zero value
384 /// otherwise.
385 template <class TYPE, class INFO>
386 int operator()(TYPE *value, const INFO& info);
387};
388
389 // ===================================
390 // struct JsonConverter_DecodeImpProxy
391 // ===================================
392
393/// This class provides a functor that dispatches the appropriate `decodeImp` method for a `bdeat` Dynamic type.
394///
395/// \note Note that the operators provided in
396/// this `class` match the function signatures required of visitors decoding
397/// into compatible types.
398///
399/// See @ref baljsn_jsonconverter
401
402 // DATA
403 JsonConverter *d_decoder_p; // converter (held, not owned)
404 int d_mode; // formatting mode
405
406 // CREATORS
407
408 // Creators have been omitted to allow simple static initialization of this
409 // struct.
410
411 // MANIPULATORS
412 template <class TYPE>
413 int operator()(TYPE *, bslmf::Nil);
414
415 /// Dencode into the specified `value` of the specified `bdeat` `category`
416 /// from the data in the JSON format. Return 0 on success and a non-zero
417 /// value otherwise.
418 template <class TYPE, class ANY_CATEGORY>
419 int operator()(TYPE *object, ANY_CATEGORY category);
420};
421// ============================================================================
422// INLINE DEFINITIONS
423// ============================================================================
424
425 // -------------------
426 // class JsonConverter
427 // -------------------
428// PRIVATE MANIPULATORS
429
430template <class TYPE>
431inline
432int JsonConverter::decodeImp(TYPE *value,
433 int mode,
435{
436 JsonConverter_DecodeImpProxy proxy = {this, mode};
438}
439
440template <class TYPE>
441int JsonConverter::decodeImp(TYPE *value,
442 int mode,
444{
446 // This is an anonymous element. Do not read anything and instead
447 // decode into the corresponding sub-element.
448
450 *value,
451 d_elementName.data(),
452 static_cast<int>(d_elementName.length()))) {
453 JsonConverter_ElementVisitor visitor = {this, mode};
454
456 value,
457 visitor,
458 d_elementName.data(),
459 static_cast<int>(d_elementName.length()))) {
460 d_logStream << "Could not decode sequence, error decoding "
461 << "element or bad element name '"
462 << d_elementName << "' \n";
463 return -1; // RETURN
464 }
465 }
466 else {
467 if (d_skipUnknownElements) {
468 const int rc = skipUnknownElement(d_elementName);
469 if (rc) {
470 d_logStream << "Error reading unknown element '"
471 << d_elementName << "' or after it\n";
472 return -1; // RETURN
473 }
474 }
475 else {
476 d_logStream << "Unknown element '" << d_elementName
477 << "' found\n";
478 return -1; // RETURN
479 }
480 }
481 }
482 else {
483 if (++d_currentDepth > d_maxDepth) {
484 d_logStream << "Maximum allowed decoding depth reached: "
485 << d_currentDepth << "\n";
486 return -1; // RETURN
487 }
488
489 if (Tokenizer::e_START_OBJECT != d_tokenizer.tokenType()) {
490 d_logStream << "Could not decode sequence, missing starting '{'\n";
491 return -1; // RETURN
492 }
493
494 int rc = d_tokenizer.advanceToNextToken();
495 if (rc) {
496 d_logStream << "Could not decode sequence, ";
497 logTokenizerError("error") << " reading token after '{'\n";
498 return -1; // RETURN
499 }
500
501 while (Tokenizer::e_ELEMENT_NAME == d_tokenizer.tokenType()) {
502
503 bslstl::StringRef elementName;
504 rc = d_tokenizer.value(&elementName);
505 if (rc) {
506 d_logStream << "Error reading attribute name after '{'\n";
507 return -1; // RETURN
508 }
509
511 *value,
512 elementName.data(),
513 static_cast<int>(elementName.length()))) {
514 d_elementName = elementName;
515
516 rc = d_tokenizer.advanceToNextToken();
517 if (rc) {
518 logTokenizerError("Error")
519 << " reading value for"
520 << " attribute '" << d_elementName << "' \n";
521 return -1; // RETURN
522 }
523
524 JsonConverter_ElementVisitor visitor = {this, mode};
525
527 value,
528 visitor,
529 d_elementName.data(),
530 static_cast<int>(d_elementName.length()))) {
531 d_logStream << "Could not decode sequence, error decoding "
532 << "element or bad element name '"
533 << d_elementName << "' \n";
534 return -1; // RETURN
535 }
536 }
537 else {
538 if (d_skipUnknownElements) {
539 rc = skipUnknownElement(elementName);
540 if (rc) {
541 d_logStream << "Error reading unknown element '"
542 << elementName << "' or after it\n";
543 return -1; // RETURN
544 }
545 }
546 else {
547 d_logStream << "Unknown element '" << elementName
548 << "' found\n";
549 return -1; // RETURN
550 }
551 }
552
553 rc = d_tokenizer.advanceToNextToken();
554 if (rc) {
555 d_logStream << "Could not decode sequence, ";
556 logTokenizerError("error") << " reading token"
557 << " after value for attribute '"
558 << d_elementName << "' \n";
559 return -1; // RETURN
560 }
561 }
562
563 if (Tokenizer::e_END_OBJECT != d_tokenizer.tokenType()) {
564 d_logStream << "Could not decode sequence, "
565 << "missing terminator '}' or separator ','\n";
566 return -1; // RETURN
567 }
568
569 --d_currentDepth;
570 }
571 return 0;
572}
573
574template <class TYPE>
575int JsonConverter::decodeImp(TYPE *value,
576 int mode,
578{
580 // This is an anonymous element. Do not read anything and instead
581 // decode into the corresponding sub-element.
582
583 bslstl::StringRef selectionName;
584 selectionName.assign(d_elementName.begin(), d_elementName.end());
585
587 *value,
588 selectionName.data(),
589 static_cast<int>(selectionName.length()))) {
591 value,
592 selectionName.data(),
593 static_cast<int>(selectionName.length()))) {
594 d_logStream << "Could not decode choice, bad selection name '"
595 << selectionName << "' \n";
596 return -1; // RETURN
597 }
598
599 JsonConverter_ElementVisitor visitor = {this, mode};
600
602 visitor)) {
603 d_logStream << "Could not decode choice, selection "
604 << "was not decoded\n";
605 return -1; // RETURN
606 }
607 }
608 else {
609 if (d_skipUnknownElements) {
610 const int rc = skipUnknownElement(selectionName);
611 if (rc) {
612 d_logStream << "Error reading unknown element '"
613 << selectionName << "' or after that "
614 << "element\n";
615 return -1; // RETURN
616 }
617 }
618 else {
619 d_logStream << "Unknown element '" << selectionName
620 << "' found\n";
621 return -1; // RETURN
622 }
623 }
624 }
625 else {
626 if (++d_currentDepth > d_maxDepth) {
627 d_logStream << "Maximum allowed decoding depth reached: "
628 << d_currentDepth << "\n";
629 return -1; // RETURN
630 }
631
632 if (Tokenizer::e_START_OBJECT != d_tokenizer.tokenType()) {
633 d_logStream << "Could not decode choice, missing starting {\n";
634 return -1; // RETURN
635 }
636
637 int rc = d_tokenizer.advanceToNextToken();
638 if (rc) {
639 d_logStream << "Could not decode choice, ";
640 logTokenizerError("error") << " reading token after {\n";
641 return -1; // RETURN
642 }
643
644 if (Tokenizer::e_ELEMENT_NAME == d_tokenizer.tokenType()) {
645 bslstl::StringRef selectionName;
646 rc = d_tokenizer.value(&selectionName);
647 if (rc) {
648 d_logStream << "Error reading selection name after '{'\n";
649 return -1; // RETURN
650 }
651
653 *value,
654 selectionName.data(),
655 static_cast<int>(selectionName.length()))) {
657 value,
658 selectionName.data(),
659 static_cast<int>(selectionName.length()))) {
660 d_logStream << "Could not decode choice, bad selection "
661 << "name '" << selectionName << "' \n";
662 return -1; // RETURN
663 }
664
665 rc = d_tokenizer.advanceToNextToken();
666 if (rc) {
667 d_logStream << "Could not decode choice, ";
668 logTokenizerError("error") << " reading value \n";
669 return -1; // RETURN
670 }
671
672 JsonConverter_ElementVisitor visitor = {this, mode};
673
675 visitor)) {
676 d_logStream << "Could not decode choice, selection "
677 << "was not decoded\n";
678 return -1; // RETURN
679 }
680 }
681 else {
682 if (d_skipUnknownElements) {
683 rc = skipUnknownElement(selectionName);
684 if (rc) {
685 d_logStream << "Error reading unknown element '"
686 << selectionName << "' or after that "
687 << "element\n";
688 return -1; // RETURN
689 }
690 }
691 else {
692 d_logStream << "Unknown element '" << selectionName
693 << "' found\n";
694 return -1; // RETURN
695 }
696 }
697
698 rc = d_tokenizer.advanceToNextToken();
699
700 if (rc) {
701 d_logStream << "Could not decode choice, ";
702 logTokenizerError("error") << " reading token after value for"
703 " selection \n";
704
705 return -1; // RETURN
706 }
707 }
708
709 if (Tokenizer::e_END_OBJECT != d_tokenizer.tokenType()) {
710 d_logStream << "Could not decode choice, "
711 << "missing terminator '}'\n";
712 return -1; // RETURN
713 }
714
715 --d_currentDepth;
716 }
717 return 0;
718}
719
720template <class TYPE>
721int JsonConverter::decodeImp(TYPE *value,
722 int ,
724{
725 enum { k_MIN_ENUM_STRING_LENGTH = 2 };
726
727 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
728 d_logStream << "Enumeration element value was not found\n";
729 return -1; // RETURN
730 }
731
732 const bdljsn::Json *dataValue;
733 int rc = d_tokenizer.value(&dataValue);
734 if (rc) {
735 d_logStream << "Error reading enumeration value\n";
736 return -1; // RETURN
737 }
738
739 BSLS_ASSERT(dataValue);
740
741 if (dataValue->isString()) {
742
744 value,
745 dataValue->theString().data(),
746 static_cast<int>(dataValue->theString().size()));
747 if (0 == rc) {
748 return 0; // RETURN
749 } else {
750 d_logStream << "Could not decode Enum String, value not allowed \""
751 << dataValue << "\"\n";
752 return rc;
753 }
754 } else if (dataValue->isNumber()) {
755
756 // We also accept an unquoted integer (DRQS 166048981).
757 int intValue;
758 bsl::string_view data = dataValue->theNumber().value();
759 rc = ParserUtil::getValue(&intValue, data);
760 if (rc) {
761 d_logStream << "Error reading enumeration value\n";
762 return -1; // RETURN
763 }
764
766 if (0 == rc) {
767 return 0; // RETURN
768 } else {
769 d_logStream << "Could not decode int Enum, value " << intValue
770 << " not allowed\n";
771 return rc; // RETURN
772 }
773 }
774 return 666;
775}
776
777template <class TYPE>
778int JsonConverter::decodeImp(TYPE *value,
779 int ,
781{
782 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
783 d_logStream << "Customized element value was not found\n";
784 return -1; // RETURN
785 }
786
787 const bdljsn::Json *dataValue;
788 int rc = d_tokenizer.value(&dataValue);
789 if (rc) {
790 d_logStream << "Error reading customized type value\n";
791 return -1; // RETURN
792 }
793
794 typedef
796
797 BaseType valueBaseType;
798
800 && dataValue->isString()) { // per DRQS 166048981
801 bsl::string_view data(dataValue->theString());
802 rc = ParserUtil::getValue(&valueBaseType, data);
803 } else {
804 rc = JsonParserUtil::getValue(&valueBaseType, *dataValue);
805 }
806 if (rc) {
807 d_logStream << "Could not decode Enum Customized, "
808 << "value not allowed \"" << dataValue << "\"\n";
809 return -1; // RETURN
810 }
811
813 valueBaseType);
814 if (rc) {
815 d_logStream << "Could not convert base type to customized type, "
816 << "base value disallowed: \"";
817 bdlb::PrintMethods::print(d_logStream, valueBaseType, 0, -1);
818 d_logStream << "\"\n";
819 }
820 return rc;
821}
822
823template <class TYPE>
824int JsonConverter::decodeImp(TYPE *value,
825 int ,
827{
828 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
829 d_logStream << "Simple element value was not found\n";
830 return -1; // RETURN
831 }
832
833 const bdljsn::Json *dataValue;
834 int rc = d_tokenizer.value(&dataValue);
835 if (rc) {
836 d_logStream << "Error reading simple value\n";
837 return -1; // RETURN
838 }
839
841 && dataValue->isString()) { // per DRQS 166048981
842 bsl::string_view data(dataValue->theString());
843 rc = ParserUtil::getValue(value, data);
844 } else {
845 rc = JsonParserUtil::getValue(value, *dataValue);
846 }
847
848 return rc;
849}
850
851inline
852int JsonConverter::decodeImp(bsl::vector<char> *value,
853 int ,
855{
856 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
857 d_logStream << "Could not decode vector<char> "
858 << "expected as an element value\n";
859 return -1; // RETURN
860 }
861
862 const bdljsn::Json *dataValue;
863 int rc = d_tokenizer.value(&dataValue);
864
865 if (rc) {
866 d_logStream << "Error reading customized type element value\n";
867 return -1; // RETURN
868 }
869
870 {
871 BSLS_ASSERT_SAFE(dataValue->isString());
872
873 value->clear();
874
875 const bsl::string& base64String = dataValue->theString();
876
877 bdlde::Base64Decoder base64Decoder(true);
878 int length = static_cast<int>(base64String.length());
879
880 value->resize(static_cast<bsl::size_t>(
882
883 rc = base64Decoder.convert(value->begin(),
884 base64String.begin(),
885 base64String.end());
886
887 if (rc < 0) {
888 return rc; // RETURN
889 }
890
891 rc = base64Decoder.endConvert(value->begin() +
892 base64Decoder.outputLength());
893
894 if (rc < 0) {
895 return rc; // RETURN
896 }
897
898 value->resize(static_cast<bsl::size_t>(base64Decoder.outputLength()));
899 }
900
901 return rc;
902}
903
904template <class TYPE>
905int JsonConverter::decodeImp(TYPE *value,
906 int mode,
908{
909 if (Tokenizer::e_START_ARRAY != d_tokenizer.tokenType()) {
910 d_logStream << "Could not decode vector, missing start token: '['\n";
911 return -1; // RETURN
912 }
913
914 int rc = d_tokenizer.advanceToNextToken();
915 if (rc) {
916 logTokenizerError("Error") << " reading array.\n";
917 return rc; // RETURN
918 }
919
920 int i = 0;
921 while (Tokenizer::e_END_ARRAY != d_tokenizer.tokenType()) {
922
923 if (Tokenizer::e_ELEMENT_VALUE == d_tokenizer.tokenType()
924 || Tokenizer::e_START_OBJECT == d_tokenizer.tokenType()
925 || Tokenizer::e_START_ARRAY == d_tokenizer.tokenType()) {
926 ++i;
928
929 JsonConverter_ElementVisitor visitor = {this, mode};
930
932 visitor,
933 i - 1)) {
934 d_logStream << "Error adding element '" << i - 1 << "'\n";
935 return -1; // RETURN
936 }
937
938 rc = d_tokenizer.advanceToNextToken();
939 if (rc) {
940 logTokenizerError("Error") << " reading token after value of"
941 " element '" << i - 1 << "'\n";
942 return rc; // RETURN
943 }
944 }
945 else {
946 d_logStream << "Erroneous token found instead of array element\n";
947 return -1; // RETURN
948 }
949 }
950
951 if (Tokenizer::e_END_ARRAY != d_tokenizer.tokenType()) {
952 d_logStream << "Could not decode vector, missing end token: ']'\n";
953 return -1; // RETURN
954 }
955
956 return 0;
957}
958
959template <class TYPE>
960int JsonConverter::decodeImp(TYPE *value,
961 int mode,
963{
964 enum { k_NULL_VALUE_LENGTH = 4 };
965
966 if (Tokenizer::e_ELEMENT_VALUE == d_tokenizer.tokenType()) {
967 const bdljsn::Json *dataValue;
968 const int rc = d_tokenizer.value(&dataValue);
969 if (rc) {
970 return rc; // RETURN
971 }
972 BSLS_ASSERT_SAFE(dataValue);
973 if (dataValue->isNull()) {
974 return 0; // RETURN
975 }
976 }
977
979
980 JsonConverter_ElementVisitor visitor = {this, mode};
981 int rc = bdlat_NullableValueFunctions::manipulateValue(value, visitor);
982 return rc;
983}
984
985template <class TYPE, class ANY_CATEGORY>
986inline
987int JsonConverter::decodeImp(TYPE * , ANY_CATEGORY )
988{
989 BSLS_ASSERT_OPT(0 == "Unreachable");
990
991 return -1;
992}
993
994// CREATORS
995inline
997: d_logStream()
998{
999}
1000
1001inline
1003: d_logStream(bslma::AllocatorUtil::adapt(allocator))
1004{
1005}
1006
1007// MANIPULATORS
1008template <class TYPE>
1010 const TYPE& value,
1011 const ConvertToJsonOptions& options)
1012{
1013 BSLS_ASSERT(json);
1014
1015 d_logStream.clear();
1016 d_logStream.str("");
1017
1018 bdlat_TypeCategory::Value category =
1020
1021 switch (category) {
1025 } break;
1026 default: {
1027 d_logStream
1028 << "Encoded object must be a Sequence, Choice, or Array type."
1029 << bsl::endl;
1030 return -1; // RETURN
1031 } break;
1032 }
1033
1034 static const bool s_FIRST_MEMBER_FLAG = false;
1035
1036 EncoderOptions mOptions; const EncoderOptions& cOptions = mOptions;
1037 mOptions.setEncodeEmptyArrays (options.convertEmptyArrays());
1038 mOptions.setEncodeNullElements (options.convertNullElements());
1039 mOptions.setEncodeInfAndNaNAsStrings(true); // not the default
1040
1041 json->makeNull();
1042
1043 bool isValueEmpty;
1044 JsonFormatter formatter(json,
1046 d_logStream.get_allocator()));
1047
1049 &isValueEmpty,
1050 &formatter,
1051 &d_logStream,
1052 value,
1054 cOptions,
1055 s_FIRST_MEMBER_FLAG);
1056 return rc;
1057}
1058
1059template <class TYPE>
1061 const bdljsn::Json& json,
1062 const ConvertFromJsonOptions& options)
1063{
1064 BSLS_ASSERT(value);
1065
1066 d_logStream.clear();
1067 d_logStream.str("");
1068
1069 bdlat_TypeCategory::Value category =
1071
1072 switch (category) {
1076 } break;
1077 default: {
1078 d_logStream
1079 << "Target object must be a Sequence, Choice, or Array type."
1080 << bsl::endl;
1081 int rc = -1;
1082 return rc; // RETURN
1083 } break;
1084 }
1085
1086 d_currentDepth = 0;
1087 d_maxDepth = options.maxDepth();
1088 d_skipUnknownElements = options.skipUnknownElements();
1089
1090 d_tokenizer.reset(&json);
1091
1093 int rc = d_tokenizer.advanceToNextToken();
1094 if (rc) {
1095 logTokenizerError("Error") << " advancing to the first token.\n";
1096 return rc; // RETURN
1097 }
1098
1100
1101 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1102 rc = decodeImp(value, 0, TypeCategory());
1103
1104 return rc;
1105}
1106// ACCESSORS
1107inline
1109{
1110 return d_logStream.str();
1111}
1112
1113 // Aspects
1114
1115inline
1117{
1118 return bslma::AATypeUtil::getAllocatorFromSubobject<allocator_type>(
1119 d_logStream);
1120}
1121
1122 // -----------------------------------
1123 // struct JsonConverter_ElementVisitor
1124 // -----------------------------------
1125
1126template <class TYPE>
1127inline
1129{
1130 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1131 return d_decoder_p->decodeImp(value, d_mode, TypeCategory());
1132}
1133
1134template <class TYPE, class INFO>
1135inline
1136int JsonConverter_ElementVisitor::operator()(TYPE *value, const INFO& info)
1137{
1138 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1139 return d_decoder_p->decodeImp(value,
1140 info.formattingMode(),
1141 TypeCategory());
1142}
1143
1144 // -----------------------------------
1145 // struct JsonConverter_DecodeImpProxy
1146 // -----------------------------------
1147
1148// MANIPULATORS
1149template <class TYPE>
1150inline
1152{
1153 BSLS_ASSERT_OPT(0 == "Unreachable");
1154
1155 return -1;
1156}
1157
1158template <class TYPE, class ANY_CATEGORY>
1159inline
1161 ANY_CATEGORY category)
1162{
1163 return d_decoder_p->decodeImp(object, d_mode, category);
1164}
1165} // close package namespace
1166
1167#endif
1168
1169// ----------------------------------------------------------------------------
1170// Copyright 2025 Bloomberg Finance L.P.
1171//
1172// Licensed under the Apache License, Version 2.0 (the "License");
1173// you may not use this file except in compliance with the License.
1174// You may obtain a copy of the License at
1175//
1176// http://www.apache.org/licenses/LICENSE-2.0
1177//
1178// Unless required by applicable law or agreed to in writing, software
1179// distributed under the License is distributed on an "AS IS" BASIS,
1180// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1181// See the License for the specific language governing permissions and
1182// limitations under the License.
1183// ----------------------------- END-OF-FILE ----------------------------------
1184
1185/** @} */
1186/** @} */
1187/** @} */
Definition baljsn_convertfromjsonoptions.h:118
int maxDepth() const
Return the value of the maxDepth attribute of this object.
Definition baljsn_convertfromjsonoptions.h:278
bool skipUnknownElements() const
Return the value of the skipUnknownElements attribute of this object.
Definition baljsn_convertfromjsonoptions.h:284
Definition baljsn_converttojsonoptions.h:115
bool convertEmptyArrays() const
Return the value of the convertEmptyArrays attribute of this object.
Definition baljsn_converttojsonoptions.h:273
bool convertNullElements() const
Return the value of the convertNullElements attribute of this object.
Definition baljsn_converttojsonoptions.h:279
Definition baljsn_encoderoptions.h:290
void setEncodeEmptyArrays(bool value)
Definition baljsn_encoderoptions.h:837
void setEncodeNullElements(bool value)
Definition baljsn_encoderoptions.h:843
void setEncodeInfAndNaNAsStrings(bool value)
Definition baljsn_encoderoptions.h:849
Definition baljsn_jsonconverter.h:232
JsonConverter()
Definition baljsn_jsonconverter.h:996
bsl::string loggedMessages() const
Definition baljsn_jsonconverter.h:1108
~JsonConverter()=default
Destroy this object.
allocator_type get_allocator() const
Definition baljsn_jsonconverter.h:1116
int convert(bdljsn::Json *json, const TYPE &value, const ConvertToJsonOptions &options=ConvertToJsonOptions())
Definition baljsn_jsonconverter.h:1009
bsl::allocator allocator_type
Definition baljsn_jsonconverter.h:300
Definition baljsn_jsonformatter.h:361
Definition baljsn_jsontokenizer.h:357
@ e_END_OBJECT
Definition baljsn_jsontokenizer.h:367
@ e_START_ARRAY
Definition baljsn_jsontokenizer.h:368
@ e_END_ARRAY
Definition baljsn_jsontokenizer.h:369
@ e_BEGIN
Definition baljsn_jsontokenizer.h:364
@ e_START_OBJECT
Definition baljsn_jsontokenizer.h:366
@ e_ELEMENT_NAME
Definition baljsn_jsontokenizer.h:365
@ e_ELEMENT_VALUE
Definition baljsn_jsontokenizer.h:370
int reset(const bdljsn::Json *json)
TokenType tokenType() const
Return the type of the current token.
Definition baljsn_jsontokenizer.h:652
int value(bsl::string_view *data) const
Definition baljsn_jsontokenizer.h:660
Definition bdlde_base64decoder.h:417
static int maxDecodedLength(int inputLength)
Definition bdlde_base64decoder.h:685
const bsl::string & value() const
Return the textual representation of this JsonNumber.
Definition bdljsn_jsonnumber.h:1010
Definition bdljsn_json.h:1461
bool isNumber() const
Definition bdljsn_json.h:5076
bool isString() const
Definition bdljsn_json.h:5088
JsonNumber & theNumber()
Definition bdljsn_json.h:5112
bool isNull() const
Definition bdljsn_json.h:5070
void makeNull()
Definition bdljsn_json.h:4505
const bsl::string & theString() const
Definition bdljsn_json.h:5320
Definition bslma_bslallocator.h:588
Definition bslstl_stringview.h:471
Definition bslstl_string.h:1252
size_type length() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7301
size_type size() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7292
iterator end() BSLS_KEYWORD_NOEXCEPT
Return the past-the-end iterator for this modifiable string.
Definition bslstl_string.h:6065
CHAR_TYPE * data() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:7177
void swap(basic_string &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits const_iterator begin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:2792
iterator begin() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:2866
Definition bslstl_vector.h:1120
void swap(vector &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits void clear() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_vector.h:1938
void resize(size_type newSize)
Definition bslstl_vector.h:4189
Definition bslstl_stringref.h:374
const CHAR_TYPE * data() const
Definition bslstl_stringref.h:962
size_type length() const
Definition bslstl_stringref.h:984
void assign(const CHAR_TYPE *data, INT_TYPE length, typename bsl::enable_if< bsl::is_integral< INT_TYPE >::value, bslmf::Nil >::type=bslmf::Nil())
Definition bslstl_stringref.h:847
static int manipulateByCategory(TYPE *object, MANIPULATOR &manipulator)
Definition bdlat_typecategory.h:1414
#define BSLA_FALLTHROUGH
Definition bsla_fallthrough.h:188
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_ASSERT_SAFE(X)
Definition bsls_assert.h:1917
#define BSLS_ASSERT_OPT(X)
Definition bsls_assert.h:2045
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition baljsn_convertfromjsonoptions.h:112
int manipulateElement(TYPE *array, MANIPULATOR &manipulator, int index)
void resize(TYPE *array, int newSize)
bool hasSelection(const TYPE &object, const char *selectionName, int selectionNameLength)
int manipulateSelection(TYPE *object, MANIPULATOR &manipulator)
int makeSelection(TYPE *object, int selectionId)
int convertFromBaseType(TYPE *object, const BASE_TYPE &value)
int manipulateValue(TYPE *object, MANIPULATOR &manipulator)
void makeValue(TYPE *object)
int manipulateAttribute(TYPE *object, MANIPULATOR &manipulator, const char *attributeName, int attributeNameLength)
bool hasAttribute(const TYPE &object, const char *attributeName, int attributeNameLength)
bdlat_TypeCategory::Value select(const TYPE &object)
void reset(TYPE *object)
Reset the value of the specified object to its default value.
bsl::ostream & print(bsl::ostream &stream, const TYPE &object, int level=0, int spacesPerLevel=4)
Definition bdlb_printmethods.h:725
basic_ostringstream< char, char_traits< char >, allocator< char > > ostringstream
Definition bslstl_iosfwd.h:97
BSLS_KEYWORD_CONSTEXPR CONTAINER::value_type * data(CONTAINER &container)
Definition bslstl_iterator.h:1325
Definition baljsn_encoder_testtypes.h:76
static int encode(bsl::ostream *jsonStream, const TYPE &value, const EncoderOptions &options=EncoderOptions())
Definition baljsn_encodeimplutil.h:1237
Definition baljsn_jsonconverter.h:400
int operator()(TYPE *, bslmf::Nil)
Definition baljsn_jsonconverter.h:1151
int d_mode
Definition baljsn_jsonconverter.h:404
JsonConverter * d_decoder_p
Definition baljsn_jsonconverter.h:403
Definition baljsn_jsonconverter.h:364
JsonConverter * d_decoder_p
Definition baljsn_jsonconverter.h:367
int d_mode
Definition baljsn_jsonconverter.h:368
int operator()(TYPE *value)
Definition baljsn_jsonconverter.h:1128
static int getValue(bool *value, const bdljsn::Json &json)
Definition baljsn_jsonparserutil.h:238
static int getValue(bool *value, const bsl::string_view &data)
static int fromIntOrFallbackIfEnabled(TYPE *result, int number)
Definition bdlat_enumutil.h:333
static int fromStringOrFallbackIfEnabled(TYPE *result, const char *string, int stringLength)
Definition bdlat_enumutil.h:347
TYPE::BaseType Type
Definition bdlat_customizedtypefunctions.h:535
@ e_DEFAULT
Definition bdlat_formattingmode.h:114
@ e_UNTAGGED
Definition bdlat_formattingmode.h:122
Definition bdlat_typecategory.h:1037
Definition bdlat_typecategory.h:1038
Definition bdlat_typecategory.h:1039
Definition bdlat_typecategory.h:1036
Definition bdlat_typecategory.h:1040
Definition bdlat_typecategory.h:1041
Definition bdlat_typecategory.h:1042
Definition bdlat_typecategory.h:1043
Value
Definition bdlat_typecategory.h:1046
@ e_ARRAY_CATEGORY
Definition bdlat_typecategory.h:1048
@ e_CHOICE_CATEGORY
Definition bdlat_typecategory.h:1049
@ e_SEQUENCE_CATEGORY
Definition bdlat_typecategory.h:1053
Definition bslmf_isintegral.h:140
static bsl::enable_if<!IsDerivedFromBslAllocator< t_ALLOC >::value, t_ALLOC >::type adapt(const t_ALLOC &from)
Definition bslma_allocatorutil.h:871
Definition bslmf_nil.h:133