json icon indicating copy to clipboard operation
json copied to clipboard

Add NLOHMANN_JSON_SERIALIZE_ENUM_STRICT macro that throws type_error.302 on unknown JSON value (Fixes #3992)

Open Ash-Jose opened this issue 2 months ago • 29 comments

Summary

This PR fixes #3992 by introducing a new macro
NLOHMANN_JSON_SERIALIZE_ENUM_STRICT, which throws a json.exception.type_error.302
when deserializing a JSON string that does not match any enumerator.

The existing NLOHMANN_JSON_SERIALIZE_ENUM macro remains unchanged to preserve backward compatibility.


Changes

  • Added new macro NLOHMANN_JSON_SERIALIZE_ENUM_STRICT in macro_scope.hpp that throws type_error.302 for unmapped enum strings.
  • Added new test file unit-serialize_enum_strict.cpp validating the strict throwing behavior.
  • Regenerated single-header files using make amalgamate.
  • Verified all tests using ctest --output-on-failure.

Expected test impact

All existing tests for NLOHMANN_JSON_SERIALIZE_ENUM continue to pass unchanged.
New tests for NLOHMANN_JSON_SERIALIZE_ENUM_STRICT confirm that unknown JSON values now trigger exceptions.

Other unrelated floating-point mismatches (e.g., test-regression1_cpp11) are not affected by this change.


Documentation

A new documentation entry will be added at
docs/api/macros/nlohmann_json_serialize_enum_strict.md describing the stricter deserialization behavior.


Checklist

  • [x] Implementation complete
  • [x] New strict macro added (NLOHMANN_JSON_SERIALIZE_ENUM_STRICT)
  • [x] New test added and passing
  • [x] Single-header regenerated (make amalgamate)
  • [x] Backward compatibility preserved
  • [x] DCO signed
  • [x] Documentation pending maintainer confirmation

Ash-Jose avatar Nov 04 '25 20:11 Ash-Jose

i have made changes accordingly pls review

Ash-Jose avatar Nov 04 '25 22:11 Ash-Jose

🔴 Amalgamation check failed! 🔴

The source code has not been amalgamated. @Ash-Jose Please read and follow the Contribution Guidelines.

github-actions[bot] avatar Nov 04 '25 23:11 github-actions[bot]

Coverage Status

coverage: 99.192% (+0.001%) from 99.191% when pulling 12319044db42395e8709fd58a04e79dad51fceb1 on Ash-Jose:fix/enum-deser-throw-on-unknown into 49026f799983840d7cf1a8109ffffe7eb4b1012c on nlohmann:develop.

coveralls avatar Nov 04 '25 23:11 coveralls

🔴 Amalgamation check failed! 🔴

The source code has not been amalgamated. @Ash-Jose Please read and follow the Contribution Guidelines.

github-actions[bot] avatar Nov 05 '25 09:11 github-actions[bot]

is this because of using concat amalgamation check seems to have passed this time around

Ash-Jose avatar Nov 05 '25 10:11 Ash-Jose

is this because of using concat amalgamation check seems to have passed this time around

You need to include #include <nlohmann/detail/string_concat.hpp>.

nlohmann avatar Nov 05 '25 11:11 nlohmann

included the header

Ash-Jose avatar Nov 05 '25 11:11 Ash-Jose

🔴 Amalgamation check failed! 🔴

The source code has not been amalgamated. @Ash-Jose Please read and follow the Contribution Guidelines.

github-actions[bot] avatar Nov 05 '25 11:11 github-actions[bot]

why are tests still failing??

Ash-Jose avatar Nov 05 '25 13:11 Ash-Jose

Maybe some issue with the includes. Please try:

  • remove the string_concat.hpp include
  • revert the code to using std::string()... like you did before

Sorry for the confusion.

nlohmann avatar Nov 05 '25 14:11 nlohmann

i have reverted it

Ash-Jose avatar Nov 05 '25 14:11 Ash-Jose

should i redo in a different branch?? i dont understand why checks are failing

Ash-Jose avatar Nov 05 '25 15:11 Ash-Jose

i dont understand why they still fail

Ash-Jose avatar Nov 05 '25 17:11 Ash-Jose

Because there is more to forward-declare. I'm sorry, but it seems to be a more complicated issue to use an exception in the macro header.

nlohmann avatar Nov 05 '25 18:11 nlohmann

The forward declarations aren't required for the macro definition, they're required where the things are used.

~I think the issue is that it's using the detail namespace. I don't think we do that for any of the other user space macros.~ Nope, simple type issue.

gregmarr avatar Nov 05 '25 18:11 gregmarr

i have made changes accordingly this was the first version of my change although back then i wasnt able to make amalgamate work

Ash-Jose avatar Nov 05 '25 18:11 Ash-Jose

its still failing a few tests is that concerning??

Ash-Jose avatar Nov 05 '25 20:11 Ash-Jose

its still failing a few tests is that concerning??

Yes, one says you need to include <string> in macro_scope.hxx.

The fix for the other two is here: https://github.com/nlohmann/json/blob/af524ab666359f09a16bca1a41543a9a3a941251/tests/src/unit-unicode3.cpp#L23-L25

The "code scanning" one seems to be outside of the scope of your PR, since it's failing at

  /home/runner/work/json/json/tests/src/unit-comparison.cpp:437:57: warning: ‘bool nlohmann::json_abi_ldvcmp_v3_12_0::basic_json<>::operator<=(const_reference) const is deprecated: Since 3.11.0; use undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON [-Wdeprecated-declarations]
    437 |                         CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]));
        |                                                         ^
  /home/runner/work/json/json/tests/thirdparty/doctest/doctest.h:2428:24: note: in definition of macro ‘DOCTEST_ASSERT_IMPLEMENT_1’
   2428 |                     << __VA_ARGS__) DOCTEST_CLANG_SUPPRESS_WARNING_POP
        |                        ^~~~~~~~~~~
  /home/runner/work/json/json/tests/thirdparty/doctest/doctest.h:2970:20: note: in expansion of macro ‘DOCTEST_CHECK’
   2970 | #define CHECK(...) DOCTEST_CHECK(__VA_ARGS__)
        |                    ^~~~~~~~~~~~~
  /home/runner/work/json/json/tests/src/unit-comparison.cpp:437:25: note: in expansion of macro ‘CHECK’
    437 |                         CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]));
        |                         ^~~~~
  In file included from /home/runner/work/json/json/tests/src/unit-comparison.cpp:19:
  /home/runner/work/json/json/include/nlohmann/json.hpp:3775:10: note: declared here
   3775 |     bool operator<=(const_reference rhs) const noexcept
        |          ^~~~~~~~

gregmarr avatar Nov 05 '25 20:11 gregmarr

🔴 Amalgamation check failed! 🔴

The source code has not been amalgamated. @Ash-Jose Please read and follow the Contribution Guidelines.

github-actions[bot] avatar Nov 05 '25 20:11 github-actions[bot]

are these fails still related to my pr?

Ash-Jose avatar Nov 05 '25 22:11 Ash-Jose

Yes, the CI is green on the base branch.

nlohmann avatar Nov 06 '25 05:11 nlohmann

ignore this recent push, that was by accident anyways, when i try to use JSON_THROW i get error: 'JSON_THROW' was not declared in this scope; did you mean 'JSON_TRY'? even though this exists // allow disabling exceptions #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #define JSON_THROW(exception) throw exception #define JSON_TRY try #define JSON_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch(exception) #else #include #define JSON_THROW(exception) std::abort() #define JSON_TRY if(true) #define JSON_CATCH(exception) if(false) #define JSON_INTERNAL_CATCH(exception) if(false) #endif

Ash-Jose avatar Nov 06 '25 13:11 Ash-Jose

Ugh, JSON_THROW is undefined by macro_unscope.hpp. @nlohmann Thoughts on letting that stay defined? Otherwise I guess there would need to be a helper function to do the actual JSON_THROW.

gregmarr avatar Nov 06 '25 15:11 gregmarr

template <typename BasicJsonType>
inline void throw_enum_error(const BasicJsonType& j, const char* enum_type)
{
    JSON_THROW(::nlohmann::detail::type_error::create(
        302, std::string("invalid value for ") + enum_type + ": " + j.dump(), &j));
}

can i define a helper like this??

Ash-Jose avatar Nov 06 '25 17:11 Ash-Jose

i have made the previously suggested changes like the positioning of string header and all but i am still waiting for reply on what to do about error: 'JSON_THROW' was not declared in this scope; did you mean 'JSON_TRY'? sorry i was inactive a couple of days due to college final submissions but i am free again now and would love to solve this issue

Ash-Jose avatar Nov 12 '25 12:11 Ash-Jose

template <typename BasicJsonType>
inline void throw_enum_error(const BasicJsonType& j, const char* enum_type)
{
    JSON_THROW(::nlohmann::detail::type_error::create(
        302, std::string("invalid value for ") + enum_type + ": " + j.dump(), &j));
}

can i define a helper like this??

Seems reasonable to me, @nlohmann any objections?

gregmarr avatar Nov 12 '25 18:11 gregmarr

Sure! Sorry for not answering earlier.

nlohmann avatar Nov 12 '25 18:11 nlohmann

are my changes sufficient this time around? i will make the signoff change to avoid the DCO error also this pr has become quite messy with all my unecessary commits if you want i will submit another pr with only the necessary commits to keep things clean

Ash-Jose avatar Nov 18 '25 14:11 Ash-Jose

@nlohmann Looks like the workflows here are awaiting approval. Not sure why since they ran before.

gregmarr avatar Nov 18 '25 15:11 gregmarr