Skip to content

Commit 2fcdf08

Browse files
committed
Fixed issue with smart pointer traits specialization when converting from JSON null.
1 parent 91c275b commit 2fcdf08

File tree

10 files changed

+240
-82
lines changed

10 files changed

+240
-82
lines changed

ChangeLog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
v0.146.1
2+
--------
3+
4+
Fixed issue with `json_type_traits` specializations of `std::shared_ptr<T>` and
5+
`std::unique_ptr<T>` when converting from JSON null.
6+
17
v0.146.0
28
--------
39

doc/Examples.md

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,24 +1051,31 @@ int main()
10511051
val.field8 = std::unique_ptr<std::string>(nullptr);
10521052

10531053
std::string buf;
1054-
encode_json(val, buf);
1055-
1056-
json j = decode_json<json>(buf);
1057-
assert(j.contains("field1"));
1058-
assert(j.contains("field2"));
1059-
assert(j.contains("field3"));
1060-
assert(j.contains("field4"));
1061-
assert(j.contains("field5"));
1062-
assert(j.contains("field6"));
1063-
assert(!j.contains("field7"));
1064-
assert(!j.contains("field8"));
1065-
1066-
assert(j["field1"].as<std::string>() == std::string("Field 1"));
1067-
assert(j["field2"].as<std::string>() == std::string("Field 2"));
1068-
assert(j["field3"].is_null());
1069-
assert(j["field4"].is_null());
1070-
assert(j["field5"].as<std::string>() == std::string("Field 5"));
1071-
assert(j["field6"].as<std::string>() == std::string("Field 6"));
1054+
encode_json(val, buf, indenting::indent);
1055+
1056+
std::cout << buf << "\n";
1057+
1058+
auto other = decode_json<ns::smart_pointer_test>(buf);
1059+
1060+
assert(*other.field1 == *val.field1);
1061+
assert(*other.field2 == *val.field2);
1062+
assert(!other.field3);
1063+
assert(!other.field4);
1064+
assert(*other.field5 == *val.field5);
1065+
assert(*other.field6 == *val.field6);
1066+
assert(!other.field7);
1067+
assert(!other.field8);
1068+
}
1069+
```
1070+
Output:
1071+
```
1072+
{
1073+
"field1": "Field 1",
1074+
"field2": "Field 2",
1075+
"field3": null,
1076+
"field4": null,
1077+
"field5": "Field 5",
1078+
"field6": "Field 6"
10721079
}
10731080
```
10741081

doc/ref/json_type_traits.md

Lines changed: 46 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -711,46 +711,52 @@ using namespace jsoncons; // for convenience
711711
712712
int main()
713713
{
714-
ns::smart_pointer_and_optional_test1 val;
715-
val.field1 = std::make_shared<std::string>("Field 1");
716-
val.field2 = jsoncons::make_unique<std::string>("Field 2");
717-
val.field3 = "Field 3";
718-
val.field4 = std::shared_ptr<std::string>(nullptr);
719-
val.field5 = std::unique_ptr<std::string>(nullptr);
720-
val.field6 = std::optional<std::string>();
721-
val.field7 = std::make_shared<std::string>("Field 7");
722-
val.field8 = jsoncons::make_unique<std::string>("Field 8");
723-
val.field9 = "Field 9";
724-
val.field10 = std::shared_ptr<std::string>(nullptr);
725-
val.field11 = std::unique_ptr<std::string>(nullptr);
726-
val.field12 = std::optional<std::string>();
727-
728-
std::string buf;
729-
encode_json(val, buf);
730-
731-
json j = decode_json<json>(buf);
732-
assert(j.contains("field1"));
733-
assert(j.contains("field2"));
734-
assert(j.contains("field3"));
735-
assert(j.contains("field4"));
736-
assert(j.contains("field5"));
737-
assert(j.contains("field6"));
738-
assert(j.contains("field7"));
739-
assert(j.contains("field8"));
740-
assert(j.contains("field9"));
741-
CHECK(!j.contains("field10"));
742-
CHECK(!j.contains("field11"));
743-
CHECK(!j.contains("field12"));
744-
745-
assert(j["field1"].as<std::string>() == std::string("Field 1"));
746-
assert(j["field2"].as<std::string>() == std::string("Field 2"));
747-
assert(j["field3"].as<std::string>() == std::string("Field 3"));
748-
assert(j["field4"].is_null());
749-
assert(j["field5"].is_null());
750-
assert(j["field6"].is_null());
751-
assert(j["field7"].as<std::string>() == std::string("Field 7"));
752-
assert(j["field8"].as<std::string>() == std::string("Field 8"));
753-
assert(j["field9"].as<std::string>() == std::string("Field 9"));
714+
ns::smart_pointer_and_optional_test val;
715+
val.field1 = std::make_shared<std::string>("Field 1");
716+
val.field2 = jsoncons::make_unique<std::string>("Field 2");
717+
val.field3 = "Field 3";
718+
val.field4 = std::shared_ptr<std::string>(nullptr);
719+
val.field5 = std::unique_ptr<std::string>(nullptr);
720+
val.field6 = std::optional<std::string>();
721+
val.field7 = std::make_shared<std::string>("Field 7");
722+
val.field8 = jsoncons::make_unique<std::string>("Field 8");
723+
val.field9 = "Field 9";
724+
val.field10 = std::shared_ptr<std::string>(nullptr);
725+
val.field11 = std::unique_ptr<std::string>(nullptr);
726+
val.field12 = std::optional<std::string>();
727+
728+
std::string buf;
729+
encode_json(val, buf, indenting::indent);
730+
std::cout << buf << "\n";
731+
732+
auto other = decode_json<ns::smart_pointer_and_optional_test>(buf);
733+
734+
assert(*other.field1 == *val.field1);
735+
assert(*other.field2 == *val.field2);
736+
assert(*other.field3 == *val.field3);
737+
assert(!other.field4);
738+
assert(!other.field5);
739+
assert(!other.field6);
740+
assert(*other.field7 == *val.field7);
741+
assert(*other.field8 == *val.field8);
742+
assert(*other.field9 == *val.field9);
743+
assert(!other.field10);
744+
assert(!other.field11);
745+
assert(!other.field12);
746+
}
747+
```
748+
Output:
749+
```
750+
{
751+
"field1": "Field 1",
752+
"field2": "Field 2",
753+
"field3": "Field 3",
754+
"field4": null,
755+
"field5": null,
756+
"field6": null,
757+
"field7": "Field 7",
758+
"field8": "Field 8",
759+
"field9": "Field 9"
754760
}
755761
```
756762

examples/src/examples.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,9 @@ int main()
435435

436436
json_accessor_examples();
437437

438-
json_traits_macros_examples();
439-
440438
run_cbor_typed_array_examples();
439+
440+
json_traits_macros_examples();
441441
}
442442
catch (const std::exception& e)
443443
{

examples/src/json_traits_macros_examples.cpp

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -293,24 +293,20 @@ namespace {
293293
val.field8 = std::unique_ptr<std::string>(nullptr);
294294

295295
std::string buf;
296-
encode_json(val, buf);
297-
298-
json j = decode_json<json>(buf);
299-
assert(j.contains("field1"));
300-
assert(j.contains("field2"));
301-
assert(j.contains("field3"));
302-
assert(j.contains("field4"));
303-
assert(j.contains("field5"));
304-
assert(j.contains("field6"));
305-
assert(!j.contains("field7"));
306-
assert(!j.contains("field8"));
307-
308-
assert(j["field1"].as<std::string>() == std::string("Field 1"));
309-
assert(j["field2"].as<std::string>() == std::string("Field 2"));
310-
assert(j["field3"].is_null());
311-
assert(j["field4"].is_null());
312-
assert(j["field5"].as<std::string>() == std::string("Field 5"));
313-
assert(j["field6"].as<std::string>() == std::string("Field 6"));
296+
encode_json(val, buf, indenting::indent);
297+
298+
std::cout << buf << "\n";
299+
300+
auto other = decode_json<ns::smart_pointer_test>(buf);
301+
302+
assert(*other.field1 == *val.field1);
303+
assert(*other.field2 == *val.field2);
304+
assert(!other.field3);
305+
assert(!other.field4);
306+
assert(*other.field5 == *val.field5);
307+
assert(*other.field6 == *val.field6);
308+
assert(!other.field7);
309+
assert(!other.field8);
314310
}
315311

316312
void json_type_traits_book_examples()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// interprocess_allocator.cpp : This file contains the 'main' function. Program execution begins and ends there.
2+
//
3+
4+
#include <iostream>
5+
6+
int main()
7+
{
8+
std::cout << "Hello World!\n";
9+
}
10+
11+
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
12+
// Debug program: F5 or Debug > Start Debugging menu
13+
14+
// Tips for Getting Started:
15+
// 1. Use the Solution Explorer window to add/manage files
16+
// 2. Use the Team Explorer window to connect to source control
17+
// 3. Use the Output window to see build output and other messages
18+
// 4. Use the Error List window to view errors
19+
// 5. Go to Project > Add New Item to create new code files, or Project > Add Existing Item to add existing code files to the project
20+
// 6. In the future, to open this project again, go to File > Open > Project and select the .sln file
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#include <boost/interprocess/managed_shared_memory.hpp>
2+
#include <boost/interprocess/containers/vector.hpp>
3+
#include <boost/interprocess/allocators/allocator.hpp>
4+
#include <boost/interprocess/containers/string.hpp>
5+
#include <cstdlib> //std::system
6+
#include <jsoncons/json.hpp>
7+
8+
using namespace jsoncons;
9+
10+
typedef boost::interprocess::allocator<int,
11+
boost::interprocess::managed_shared_memory::segment_manager> shmem_allocator;
12+
13+
struct boost_sorted_policy : public sorted_policy
14+
{
15+
template <class T, class Allocator>
16+
using sequence_container_type = boost::interprocess::vector<T,Allocator>;
17+
18+
template <class CharT, class CharTraits, class Allocator>
19+
using key_storage = boost::interprocess::basic_string<CharT, CharTraits, Allocator>;
20+
21+
template <class CharT, class CharTraits, class Allocator>
22+
using string_storage = boost::interprocess::basic_string<CharT, CharTraits, Allocator>;
23+
};
24+
25+
typedef basic_json<char,boost_sorted_policy,shmem_allocator> shm_json;
26+
27+
int main(int argc, char *argv[])
28+
{
29+
typedef std::pair<double, int> MyType;
30+
31+
if(argc == 1){ //Parent process
32+
//Remove shared memory on construction and destruction
33+
struct shm_remove
34+
{
35+
shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
36+
~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
37+
} remover;
38+
39+
//Construct managed shared memory
40+
boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only,
41+
"MySharedMemory", 65536);
42+
43+
//Initialize shared memory STL-compatible allocator
44+
const shmem_allocator allocator(segment.get_segment_manager());
45+
46+
// Create json value with all dynamic allocations in shared memory
47+
48+
shm_json* j = segment.construct<shm_json>("my json")(shm_json::array(allocator));
49+
j->push_back(10);
50+
51+
shm_json o(allocator);
52+
//o.try_emplace("category", "reference",allocator);
53+
//o.try_emplace("author", "Nigel Rees",allocator);
54+
//o.try_emplace("title", "Sayings of the Century",allocator);
55+
//o.try_emplace("price", 8.95, allocator);
56+
o.insert_or_assign("category", "reference");
57+
o.insert_or_assign("author", "Nigel Rees");
58+
o.insert_or_assign("title", "Sayings of the Century");
59+
o.insert_or_assign("price", 8.95);
60+
61+
j->push_back(o);
62+
63+
shm_json a = shm_json::array(2,shm_json::object(allocator),allocator);
64+
a[0]["first"] = 1;
65+
66+
j->push_back(a);
67+
68+
std::pair<shm_json*, boost::interprocess::managed_shared_memory::size_type> res;
69+
res = segment.find<shm_json>("my json");
70+
71+
std::cout << "Parent:" << std::endl;
72+
std::cout << pretty_print(*(res.first)) << std::endl;
73+
74+
//Launch child process
75+
std::string s(argv[0]); s += " child ";
76+
if(0 != std::system(s.c_str()))
77+
return 1;
78+
79+
80+
//Check child has destroyed all objects
81+
if(segment.find<MyType>("my json").first)
82+
return 1;
83+
}
84+
else{
85+
//Open managed shared memory
86+
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only,
87+
"MySharedMemory");
88+
89+
std::pair<shm_json*, boost::interprocess::managed_shared_memory::size_type> res;
90+
res = segment.find<shm_json>("my json");
91+
92+
if (res.first != nullptr)
93+
{
94+
std::cout << "Child:" << std::endl;
95+
std::cout << pretty_print(*(res.first)) << std::endl;
96+
}
97+
else
98+
{
99+
std::cout << "Result is null" << std::endl;
100+
}
101+
102+
//We're done, delete all the objects
103+
segment.destroy<shm_json>("my json");
104+
}
105+
return 0;
106+
}
107+

include/jsoncons/config/version.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
#define JSONCONS_VERSION_MAJOR 0
1313
#define JSONCONS_VERSION_MINOR 146
14-
#define JSONCONS_VERSION_PATCH 0
14+
#define JSONCONS_VERSION_PATCH 1
1515

1616
namespace jsoncons {
1717

include/jsoncons/json_type_traits.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -879,7 +879,7 @@ namespace detail
879879

880880
static std::shared_ptr<ValueType> as(const Json& j)
881881
{
882-
return std::make_shared<ValueType>(j.template as<ValueType>());
882+
return j.is_null() ? std::shared_ptr<ValueType>(nullptr) : std::make_shared<ValueType>(j.template as<ValueType>());
883883
}
884884

885885
static Json to_json(const std::shared_ptr<ValueType>& ptr)
@@ -909,7 +909,7 @@ namespace detail
909909

910910
static std::unique_ptr<ValueType> as(const Json& j)
911911
{
912-
return jsoncons::make_unique<ValueType>(j.template as<ValueType>());
912+
return j.is_null() ? std::unique_ptr<ValueType>(nullptr) : jsoncons::make_unique<ValueType>(j.template as<ValueType>());
913913
}
914914

915915
static Json to_json(const std::unique_ptr<ValueType>& ptr)

tests/src/json_traits_macro_tests.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1208,7 +1208,8 @@ TEST_CASE("JSONCONS_N_MEMBER_TRAITS pointer and optional test")
12081208
val.field12 = jsoncons::optional<std::string>();
12091209

12101210
std::string buf;
1211-
encode_json(val, buf);
1211+
encode_json(val, buf, indenting::indent);
1212+
//std::cout << buf << "\n";
12121213

12131214
json j = decode_json<json>(buf);
12141215
CHECK(j.contains("field1"));
@@ -1233,5 +1234,20 @@ TEST_CASE("JSONCONS_N_MEMBER_TRAITS pointer and optional test")
12331234
CHECK(j["field7"].as<std::string>() == std::string("Field 7"));
12341235
CHECK(j["field8"].as<std::string>() == std::string("Field 8"));
12351236
CHECK(j["field9"].as<std::string>() == std::string("Field 9"));
1237+
1238+
auto other = decode_json<ns::smart_pointer_and_optional_test1>(buf);
1239+
1240+
CHECK(*other.field1 == *val.field1);
1241+
CHECK(*other.field2 == *val.field2);
1242+
CHECK(*other.field3 == *val.field3);
1243+
CHECK_FALSE(other.field4);
1244+
CHECK_FALSE(other.field5);
1245+
CHECK_FALSE(other.field6);
1246+
CHECK(*other.field7 == *val.field7);
1247+
CHECK(*other.field8 == *val.field8);
1248+
CHECK(*other.field9 == *val.field9);
1249+
CHECK_FALSE(other.field10);
1250+
CHECK_FALSE(other.field11);
1251+
CHECK_FALSE(other.field12);
12361252
}
12371253
}

0 commit comments

Comments
 (0)