Skip to content

Commit 69ad558

Browse files
authored
Merge pull request #47 from FFMG/feature/warning
When looking for a key that does not exist we now raise a warning, (if there is a valid callback).
2 parents 6f8d767 + 6b0bee4 commit 69ad558

8 files changed

Lines changed: 249 additions & 44 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.2.5] - 2026-06-11
9+
10+
### Added
11+
- Added warning callback trigger when attempting to retrieve non-existent keys in `TJValueObject` using `try_get_string`, `get_*(..)`, or `get<>(..)` methods.
12+
13+
### Changed
14+
- Incremented version to 0.3.0.
15+
816
## [0.2.4] - 2026-05-20
917

1018
### Added

README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[![CI](https://github.com/FFMG/TinyJSON/actions/workflows/c-cpp.yml/badge.svg)](https://github.com/FFMG/TinyJSON/actions/workflows/c-cpp.yml)
44
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5-
[![Version](https://img.shields.io/badge/version-0.2.4-blue.svg)](src/TinyJSON.h)
5+
[![Version](https://img.shields.io/badge/version-0.2.5-blue.svg)](src/TinyJSON.h)
66

77
A lightweight and lightning-fast C++ JSON & JSON5 parser designed for high performance and minimal footprint.
88

@@ -131,8 +131,8 @@ The version is set in the `TinyJSON.h` file.
131131
```cpp
132132
static const short TJ_VERSION_MAJOR = 0;
133133
static const short TJ_VERSION_MINOR = 2;
134-
static const short TJ_VERSION_PATCH = 4;
135-
static const char TJ_VERSION_STRING[] = "0.2.4";
134+
static const short TJ_VERSION_PATCH = 5;
135+
static const char TJ_VERSION_STRING[] = "0.2.5";
136136
```
137137

138138
### Simple Value Access
@@ -169,6 +169,7 @@ if (tj) {
169169
* json5_1_0_0
170170
* Callback: (`callback_function:std::function<void(message_type, const TJCHAR*)>`) Callback function called where there is an error, warning etc.
171171
NB: The Callback function is called even if Throw is false.
172+
* If a getter method (`try_get_string`, `get_*(..)`, or `get<>(..)`) is called on a key that does not exist in a `TJValueObject`, a warning message indicating the missing key (e.g. `"The key 'missing' was not found!"`) is passed to the callback function.
172173
* trace
173174
* debug
174175
* info
@@ -673,7 +674,7 @@ auto doubles = obj->get<std::vector<double>>("floats");
673674
#### Strict Get values
674675

675676

676-
Getter methods on `TJValue` (or through `TJValueObject` keys) can be used to retrieve specific types. By default, these methods are non-strict and return default values if the type is incorrect. By setting `strict: true` in `parse_options`, these methods will throw a `TJParseException` instead.
677+
Getter methods on `TJValue` (or through `TJValueObject` keys) can be used to retrieve specific types. By default, these methods are non-strict and return default values if the type is incorrect. By setting `strict: true` in `parse_options`, these methods will throw a `TJParseException` instead. If a key is not found when calling `try_get_string`, `get_*(..)`, or `get<>(..)`, a warning callback is triggered with a message indicating the key that was not found (e.g. `"The key 'missing' was not found!"`) if a callback function is registered in `parse_options`.
677678

678679
- get_number<T>()
679680
- get_float<T>()

src/TinyJSON.cpp

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5396,16 +5396,68 @@ namespace TinyJSON
53965396
return object;
53975397
}
53985398

5399+
void TJValueObject::raise_key_not_found(const TJCHAR* key, bool is_strict) const
5400+
{
5401+
if (key == nullptr)
5402+
{
5403+
return;
5404+
}
5405+
int key_len = 0;
5406+
while (key[key_len] != 0)
5407+
{
5408+
key_len++;
5409+
}
5410+
int total_len = 9 + key_len + 17;
5411+
TJCHAR* msg = new TJCHAR[total_len + 1];
5412+
5413+
const TJCHAR* prefix = TJCHARPREFIX("The key '");
5414+
for (int i = 0; i < 9; ++i)
5415+
{
5416+
msg[i] = prefix[i];
5417+
}
5418+
5419+
for (int i = 0; i < key_len; ++i)
5420+
{
5421+
msg[9 + i] = key[i];
5422+
}
5423+
5424+
const TJCHAR* suffix = TJCHARPREFIX("' was not found!");
5425+
for (int i = 0; i < 17; ++i)
5426+
{
5427+
msg[9 + key_len + i] = suffix[i];
5428+
}
5429+
5430+
msg[total_len] = 0;
5431+
5432+
if (is_strict)
5433+
{
5434+
_parse_options.callback_function(parse_options::message_type::fatal, msg);
5435+
if (_parse_options.throw_exception)
5436+
{
5437+
#if TJ_USE_CHAR == 1
5438+
TJParseException ex(msg);
5439+
delete[] msg;
5440+
throw ex;
5441+
#else
5442+
delete[] msg;
5443+
throw TJParseException("The key was not found!");
5444+
#endif
5445+
}
5446+
}
5447+
else
5448+
{
5449+
_parse_options.callback_function(parse_options::message_type::warning, msg);
5450+
}
5451+
5452+
delete[] msg;
5453+
}
5454+
53995455
Optional<long double> TJValueObject::get_raw_float(const TJCHAR* key, bool case_sensitive) const
54005456
{
54015457
auto value = try_get_value(key, case_sensitive);
54025458
if (nullptr == value)
54035459
{
5404-
if (_parse_options.strict)
5405-
{
5406-
ParseResult _parse_result(_parse_options);
5407-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5408-
}
5460+
raise_key_not_found(key, _parse_options.strict);
54095461
return Optional<long double>();
54105462
}
54115463
return Optional<long double>(value->get_raw_float());
@@ -5416,11 +5468,7 @@ namespace TinyJSON
54165468
auto value = try_get_value(key, case_sensitive);
54175469
if (nullptr == value)
54185470
{
5419-
if (_parse_options.strict)
5420-
{
5421-
ParseResult _parse_result(_parse_options);
5422-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5423-
}
5471+
raise_key_not_found(key, _parse_options.strict);
54245472
return Optional<long long>();
54255473
}
54265474
return Optional<long long>(value->get_raw_number());
@@ -5431,11 +5479,7 @@ namespace TinyJSON
54315479
auto value = try_get_value(key, case_sensitive);
54325480
if (nullptr == value)
54335481
{
5434-
if (_parse_options.strict)
5435-
{
5436-
ParseResult _parse_result(_parse_options);
5437-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5438-
}
5482+
raise_key_not_found(key, _parse_options.strict);
54395483
return Optional<std::vector<long double>>();
54405484
}
54415485
return Optional<std::vector<long double>>(value->get_raw_floats());
@@ -5446,11 +5490,7 @@ namespace TinyJSON
54465490
auto value = try_get_value(key, case_sensitive);
54475491
if (nullptr == value)
54485492
{
5449-
if (_parse_options.strict)
5450-
{
5451-
ParseResult _parse_result(_parse_options);
5452-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5453-
}
5493+
raise_key_not_found(key, _parse_options.strict);
54545494
return Optional<std::vector<long long>>();
54555495
}
54565496
return Optional<std::vector<long long>>(value->get_raw_numbers());
@@ -5461,11 +5501,7 @@ namespace TinyJSON
54615501
auto value = try_get_value(key, case_sensitive);
54625502
if (nullptr == value)
54635503
{
5464-
if (_parse_options.strict)
5465-
{
5466-
ParseResult _parse_result(_parse_options);
5467-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5468-
}
5504+
raise_key_not_found(key, _parse_options.strict);
54695505
return TJCHARPREFIX("");
54705506
}
54715507
return value->get_string();
@@ -5476,11 +5512,7 @@ namespace TinyJSON
54765512
auto value = try_get_value(key, case_sensitive);
54775513
if (nullptr == value)
54785514
{
5479-
if (_parse_options.strict)
5480-
{
5481-
ParseResult _parse_result(_parse_options);
5482-
_parse_result.assign_exception_message_and_throw("The key was not found!");
5483-
}
5515+
raise_key_not_found(key, _parse_options.strict);
54845516
return false;
54855517
}
54865518
return value->get_boolean();
@@ -5898,6 +5930,7 @@ namespace TinyJSON
58985930
auto value = try_get_value(key, case_sensitive);
58995931
if (nullptr == value)
59005932
{
5933+
raise_key_not_found(key, false);
59015934
return nullptr;
59025935
}
59035936

src/TinyJSON.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@
4545
// v0.2.1 - added remove_at to TJValueArray.
4646
// v0.2.2 - added support for Json5 https://github.com/json5/
4747
// v0.2.3 - added atomic file saving
48-
// v0.2.4 - added operator[] and as<T>() accessors to TJValue
48+
// v0.2.4 - added operator[] and as<T>() accessor to TJValue
49+
// v0.2.5 - added raise warning when key is not found.
4950
static const short TJ_VERSION_MAJOR = 0;
5051
static const short TJ_VERSION_MINOR = 2;
51-
static const short TJ_VERSION_PATCH = 4;
52-
static const char TJ_VERSION_STRING[] = "0.2.4";
52+
static const short TJ_VERSION_PATCH = 5;
53+
static const char TJ_VERSION_STRING[] = "0.2.5";
5354

5455
#ifndef TJ_USE_CHAR
5556
# define TJ_USE_CHAR 1
@@ -1157,6 +1158,7 @@ class TJDictionary;
11571158
}
11581159

11591160
private:
1161+
void raise_key_not_found(const TJCHAR* key, bool is_strict) const;
11601162
template<typename V>
11611163
std::vector<V> get_vector_internal(const TJCHAR* key, bool case_sensitive, std::true_type) const
11621164
{

tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ set( Sources
3535
"testtinyjsonstrings.cpp"
3636
testtinyjsonvaluesget.cpp
3737
testtinyjsonversion.cpp
38+
testtinyjsonwarnings.cpp
3839
testtinyjsonconstructors.cpp
3940
testtinyjsonwrite.cpp
4041
testtinyjsonset.cpp

tests/testtinyjsonexceptions.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ TEST(TestException, GettingNonExistentKeyWillLogAndNotThrow) {
285285
options.strict = true;
286286
options.callback_function = [&](TinyJSON::parse_options::message_type message_type, const TJCHAR* exception_message) {
287287
EXPECT_EQ(message_type, TinyJSON::parse_options::fatal);
288-
EXPECT_STREQ(exception_message, "The key was not found!");
288+
EXPECT_STREQ(exception_message, "The key 'b' was not found!");
289289
called = true;
290290
};
291291
TinyJSON::TJValue* json = TinyJSON::TJ::parse("{\"a\" : 12}", options);

tests/testtinyjsonversion.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,22 @@
55
#define TJ_USE_CHAR 1
66
#include "../src/TinyJSON.h"
77

8-
TEST(TestVersion, CheckVersionMajor) {
8+
TEST(TestVersion, CheckVersionMajor)
9+
{
910
ASSERT_EQ(0, TJ_VERSION_MAJOR);
1011
}
1112

12-
TEST(TestVersion, CheckVersionMinor) {
13+
TEST(TestVersion, CheckVersionMinor)
14+
{
1315
ASSERT_EQ(2, TJ_VERSION_MINOR);
1416
}
1517

16-
TEST(TestVersion, CheckVersionPatch) {
17-
ASSERT_EQ(4, TJ_VERSION_PATCH);
18+
TEST(TestVersion, CheckVersionPatch)
19+
{
20+
ASSERT_EQ(5, TJ_VERSION_PATCH);
1821
}
1922

20-
TEST(TestVersion, CheckVersionString) {
21-
ASSERT_STREQ("0.2.4", TJ_VERSION_STRING);
23+
TEST(TestVersion, CheckVersionString)
24+
{
25+
ASSERT_STREQ("0.2.5", TJ_VERSION_STRING);
2226
}

0 commit comments

Comments
 (0)