Skip to content

Commit c06e058

Browse files
dyackzandsobek
authored andcommitted
Add type & value fields to primitive json types (#5)
This aligns with how custom types are represented by the JsonExporter. * Update both toJson & fromJson functions in the JsonExporter * Add & update tests Co-authored by: David Sobek <[email protected]>
1 parent 50fab69 commit c06e058

File tree

2 files changed

+70
-31
lines changed

2 files changed

+70
-31
lines changed

src/json_export.cpp

+44-26
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#include "behaviortree_cpp/json_export.h"
22

3+
namespace
4+
{
5+
constexpr std::string_view kTypeField = "__type";
6+
constexpr std::string_view kValueField = "value";
7+
} // namespace
8+
39
namespace BT
410
{
511

@@ -16,19 +22,23 @@ bool JsonExporter::toJson(const Any& any, nlohmann::json& dst) const
1622

1723
if(any.isString())
1824
{
19-
dst = any.cast<std::string>();
25+
dst[kTypeField] = "string";
26+
dst[kValueField] = any.cast<std::string>();
2027
}
2128
else if(type == typeid(int64_t))
2229
{
23-
dst = any.cast<int64_t>();
30+
dst[kTypeField] = "int64_t";
31+
dst[kValueField] = any.cast<int64_t>();
2432
}
2533
else if(type == typeid(uint64_t))
2634
{
27-
dst = any.cast<uint64_t>();
35+
dst[kTypeField] = "uint64_t";
36+
dst[kValueField] = any.cast<uint64_t>();
2837
}
2938
else if(type == typeid(double))
3039
{
31-
dst = any.cast<double>();
40+
dst[kTypeField] = "double";
41+
dst[kValueField] = any.cast<double>();
3242
}
3343
else
3444
{
@@ -51,33 +61,41 @@ JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json& source)
5161
{
5262
return nonstd::make_unexpected("json object is null");
5363
}
54-
if(source.is_string())
55-
{
56-
return Entry{ BT::Any(source.get<std::string>()),
57-
BT::TypeInfo::Create<std::string>() };
58-
}
59-
if(source.is_number_unsigned())
60-
{
61-
return Entry{ BT::Any(source.get<uint64_t>()), BT::TypeInfo::Create<uint64_t>() };
62-
}
63-
if(source.is_number_integer())
64+
if(!source.contains(kTypeField))
6465
{
65-
return Entry{ BT::Any(source.get<int64_t>()), BT::TypeInfo::Create<int64_t>() };
66-
}
67-
if(source.is_number_float())
68-
{
69-
return Entry{ BT::Any(source.get<double>()), BT::TypeInfo::Create<double>() };
70-
}
71-
if(source.is_boolean())
72-
{
73-
return Entry{ BT::Any(source.get<bool>()), BT::TypeInfo::Create<bool>() };
66+
return nonstd::make_unexpected("Missing field '" + std::string(kTypeField) + "'.");
7467
}
7568

76-
if(!source.contains("__type"))
69+
const auto source_value_it = source.find(kValueField);
70+
if(source_value_it != source.end())
7771
{
78-
return nonstd::make_unexpected("Missing field '__type'");
72+
if(source_value_it->is_string())
73+
{
74+
return Entry{ BT::Any(source_value_it->get<std::string>()),
75+
BT::TypeInfo::Create<std::string>() };
76+
}
77+
if(source_value_it->is_number_unsigned())
78+
{
79+
return Entry{ BT::Any(source_value_it->get<uint64_t>()),
80+
BT::TypeInfo::Create<uint64_t>() };
81+
}
82+
if(source_value_it->is_number_integer())
83+
{
84+
return Entry{ BT::Any(source_value_it->get<int64_t>()),
85+
BT::TypeInfo::Create<int64_t>() };
86+
}
87+
if(source_value_it->is_number_float())
88+
{
89+
return Entry{ BT::Any(source_value_it->get<double>()),
90+
BT::TypeInfo::Create<double>() };
91+
}
92+
if(source_value_it->is_boolean())
93+
{
94+
return Entry{ BT::Any(source_value_it->get<bool>()), BT::TypeInfo::Create<bool>() };
95+
}
7996
}
80-
auto type_it = type_names_.find(source["__type"]);
97+
98+
auto type_it = type_names_.find(source[kTypeField]);
8199
if(type_it == type_names_.end())
82100
{
83101
return nonstd::make_unexpected("Type not found in registered list");

tests/gtest_json.cpp

+26-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
#include "behaviortree_cpp/json_export.h"
44
#include "behaviortree_cpp/basic_types.h"
55

6+
namespace
7+
{
8+
constexpr std::string_view kTypeField = "__type";
9+
constexpr std::string_view kValueField = "value";
10+
} // namespace
11+
612
//----------- Custom types ----------
713

814
namespace TestTypes
@@ -95,16 +101,27 @@ TEST_F(JsonTest, TwoWaysConversion)
95101
TestTypes::Pose3D pose = { { 1, 2, 3 }, { 4, 5, 6, 7 } };
96102

97103
nlohmann::json json;
104+
exporter.toJson(BT::Any("string_val"), json["string"]);
98105
exporter.toJson(BT::Any(69), json["int"]);
106+
exporter.toJson(BT::Any(static_cast<uint64_t>(96)), json["uint"]);
99107
exporter.toJson(BT::Any(3.14), json["real"]);
100108
exporter.toJson(BT::Any(pose), json["pose"]);
101109

102110
std::cout << json.dump(2) << std::endl;
103111

104-
ASSERT_EQ(json["int"], 69);
105-
ASSERT_EQ(json["real"], 3.14);
112+
ASSERT_EQ(json["string"][kTypeField], "string");
113+
ASSERT_EQ(json["string"][kValueField], "string_val");
114+
115+
ASSERT_EQ(json["int"][kTypeField], "int64_t");
116+
ASSERT_EQ(json["int"][kValueField], 69);
117+
118+
ASSERT_EQ(json["uint"][kTypeField], "uint64_t");
119+
ASSERT_EQ(json["uint"][kValueField], 96);
120+
121+
ASSERT_EQ(json["real"][kTypeField], "double");
122+
ASSERT_EQ(json["real"][kValueField], 3.14);
106123

107-
ASSERT_EQ(json["pose"]["__type"], "Pose3D");
124+
ASSERT_EQ(json["pose"][kTypeField], "Pose3D");
108125
ASSERT_EQ(json["pose"]["pos"]["x"], 1);
109126
ASSERT_EQ(json["pose"]["pos"]["y"], 2);
110127
ASSERT_EQ(json["pose"]["pos"]["z"], 3);
@@ -126,8 +143,12 @@ TEST_F(JsonTest, TwoWaysConversion)
126143
ASSERT_EQ(pose.rot.y, pose2.rot.y);
127144
ASSERT_EQ(pose.rot.z, pose2.rot.z);
128145

129-
auto num = exporter.fromJson(json["int"])->first.cast<int>();
130-
ASSERT_EQ(num, 69);
146+
auto string_val = exporter.fromJson(json["string"])->first.cast<std::string>();
147+
ASSERT_EQ(string_val, "string_val");
148+
auto int_val = exporter.fromJson(json["int"])->first.cast<int>();
149+
ASSERT_EQ(int_val, 69);
150+
auto uint_val = exporter.fromJson(json["uint"])->first.cast<uint>();
151+
ASSERT_EQ(uint_val, 96);
131152
auto real = exporter.fromJson(json["real"])->first.cast<double>();
132153
ASSERT_EQ(real, 3.14);
133154
}

0 commit comments

Comments
 (0)