Skip to content

Commit a9e1ab3

Browse files
committed
Builder::settings_
We use Json::Value to configure the builders so we can maintain binary-compatibility easily.
1 parent 694dbcb commit a9e1ab3

5 files changed

Lines changed: 149 additions & 44 deletions

File tree

doc/jsoncpp.dox

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,13 @@ features without losing binary-compatibility.
9292
\code
9393
// For convenience, use `writeString()` with a specialized builder.
9494
Json::StreamWriterBuilder wbuilder;
95-
wbuilder.settings["indentation"] = "\t";
95+
wbuilder.settings_["indentation"] = "\t";
9696
std::string document = Json::writeString(wbuilder, root);
9797

9898
// Here, using a specialized Builder, we discard comments and
9999
// record errors as we parse.
100100
Json::CharReaderBuilder rbuilder;
101-
rbuilder.settings["collectComments"] = false;
101+
rbuilder.settings_["collectComments"] = false;
102102
std::string errs;
103103
bool ok = Json::parseFromStream(rbuilder, std::cin, &root, &errs);
104104
\endcode

include/json/reader.h

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,9 @@ class JSON_API CharReader {
270270

271271
class Factory {
272272
public:
273-
/// \brief Allocate a CharReader via operator new().
273+
/** \brief Allocate a CharReader via operator new().
274+
* \throw std::exception if something goes wrong (e.g. invalid settings)
275+
*/
274276
virtual CharReader* newCharReader() const = 0;
275277
}; // Factory
276278
}; // CharReader
@@ -283,29 +285,39 @@ class JSON_API CharReader {
283285
\code
284286
using namespace Json;
285287
CharReaderBuilder builder;
286-
builder.collectComments_ = false;
288+
builder.settings_["collectComments"] = false;
287289
Value value;
288290
std::string errs;
289291
bool ok = parseFromStream(builder, std::cin, &value, &errs);
290292
\endcode
291293
*/
292-
class CharReaderBuilder : public CharReader::Factory {
294+
class JSON_API CharReaderBuilder : public CharReader::Factory {
293295
public:
294-
/** default: true
295-
*
296-
* It is possible to "allow" comments but still not "collect" them.
297-
*/
298-
bool collectComments_;
299-
/** default: all()
300-
*
301-
* For historical reasons, Features is a separate structure.
302-
*/
303-
Features features_;
296+
// Note: We use a Json::Value so that we can add data-members to this class
297+
// without a major version bump.
298+
/** Configuration of this builder.
299+
Available settings (case-sensitive):
300+
- "collectComments": false or true (default=true)
301+
- TODO: other features ...
302+
But don't trust these docs. You can examine 'settings_` yourself
303+
to see the defaults. You can also write and read them just like any
304+
JSON Value.
305+
*/
306+
Json::Value settings_;
304307

305308
CharReaderBuilder();
306309
virtual ~CharReaderBuilder();
307310

308311
virtual CharReader* newCharReader() const;
312+
313+
/** \return true if 'settings' are illegal and consistent;
314+
* otherwise, indicate bad settings via 'invalid'.
315+
*/
316+
bool validate(Json::Value* invalid) const;
317+
/** Called by ctor, but you can use this to reset settings_.
318+
* \pre 'settings' != NULL (but Json::null is fine)
319+
*/
320+
static void setDefaults(Json::Value* settings);
309321
};
310322

311323
/** Consume entire stream and use its begin/end.

include/json/writer.h

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ class JSON_API StreamWriter {
6464
class JSON_API Factory {
6565
public:
6666
virtual ~Factory();
67-
/// Do not take ownership of sout, but maintain a reference.
67+
/** \brief Allocate a CharReader via operator new().
68+
* Do not take ownership of sout, but maintain a reference.
69+
* \throw std::exception if something goes wrong (e.g. invalid settings)
70+
*/
6871
virtual StreamWriter* newStreamWriter(std::ostream* sout) const = 0;
6972
}; // Factory
7073
}; // StreamWriter
@@ -77,41 +80,49 @@ std::string writeString(StreamWriter::Factory const& factory, Value const& root)
7780

7881
/** \brief Build a StreamWriter implementation.
7982
80-
\deprecated This is experimental and will be altered before the next release.
81-
8283
Usage:
8384
\code
8485
using namespace Json;
8586
Value value = ...;
8687
StreamWriterBuilder builder;
87-
builder.cs_ = StreamWriter::CommentStyle::None;
88-
builder.indentation_ = " "; // or whatever you like
88+
builder.settings_["commentStyle"] = "None";
89+
builder.settings_["indentation"] = " "; // or whatever you like
90+
std::unique_ptr<Json::StreamWriter> writer(
91+
builder.newStreamWriter(&std::cout));
8992
writer->write(value);
9093
std::cout << std::endl; // add lf and flush
9194
\endcode
9295
*/
9396
class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
9497
public:
95-
// Note: We cannot add data-members to this class without a major version bump.
96-
// So these might as well be completely exposed.
97-
98-
/** \brief How to write comments.
99-
* Default: All
100-
*/
101-
StreamWriter::CommentStyle::Enum cs_;
102-
/** \brief Write in human-friendly style.
103-
104-
If "", then skip all indentation and newlines.
105-
In that case, you probably want CommentStyle::None also.
106-
Default: "\t"
107-
*/
108-
std::string indentation_;
98+
// Note: We use a Json::Value so that we can add data-members to this class
99+
// without a major version bump.
100+
/** Configuration of this builder.
101+
Available settings (case-sensitive):
102+
- "commentStyle": "None", "Some", or "All" (default="All")
103+
- "indentation": (default="\t")
104+
But don't trust these docs. You can examine 'settings_` yourself
105+
to see the defaults. You can also write and read them just like any
106+
JSON Value.
107+
*/
108+
Json::Value settings_;
109109

110110
StreamWriterBuilder();
111111
virtual ~StreamWriterBuilder();
112112

113-
/// Do not take ownership of sout, but maintain a reference.
113+
/** Do not take ownership of sout, but maintain a reference.
114+
* \throw std::exception if something goes wrong (e.g. invalid settings)
115+
*/
114116
virtual StreamWriter* newStreamWriter(std::ostream* sout) const;
117+
118+
/** \return true if 'settings' are illegal and consistent;
119+
* otherwise, indicate bad settings via 'invalid'.
120+
*/
121+
bool validate(Json::Value* invalid) const;
122+
/** Called by ctor, but you can use this to reset settings_.
123+
* \pre 'settings' != NULL (but Json::null is fine)
124+
*/
125+
static void setDefaults(Json::Value* settings);
115126
};
116127

117128
/** \brief Build a StreamWriter implementation.
@@ -126,6 +137,8 @@ class JSON_API StreamWriterBuilder : public StreamWriter::Factory {
126137
* w->write(value);
127138
* delete w;
128139
* \endcode
140+
*
141+
* \deprecated Use StreamWriterBuilder
129142
*/
130143
class JSON_API OldCompressingStreamWriterBuilder : public StreamWriter::Factory
131144
{

src/lib_json/json_reader.cpp

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <istream>
1717
#include <sstream>
1818
#include <memory>
19+
#include <set>
1920

2021
#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
2122
#define snprintf _snprintf
@@ -912,14 +913,48 @@ class OldReader : public CharReader {
912913
};
913914

914915
CharReaderBuilder::CharReaderBuilder()
915-
: collectComments_(true)
916-
, features_(Features::all())
917-
{}
916+
{
917+
setDefaults(&settings_);
918+
}
918919
CharReaderBuilder::~CharReaderBuilder()
919920
{}
920921
CharReader* CharReaderBuilder::newCharReader() const
921922
{
922-
return new OldReader(collectComments_, features_);
923+
if (!validate(NULL)) throw std::runtime_error("invalid settings");
924+
// TODO: Maybe serialize the invalid settings into the exception.
925+
926+
bool collectComments = settings_["collectComments"].asBool();
927+
Features features = Features::all();
928+
// TODO: Fill in features.
929+
return new OldReader(collectComments, features);
930+
}
931+
static void getValidReaderKeys(std::set<std::string>* valid_keys)
932+
{
933+
valid_keys->clear();
934+
valid_keys->insert("collectComments");
935+
}
936+
bool CharReaderBuilder::validate(Json::Value* invalid) const
937+
{
938+
Json::Value my_invalid;
939+
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
940+
Json::Value& inv = *invalid;
941+
bool valid = true;
942+
std::set<std::string> valid_keys;
943+
getValidReaderKeys(&valid_keys);
944+
Value::Members keys = settings_.getMemberNames();
945+
size_t n = keys.size();
946+
for (size_t i = 0; i < n; ++i) {
947+
std::string const& key = keys[i];
948+
if (valid_keys.find(key) == valid_keys.end()) {
949+
inv[key] = settings_[key];
950+
}
951+
}
952+
return valid;
953+
}
954+
// static
955+
void CharReaderBuilder::setDefaults(Json::Value* settings)
956+
{
957+
(*settings)["collectComments"] = true;
923958
}
924959

925960
//////////////////////////////////

src/lib_json/json_writer.cpp

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <memory>
1212
#include <sstream>
1313
#include <utility>
14+
#include <set>
1415
#include <assert.h>
1516
#include <math.h>
1617
#include <stdio.h>
@@ -950,23 +951,67 @@ StreamWriter::~StreamWriter()
950951
StreamWriter::Factory::~Factory()
951952
{}
952953
StreamWriterBuilder::StreamWriterBuilder()
953-
: cs_(StreamWriter::CommentStyle::All)
954-
, indentation_("\t")
955-
{}
954+
{
955+
setDefaults(&settings_);
956+
}
956957
StreamWriterBuilder::~StreamWriterBuilder()
957958
{}
958959
StreamWriter* StreamWriterBuilder::newStreamWriter(std::ostream* stream) const
959960
{
961+
if (!validate(NULL)) throw std::runtime_error("invalid settings");
962+
// TODO: Maybe serialize the invalid settings into the exception.
963+
964+
std::string indentation = settings_["indentation"].asString();
965+
std::string cs_str = settings_["commentStyle"].asString();
966+
StreamWriter::CommentStyle::Enum cs = StreamWriter::CommentStyle::All;
967+
if (cs_str == "All") {
968+
cs = StreamWriter::CommentStyle::All;
969+
} else if (cs_str == "None") {
970+
cs = StreamWriter::CommentStyle::None;
971+
} else {
972+
return NULL;
973+
}
960974
std::string colonSymbol = " : ";
961-
if (indentation_.empty()) {
975+
if (indentation.empty()) {
962976
colonSymbol = ":";
963977
}
964978
std::string nullSymbol = "null";
965979
std::string endingLineFeedSymbol = "";
966980
return new BuiltStyledStreamWriter(stream,
967-
indentation_, cs_,
981+
indentation, cs,
968982
colonSymbol, nullSymbol, endingLineFeedSymbol);
969983
}
984+
static void getValidWriterKeys(std::set<std::string>* valid_keys)
985+
{
986+
valid_keys->clear();
987+
valid_keys->insert("indentation");
988+
valid_keys->insert("commentStyle");
989+
}
990+
bool StreamWriterBuilder::validate(Json::Value* invalid) const
991+
{
992+
Json::Value my_invalid;
993+
if (!invalid) invalid = &my_invalid; // so we do not need to test for NULL
994+
Json::Value& inv = *invalid;
995+
bool valid = true;
996+
std::set<std::string> valid_keys;
997+
getValidWriterKeys(&valid_keys);
998+
Value::Members keys = settings_.getMemberNames();
999+
size_t n = keys.size();
1000+
for (size_t i = 0; i < n; ++i) {
1001+
std::string const& key = keys[i];
1002+
if (valid_keys.find(key) == valid_keys.end()) {
1003+
inv[key] = settings_[key];
1004+
}
1005+
}
1006+
return valid;
1007+
}
1008+
// static
1009+
void StreamWriterBuilder::setDefaults(Json::Value* settings)
1010+
{
1011+
(*settings)["commentStyle"] = "All";
1012+
(*settings)["indentation"] = "\t";
1013+
}
1014+
9701015
/*
9711016
// This might become public someday.
9721017
class StreamWriterBuilderFactory {

0 commit comments

Comments
 (0)