Skip to content

Commit 78c13b7

Browse files
committed
new fromJSON API
1 parent e386c75 commit 78c13b7

File tree

6 files changed

+86
-33
lines changed

6 files changed

+86
-33
lines changed

include/behaviortree_cpp/blackboard.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,11 @@ class Blackboard
125125
nlohmann::json ExportBlackboardToJSON(const Blackboard &blackboard);
126126

127127
/**
128-
* @brief ImportBlackboardToJSON will append elements to the blackboard,
128+
* @brief ImportBlackboardFromJSON will append elements to the blackboard,
129129
* using the values parsed from the JSON file created using ExportBlackboardToJSON.
130130
* Complex types must be registered with JsonExporter::get()
131131
*/
132-
void ImportBlackboardToJSON(const nlohmann::json& json, Blackboard& blackboard);
132+
void ImportBlackboardFromJSON(const nlohmann::json& json, Blackboard& blackboard);
133133

134134

135135
//------------------------------------------------------

include/behaviortree_cpp/json_export.h

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include "behaviortree_cpp/basic_types.h"
34
#include "behaviortree_cpp/utils/safe_any.hpp"
45
#include "behaviortree_cpp/contrib/expected.hpp"
56

@@ -56,21 +57,26 @@ class JsonExporter {
5657
* @brief toJson adds the content of "any" to the JSON "destination".
5758
*
5859
* It will return false if the conversion toJson is not possible
59-
* ( you might need to register the converter with addConverter() ).
60+
* If it is a custom type, you might register it first with addConverter().
6061
*/
6162
bool toJson(const BT::Any& any, nlohmann::json& destination) const;
6263

63-
using ExpectedAny = nonstd::expected_lite::expected<BT::Any, std::string>;
64+
/// This information is needed to create a BT::Blackboard::entry
65+
using Entry = std::pair<BT::Any, BT::TypeInfo>;
6466

65-
ExpectedAny fromJson(const nlohmann::json& source) const;
66-
67-
ExpectedAny fromJson(const nlohmann::json& source, std::type_index type) const;
67+
using ExpectedEntry = nonstd::expected_lite::expected<Entry, std::string>;
6868

69+
/**
70+
* @brief fromJson will return an Entry (value wrappedn in Any + TypeInfo)
71+
* from a json source.
72+
* If it is a custom type, you might register it first with addConverter().
73+
* @param source
74+
* @return
75+
*/
76+
ExpectedEntry fromJson(const nlohmann::json& source) const;
6977

70-
template <typename T>
71-
void toJson(const T& val, nlohmann::json& dst) const {
72-
dst = val;
73-
}
78+
/// Same as the other, but providing the specific type
79+
ExpectedEntry fromJson(const nlohmann::json& source, std::type_index type) const;
7480

7581
/// Register new JSON converters with addConverter<Foo>().
7682
/// You should have used first the macro BT_JSON_CONVERTER
@@ -79,11 +85,11 @@ class JsonExporter {
7985
private:
8086

8187
using ToJonConverter = std::function<void(const BT::Any&, nlohmann::json&)>;
82-
using FromJonConverter = std::function<BT::Any(const nlohmann::json&)>;
88+
using FromJonConverter = std::function<Entry(const nlohmann::json&)>;
8389

8490
std::unordered_map<std::type_index, ToJonConverter> to_json_converters_;
8591
std::unordered_map<std::type_index, FromJonConverter> from_json_converters_;
86-
std::unordered_map<std::string, std::type_index> type_names_;
92+
std::unordered_map<std::string, BT::TypeInfo> type_names_;
8793
};
8894

8995

@@ -99,22 +105,22 @@ void JsonExporter::addConverter()
99105
};
100106
to_json_converters_.insert( {typeid(T), to_converter} );
101107

102-
FromJonConverter from_converter = [](const nlohmann::json& dst) -> BT::Any
108+
FromJonConverter from_converter = [](const nlohmann::json& dst) -> Entry
103109
{
104110
T value;
105111
using namespace nlohmann;
106112
from_json(dst, value);
107-
return BT::Any(value);
113+
return {BT::Any(value), BT::TypeInfo::Create<T>()};
108114
};
109115

110116
// we need to get the name of the type
111117
nlohmann::json const js = T{};
112118
// we insert both the name obtained from JSON and demangle
113119
if(js.contains("__type"))
114120
{
115-
type_names_.insert( {std::string(js["__type"]), typeid(T)} );
121+
type_names_.insert( {std::string(js["__type"]), BT::TypeInfo::Create<T>()} );
116122
}
117-
type_names_.insert( {BT::demangle(typeid(T)), typeid(T)} );
123+
type_names_.insert( {BT::demangle(typeid(T)), BT::TypeInfo::Create<T>()} );
118124

119125
from_json_converters_.insert( {typeid(T), from_converter} );
120126
}

src/basic_types.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ Any convertFromJSON(StringView json_text, std::type_index type)
410410
{
411411
throw std::runtime_error(res.error());
412412
}
413-
return *res;
413+
return res->first;
414414
}
415415

416416
} // namespace BT

src/blackboard.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,4 +242,20 @@ nlohmann::json ExportBlackboardToJSON(const Blackboard &blackboard)
242242
return dest;
243243
}
244244

245+
void ImportBlackboardFromJSON(const nlohmann::json &json, Blackboard &blackboard)
246+
{
247+
for (auto it = json.begin(); it != json.end(); ++it)
248+
{
249+
if(auto res = JsonExporter::get().fromJson(it.value()))
250+
{
251+
auto entry = blackboard.getEntry(it.key());
252+
if(!entry) {
253+
blackboard.createEntry(it.key(), res->second);
254+
entry = blackboard.getEntry(it.key());
255+
}
256+
entry->value = res->first;
257+
}
258+
}
259+
}
260+
245261
} // namespace BT

src/json_export.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,36 @@ bool JsonExporter::toJson(const Any &any, nlohmann::json &dst) const
3838
return true;
3939
}
4040

41-
JsonExporter::ExpectedAny JsonExporter::fromJson(const nlohmann::json &source) const
41+
JsonExporter::ExpectedEntry JsonExporter::fromJson(const nlohmann::json &source) const
4242
{
4343
if(source.is_null())
4444
{
4545
return nonstd::make_unexpected("json object is null");
4646
}
4747
if( source.is_string())
4848
{
49-
return BT::Any(source.get<std::string>());
49+
return Entry{BT::Any(source.get<std::string>()),
50+
BT::TypeInfo::Create<std::string>()};
5051
}
5152
if( source.is_number_unsigned())
5253
{
53-
return BT::Any(source.get<uint64_t>());
54+
return Entry{BT::Any(source.get<uint64_t>()),
55+
BT::TypeInfo::Create<uint64_t>()};
5456
}
5557
if( source.is_number_integer())
5658
{
57-
return BT::Any(source.get<int64_t>());
59+
return Entry{BT::Any(source.get<int64_t>()),
60+
BT::TypeInfo::Create<int64_t>()};
5861
}
5962
if( source.is_number_float())
6063
{
61-
return BT::Any(source.get<double>());
64+
return Entry{BT::Any(source.get<double>()),
65+
BT::TypeInfo::Create<double>()};
6266
}
6367
if( source.is_boolean())
6468
{
65-
return BT::Any(source.get<bool>());
69+
return Entry{BT::Any(source.get<bool>()),
70+
BT::TypeInfo::Create<bool>()};
6671
}
6772

6873
if(!source.contains("__type"))
@@ -74,15 +79,16 @@ JsonExporter::ExpectedAny JsonExporter::fromJson(const nlohmann::json &source) c
7479
{
7580
return nonstd::make_unexpected("Type not found in registered list");
7681
}
77-
auto func_it = from_json_converters_.find(type_it->second);
82+
auto func_it = from_json_converters_.find(type_it->second.type());
7883
if(func_it == from_json_converters_.end())
7984
{
8085
return nonstd::make_unexpected("Type not found in registered list");
8186
}
8287
return func_it->second(source);
8388
}
8489

85-
JsonExporter::ExpectedAny JsonExporter::fromJson(const nlohmann::json &source, std::type_index type) const
90+
JsonExporter::ExpectedEntry
91+
JsonExporter::fromJson(const nlohmann::json &source, std::type_index type) const
8692
{
8793
auto func_it = from_json_converters_.find(type);
8894
if(func_it == from_json_converters_.end())

tests/gtest_json.cpp

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <gtest/gtest.h>
2+
#include "behaviortree_cpp/blackboard.h"
23
#include "behaviortree_cpp/json_export.h"
34
#include "behaviortree_cpp/basic_types.h"
45

@@ -90,7 +91,7 @@ TEST_F(JsonTest, TwoWaysConversion)
9091
ASSERT_EQ(json["pose"]["rot"]["z"], 7);
9192

9293
// check the two-ways transform, i.e. "from_json"
93-
auto pose2 = exporter.fromJson(json["pose"])->cast<TestTypes::Pose3D>();
94+
auto pose2 = exporter.fromJson(json["pose"])->first.cast<TestTypes::Pose3D>();
9495

9596
ASSERT_EQ(pose.pos.x, pose2.pos.x);
9697
ASSERT_EQ(pose.pos.y, pose2.pos.y);
@@ -101,19 +102,43 @@ TEST_F(JsonTest, TwoWaysConversion)
101102
ASSERT_EQ(pose.rot.y, pose2.rot.y);
102103
ASSERT_EQ(pose.rot.z, pose2.rot.z);
103104

104-
auto num = exporter.fromJson(json["int"])->cast<int>();
105+
auto num = exporter.fromJson(json["int"])->first.cast<int>();
105106
ASSERT_EQ(num, 69);
106-
auto real = exporter.fromJson(json["real"])->cast<double>();
107+
auto real = exporter.fromJson(json["real"])->first.cast<double>();
107108
ASSERT_EQ(real, 3.14);
109+
}
108110

111+
TEST_F(JsonTest, ConvertFromString)
112+
{
113+
TestTypes::Vector3D vect;
114+
auto const test_json = R"(json:{"x":2.1, "y":4.2, "z":6.3})";
115+
ASSERT_NO_THROW(vect = BT::convertFromString<TestTypes::Vector3D>(test_json));
109116

117+
ASSERT_EQ(vect.x, 2.1);
118+
ASSERT_EQ(vect.y, 4.2);
119+
ASSERT_EQ(vect.z, 6.3);
110120
}
111121

112-
TEST_F(JsonTest, ConvertFromString)
122+
TEST_F(JsonTest, BlackboardInOut)
113123
{
114-
TestTypes::Vector3D pose3;
115-
auto const test_json = R"(json:{"x":2, "y":4, "z":6})";
116-
ASSERT_NO_THROW(pose3 = BT::convertFromString<TestTypes::Vector3D>(test_json));
124+
auto bb = BT::Blackboard::create();
125+
bb->set("int", 42);
126+
bb->set("real", 3.14);
127+
bb->set("vect", TestTypes::Vector3D{1.1, 2.2, 3.3});
128+
129+
auto json = ExportBlackboardToJSON(*bb);
130+
std::cout << json.dump(2) << std::endl;
131+
132+
auto bb_out = BT::Blackboard::create();
133+
ImportBlackboardFromJSON(json, *bb_out);
134+
135+
ASSERT_EQ(bb_out->get<int>("int"), 42);
136+
ASSERT_EQ(bb_out->get<double>("real"), 3.14);
137+
138+
auto vect_out = bb_out->get<TestTypes::Vector3D>("vect");
139+
ASSERT_EQ(vect_out.x, 1.1);
140+
ASSERT_EQ(vect_out.y, 2.2);
141+
ASSERT_EQ(vect_out.z, 3.3);
117142
}
118143

119144

0 commit comments

Comments
 (0)