LLDB mainline
StructuredData.h
Go to the documentation of this file.
1//===-- StructuredData.h ----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLDB_UTILITY_STRUCTUREDDATA_H
10#define LLDB_UTILITY_STRUCTUREDDATA_H
11
12#include "llvm/ADT/STLExtras.h"
13#include "llvm/ADT/SmallVector.h"
14#include "llvm/ADT/StringMap.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Support/JSON.h"
17
19#include "lldb/Utility/Stream.h"
21
22#include <cassert>
23#include <cstddef>
24#include <cstdint>
25#include <functional>
26#include <map>
27#include <memory>
28#include <optional>
29#include <string>
30#include <type_traits>
31#include <utility>
32#include <variant>
33#include <vector>
34
35namespace lldb_private {
36class Status;
37}
38
39namespace lldb_private {
40
41/// \class StructuredData StructuredData.h "lldb/Utility/StructuredData.h"
42/// A class which can hold structured data
43///
44/// The StructuredData class is designed to hold the data from a JSON or plist
45/// style file -- a serialized data structure with dictionaries (maps,
46/// hashes), arrays, and concrete values like integers, floating point
47/// numbers, strings, booleans.
48///
49/// StructuredData does not presuppose any knowledge of the schema for the
50/// data it is holding; it can parse JSON data, for instance, and other parts
51/// of lldb can iterate through the parsed data set to find keys and values
52/// that may be present.
53
55 template <typename N> class Integer;
56
57public:
58 class Object;
59 class Array;
62 class Float;
63 class Boolean;
64 class String;
65 class Dictionary;
66 class Generic;
67
68 typedef std::shared_ptr<Object> ObjectSP;
69 typedef std::shared_ptr<Array> ArraySP;
70 typedef std::shared_ptr<UnsignedInteger> UnsignedIntegerSP;
71 typedef std::shared_ptr<SignedInteger> SignedIntegerSP;
72 typedef std::shared_ptr<Float> FloatSP;
73 typedef std::shared_ptr<Boolean> BooleanSP;
74 typedef std::shared_ptr<String> StringSP;
75 typedef std::shared_ptr<Dictionary> DictionarySP;
76 typedef std::shared_ptr<Generic> GenericSP;
77
78 typedef std::variant<UnsignedIntegerSP, SignedIntegerSP> IntegerSP;
79
80 class Object : public std::enable_shared_from_this<Object> {
81 public:
84
85 virtual ~Object() = default;
86
87 virtual bool IsValid() const { return true; }
88
90
92
94
97 ? static_cast<Array *>(this)
98 : nullptr);
99 }
100
103 ? static_cast<Dictionary *>(this)
104 : nullptr);
105 }
106
108 // NOTE: For backward compatibility, eStructuredDataTypeInteger is
109 // the same as eStructuredDataTypeUnsignedInteger.
112 ? static_cast<UnsignedInteger *>(this)
113 : nullptr);
114 }
115
118 ? static_cast<SignedInteger *>(this)
119 : nullptr);
120 }
121
122 uint64_t GetUnsignedIntegerValue(uint64_t fail_value = 0) {
124 return ((integer != nullptr) ? integer->GetValue() : fail_value);
125 }
126
127 int64_t GetSignedIntegerValue(int64_t fail_value = 0) {
129 return ((integer != nullptr) ? integer->GetValue() : fail_value);
130 }
131
134 ? static_cast<Float *>(this)
135 : nullptr);
136 }
137
138 double GetFloatValue(double fail_value = 0.0) {
139 Float *f = GetAsFloat();
140 return ((f != nullptr) ? f->GetValue() : fail_value);
141 }
142
145 ? static_cast<Boolean *>(this)
146 : nullptr);
147 }
148
149 bool GetBooleanValue(bool fail_value = false) {
150 Boolean *b = GetAsBoolean();
151 return ((b != nullptr) ? b->GetValue() : fail_value);
152 }
153
156 ? static_cast<String *>(this)
157 : nullptr);
158 }
159
160 llvm::StringRef GetStringValue(const char *fail_value = nullptr) {
161 String *s = GetAsString();
162 if (s)
163 return s->GetValue();
164
165 return fail_value;
166 }
167
170 ? static_cast<Generic *>(this)
171 : nullptr);
172 }
173
174 ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path);
175
176 void DumpToStdout(bool pretty_print = true) const;
177
178 virtual void Serialize(llvm::json::OStream &s) const = 0;
179
180 void Dump(lldb_private::Stream &s, bool pretty_print = true) const {
181 llvm::json::OStream jso(s.AsRawOstream(), pretty_print ? 2 : 0);
182 Serialize(jso);
183 }
184
185 virtual void GetDescription(lldb_private::Stream &s) const {
186 s.IndentMore();
187 Dump(s, false);
188 s.IndentLess();
189 }
190
191 private:
193 };
194
195 class Array : public Object {
196 public:
197 Array() : Object(lldb::eStructuredDataTypeArray) {}
198
199 ~Array() override = default;
200
201 bool
202 ForEach(std::function<bool(Object *object)> const &foreach_callback) const {
203 for (const auto &object_sp : m_items) {
204 if (!foreach_callback(object_sp.get()))
205 return false;
206 }
207 return true;
208 }
209
210 size_t GetSize() const { return m_items.size(); }
211
212 ObjectSP operator[](size_t idx) {
213 if (idx < m_items.size())
214 return m_items[idx];
215 return ObjectSP();
216 }
217
218 ObjectSP GetItemAtIndex(size_t idx) const {
219 assert(idx < GetSize());
220 if (idx < m_items.size())
221 return m_items[idx];
222 return ObjectSP();
223 }
224
225 template <class IntType>
226 std::optional<IntType> GetItemAtIndexAsInteger(size_t idx) const {
227 if (auto item_sp = GetItemAtIndex(idx)) {
228 if constexpr (std::numeric_limits<IntType>::is_signed) {
229 if (auto *signed_value = item_sp->GetAsSignedInteger())
230 return static_cast<IntType>(signed_value->GetValue());
231 } else {
232 if (auto *unsigned_value = item_sp->GetAsUnsignedInteger())
233 return static_cast<IntType>(unsigned_value->GetValue());
234 }
235 }
236 return {};
237 }
238
239 std::optional<llvm::StringRef> GetItemAtIndexAsString(size_t idx) const {
240 if (auto item_sp = GetItemAtIndex(idx)) {
241 if (auto *string_value = item_sp->GetAsString())
242 return string_value->GetValue();
243 }
244 return {};
245 }
246
247 /// Retrieves the element at index \a idx from a StructuredData::Array if it
248 /// is a Dictionary.
249 ///
250 /// \param[in] idx
251 /// The index of the element to retrieve.
252 ///
253 /// \return
254 /// If the element at index \a idx is a Dictionary, this method returns a
255 /// valid pointer to the Dictionary wrapped in a std::optional. If the
256 /// element is not a Dictionary or the index is invalid, this returns
257 /// std::nullopt. Note that the underlying Dictionary pointer is never
258 /// nullptr.
259 std::optional<Dictionary *> GetItemAtIndexAsDictionary(size_t idx) const {
260 if (auto item_sp = GetItemAtIndex(idx)) {
261 if (auto *dict = item_sp->GetAsDictionary())
262 return dict;
263 }
264 return {};
265 }
266
267 void Push(const ObjectSP &item) { m_items.push_back(item); }
268
269 void AddItem(const ObjectSP &item) { m_items.push_back(item); }
270
271 template <typename T> void AddIntegerItem(T value) {
272 static_assert(std::is_integral<T>::value ||
273 std::is_floating_point<T>::value,
274 "value type should be integral");
275 if constexpr (std::numeric_limits<T>::is_signed)
276 AddItem(std::make_shared<SignedInteger>(value));
277 else
278 AddItem(std::make_shared<UnsignedInteger>(value));
279 }
280
281 void AddFloatItem(double value) { AddItem(std::make_shared<Float>(value)); }
282
283 void AddStringItem(llvm::StringRef value) {
284 AddItem(std::make_shared<String>(std::move(value)));
285 }
286
287 void AddBooleanItem(bool value) {
288 AddItem(std::make_shared<Boolean>(value));
289 }
290
291 void Serialize(llvm::json::OStream &s) const override;
292
293 void GetDescription(lldb_private::Stream &s) const override;
294
295 protected:
296 typedef std::vector<ObjectSP> collection;
298 };
299
300private:
301 template <typename N> class Integer : public Object {
302 static_assert(std::is_integral<N>::value, "N must be an integral type");
303
304 public:
305 Integer(N i = 0)
306 : Object(std::numeric_limits<N>::is_signed
307 ? lldb::eStructuredDataTypeSignedInteger
308 : lldb::eStructuredDataTypeUnsignedInteger),
309 m_value(i) {}
310 ~Integer() override = default;
311
312 void SetValue(N value) { m_value = value; }
313
314 N GetValue() { return m_value; }
315
316 void Serialize(llvm::json::OStream &s) const override {
317 s.value(static_cast<N>(m_value));
318 }
319
320 void GetDescription(lldb_private::Stream &s) const override {
321 s.Printf(std::numeric_limits<N>::is_signed ? "%" PRId64 : "%" PRIu64,
322 static_cast<N>(m_value));
323 }
324
325 protected:
327 };
328
329public:
330 class Float : public Object {
331 public:
332 Float(double d = 0.0)
333 : Object(lldb::eStructuredDataTypeFloat), m_value(d) {}
334
335 ~Float() override = default;
336
337 void SetValue(double value) { m_value = value; }
338
339 double GetValue() { return m_value; }
340
341 void Serialize(llvm::json::OStream &s) const override;
342
343 void GetDescription(lldb_private::Stream &s) const override;
344
345 protected:
346 double m_value;
347 };
348
349 class Boolean : public Object {
350 public:
351 Boolean(bool b = false)
352 : Object(lldb::eStructuredDataTypeBoolean), m_value(b) {}
353
354 ~Boolean() override = default;
355
356 void SetValue(bool value) { m_value = value; }
357
358 bool GetValue() { return m_value; }
359
360 void Serialize(llvm::json::OStream &s) const override;
361
362 void GetDescription(lldb_private::Stream &s) const override;
363
364 protected:
366 };
367
368 class String : public Object {
369 public:
370 String() : Object(lldb::eStructuredDataTypeString) {}
371 explicit String(llvm::StringRef S)
372 : Object(lldb::eStructuredDataTypeString), m_value(S) {}
373
374 void SetValue(llvm::StringRef S) { m_value = std::string(S); }
375
376 llvm::StringRef GetValue() { return m_value; }
377
378 void Serialize(llvm::json::OStream &s) const override;
379
380 void GetDescription(lldb_private::Stream &s) const override;
381
382 protected:
383 std::string m_value;
384 };
385
386 class Dictionary : public Object {
387 public:
388 Dictionary() : Object(lldb::eStructuredDataTypeDictionary) {}
389
390 Dictionary(ObjectSP obj_sp) : Object(lldb::eStructuredDataTypeDictionary) {
391 if (!obj_sp || obj_sp->GetType() != lldb::eStructuredDataTypeDictionary) {
392 SetType(lldb::eStructuredDataTypeInvalid);
393 return;
394 }
395
396 Dictionary *dict = obj_sp->GetAsDictionary();
397 m_dict = dict->m_dict;
398 }
399
400 ~Dictionary() override = default;
401
402 size_t GetSize() const { return m_dict.size(); }
403
404 void ForEach(std::function<bool(llvm::StringRef key, Object *object)> const
405 &callback) const {
406 for (const auto &pair : m_dict) {
407 if (!callback(pair.first(), pair.second.get()))
408 break;
409 }
410 }
411
412 /// Like ForEach, but visits the entries in key order, for stable output.
413 void
414 ForEachSorted(std::function<bool(llvm::StringRef key, Object *object)> const
415 &callback) const {
416 llvm::SmallVector<llvm::StringRef> keys;
417 keys.reserve(m_dict.size());
418 for (const auto &pair : m_dict)
419 keys.push_back(pair.first());
420 llvm::sort(keys);
421 for (llvm::StringRef key : keys) {
422 if (!callback(key, m_dict.lookup(key).get()))
423 break;
424 }
425 }
426
427 ArraySP GetKeys() const {
428 auto array_sp = std::make_shared<Array>();
429 for (auto iter = m_dict.begin(); iter != m_dict.end(); ++iter) {
430 auto key_object_sp = std::make_shared<String>(iter->first());
431 array_sp->Push(key_object_sp);
432 }
433 return array_sp;
434 }
435
436 ObjectSP GetValueForKey(llvm::StringRef key) const {
437 return m_dict.lookup(key);
438 }
439
440 bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const {
441 bool success = false;
442 ObjectSP value_sp = GetValueForKey(key);
443 if (value_sp.get()) {
444 Boolean *result_ptr = value_sp->GetAsBoolean();
445 if (result_ptr) {
446 result = result_ptr->GetValue();
447 success = true;
448 }
449 }
450 return success;
451 }
452
453 template <class IntType>
454 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const {
455 ObjectSP value_sp = GetValueForKey(key);
456 if (value_sp) {
457 if constexpr (std::numeric_limits<IntType>::is_signed) {
458 if (auto signed_value = value_sp->GetAsSignedInteger()) {
459 result = static_cast<IntType>(signed_value->GetValue());
460 return true;
461 }
462 } else {
463 if (auto unsigned_value = value_sp->GetAsUnsignedInteger()) {
464 result = static_cast<IntType>(unsigned_value->GetValue());
465 return true;
466 }
467 }
468 }
469 return false;
470 }
471
472 template <class IntType>
473 bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result,
474 IntType default_val) const {
475 bool success = GetValueForKeyAsInteger<IntType>(key, result);
476 if (!success)
477 result = default_val;
478 return success;
479 }
480
481 bool GetValueForKeyAsString(llvm::StringRef key,
482 llvm::StringRef &result) const {
483 ObjectSP value_sp = GetValueForKey(key);
484 if (value_sp.get()) {
485 if (auto string_value = value_sp->GetAsString()) {
486 result = string_value->GetValue();
487 return true;
488 }
489 }
490 return false;
491 }
492
493 bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result,
494 const char *default_val) const {
495 bool success = GetValueForKeyAsString(key, result);
496 if (!success) {
497 if (default_val)
498 result = default_val;
499 else
500 result = llvm::StringRef();
501 }
502 return success;
503 }
504
505 bool GetValueForKeyAsDictionary(llvm::StringRef key,
506 Dictionary *&result) const {
507 result = nullptr;
508 ObjectSP value_sp = GetValueForKey(key);
509 if (value_sp.get()) {
510 result = value_sp->GetAsDictionary();
511 return (result != nullptr);
512 }
513 return false;
514 }
515
516 bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const {
517 result = nullptr;
518 ObjectSP value_sp = GetValueForKey(key);
519 if (value_sp.get()) {
520 result = value_sp->GetAsArray();
521 return (result != nullptr);
522 }
523 return false;
524 }
525
526 bool HasKey(llvm::StringRef key) const { return m_dict.contains(key); }
527
528 void AddItem(llvm::StringRef key, ObjectSP value_sp) {
529 m_dict.insert_or_assign(key, std::move(value_sp));
530 }
531
532 template <typename T> void AddIntegerItem(llvm::StringRef key, T value) {
533 static_assert(std::is_integral<T>::value ||
534 std::is_floating_point<T>::value,
535 "value type should be integral");
536 if constexpr (std::numeric_limits<T>::is_signed)
537 AddItem(key, std::make_shared<SignedInteger>(value));
538 else
539 AddItem(key, std::make_shared<UnsignedInteger>(value));
540 }
541
542 void AddFloatItem(llvm::StringRef key, double value) {
543 AddItem(key, std::make_shared<Float>(value));
544 }
545
546 void AddStringItem(llvm::StringRef key, llvm::StringRef value) {
547 AddItem(key, std::make_shared<String>(std::move(value)));
548 }
549
550 void AddBooleanItem(llvm::StringRef key, bool value) {
551 AddItem(key, std::make_shared<Boolean>(value));
552 }
553
554 void Serialize(llvm::json::OStream &s) const override;
555
556 void GetDescription(lldb_private::Stream &s) const override;
557
558 protected:
559 llvm::StringMap<ObjectSP> m_dict;
560 };
561
562 class Null : public Object {
563 public:
564 Null() : Object(lldb::eStructuredDataTypeNull) {}
565
566 ~Null() override = default;
567
568 bool IsValid() const override { return false; }
569
570 void Serialize(llvm::json::OStream &s) const override;
571
572 void GetDescription(lldb_private::Stream &s) const override;
573 };
574
575 class Generic : public Object {
576 public:
577 explicit Generic(void *object = nullptr)
578 : Object(lldb::eStructuredDataTypeGeneric), m_object(object) {}
579
580 void SetValue(void *value) { m_object = value; }
581
582 void *GetValue() const { return m_object; }
583
584 bool IsValid() const override { return m_object != nullptr; }
585
586 void Serialize(llvm::json::OStream &s) const override;
587
588 void GetDescription(lldb_private::Stream &s) const override;
589
590 private:
591 void *m_object;
592 };
593
594 template <typename T> static ObjectSP FromInteger(T value) {
595 return std::make_shared<Integer<T>>(value);
596 }
597
598 static StructuredData::ObjectSP FromFloat(double value) {
599 return std::make_shared<StructuredData::Float>(value);
600 }
602 return std::make_shared<StructuredData::Boolean>(value);
603 }
604 static StructuredData::ObjectSP FromString(llvm::StringRef value) {
605 return std::make_shared<StructuredData::String>(value);
606 }
608 return std::make_shared<StructuredData::Generic>(value);
609 }
610
612 FromKeyValue(llvm::StringRef key, const StructuredData::ObjectSP &value_sp) {
613 auto dict_sp = std::make_shared<StructuredData::Dictionary>();
614 dict_sp->AddItem(key, value_sp);
615 return dict_sp;
616 }
617
618 static ObjectSP ParseJSON(llvm::StringRef json_text);
619 static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
620 static bool IsRecordType(const ObjectSP object_sp);
621};
622
623} // namespace lldb_private
624
625#endif // LLDB_UTILITY_STRUCTUREDDATA_H
static llvm::raw_ostream & error(Stream &strm)
#define integer
A file utility class.
Definition FileSpec.h:56
An error handling class.
Definition Status.h:118
A stream class that can stream formatted output to a file.
Definition Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition Stream.cpp:204
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition Stream.cpp:201
void AddItem(const ObjectSP &item)
void Serialize(llvm::json::OStream &s) const override
ObjectSP GetItemAtIndex(size_t idx) const
void AddStringItem(llvm::StringRef value)
std::vector< ObjectSP > collection
void GetDescription(lldb_private::Stream &s) const override
std::optional< IntType > GetItemAtIndexAsInteger(size_t idx) const
bool ForEach(std::function< bool(Object *object)> const &foreach_callback) const
void Push(const ObjectSP &item)
std::optional< Dictionary * > GetItemAtIndexAsDictionary(size_t idx) const
Retrieves the element at index idx from a StructuredData::Array if it is a Dictionary.
std::optional< llvm::StringRef > GetItemAtIndexAsString(size_t idx) const
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void AddBooleanItem(llvm::StringRef key, bool value)
void Serialize(llvm::json::OStream &s) const override
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result) const
void ForEachSorted(std::function< bool(llvm::StringRef key, Object *object)> const &callback) const
Like ForEach, but visits the entries in key order, for stable output.
bool GetValueForKeyAsBoolean(llvm::StringRef key, bool &result) const
void AddFloatItem(llvm::StringRef key, double value)
bool GetValueForKeyAsInteger(llvm::StringRef key, IntType &result, IntType default_val) const
void AddIntegerItem(llvm::StringRef key, T value)
ObjectSP GetValueForKey(llvm::StringRef key) const
void AddStringItem(llvm::StringRef key, llvm::StringRef value)
void GetDescription(lldb_private::Stream &s) const override
bool HasKey(llvm::StringRef key) const
void AddItem(llvm::StringRef key, ObjectSP value_sp)
bool GetValueForKeyAsArray(llvm::StringRef key, Array *&result) const
void ForEach(std::function< bool(llvm::StringRef key, Object *object)> const &callback) const
bool GetValueForKeyAsString(llvm::StringRef key, llvm::StringRef &result, const char *default_val) const
bool GetValueForKeyAsDictionary(llvm::StringRef key, Dictionary *&result) const
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
virtual void Serialize(llvm::json::OStream &s) const =0
llvm::StringRef GetStringValue(const char *fail_value=nullptr)
void DumpToStdout(bool pretty_print=true) const
virtual void GetDescription(lldb_private::Stream &s) const
double GetFloatValue(double fail_value=0.0)
Object(lldb::StructuredDataType t=lldb::eStructuredDataTypeInvalid)
int64_t GetSignedIntegerValue(int64_t fail_value=0)
bool GetBooleanValue(bool fail_value=false)
void SetType(lldb::StructuredDataType t)
void Dump(lldb_private::Stream &s, bool pretty_print=true) const
lldb::StructuredDataType GetType() const
uint64_t GetUnsignedIntegerValue(uint64_t fail_value=0)
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path)
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
A class which can hold structured data.
static StructuredData::ObjectSP FromFloat(double value)
static bool IsRecordType(const ObjectSP object_sp)
static StructuredData::ObjectSP FromString(llvm::StringRef value)
std::shared_ptr< Generic > GenericSP
std::shared_ptr< UnsignedInteger > UnsignedIntegerSP
std::shared_ptr< Float > FloatSP
static ObjectSP FromInteger(T value)
std::shared_ptr< Dictionary > DictionarySP
std::shared_ptr< Object > ObjectSP
Integer< int64_t > SignedInteger
static StructuredData::ObjectSP FromKeyValue(llvm::StringRef key, const StructuredData::ObjectSP &value_sp)
static ObjectSP ParseJSON(llvm::StringRef json_text)
std::shared_ptr< String > StringSP
static StructuredData::ObjectSP FromBoolean(bool value)
std::shared_ptr< Array > ArraySP
std::shared_ptr< Boolean > BooleanSP
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error)
std::shared_ptr< SignedInteger > SignedIntegerSP
static StructuredData::ObjectSP FromGeneric(void *value)
std::variant< UnsignedIntegerSP, SignedIntegerSP > IntegerSP
Integer< uint64_t > UnsignedInteger
A class that represents a running process on the host machine.
@ eStructuredDataTypeFloat
@ eStructuredDataTypeDictionary
@ eStructuredDataTypeInvalid
@ eStructuredDataTypeInteger
@ eStructuredDataTypeGeneric
@ eStructuredDataTypeArray
@ eStructuredDataTypeSignedInteger
@ eStructuredDataTypeUnsignedInteger
@ eStructuredDataTypeBoolean
@ eStructuredDataTypeString