nlohmann / json

JSON for Modern C++
https://json.nlohmann.me
MIT License
43.34k stars 6.75k forks source link

Error converting to/from scoped enumerations #4499

Open askr0x123456789 opened 5 days ago

askr0x123456789 commented 5 days ago

Description

nlohmann::json conversion from invalid json to scoped enumeration works without exceptions.

Reproduction steps

1- define a scoped enumeration 2- use NLOHMANN_JSON_SERIALIZE_ENUM for convertion from string to the enum type 3- convert an invalid string to the enum type

Expected vs. actual results

Actual results:

color: "blue"
color (int): 0
color is red
color (int): 0

Minimal code example

enum class Color: int {
    Red,
    Green,
    Blue
};

NLOHMANN_JSON_SERIALIZE_ENUM(Color, {
    {Color::Red, "red"},
    {Color::Green, "green"},
    {Color::Blue, "blue"}
});

int main() {
    auto blue = Color::Blue;
    const nlohmann::json blueJson = blue;
    fmt::println("color: {}", blueJson.dump()); // correct - works fine for valid enumerations
    const nlohmann::json invalidColorJson = "yellow";
    const Color invalidColor = invalidColorJson.get<Color>();
    fmt::println("color (int): {}", static_cast<int>(invalidColor)); // output is 0 - which is wrong
    if (invalidColor == Color::Red) { /// condition is true, which is wrong
        fmt::println("color is red");
    }
    fmt::println("color (int): {}", static_cast<int>(Color::Red)); // output is 0 - correct
    return EXIT_SUCCESS;
}

Error messages

No error message

Compiler and operating system

g++-14 on Kali Linux 2024.3

Library version

latest from develop branch

Validation

nlohmann commented 5 days ago

You try to find an enum value for the string "yellow". The documentation states:

When using template get(), undefined JSON values will default to the first specified conversion. Select this default pair carefully. See example 1 below.

Therefore, Color::Red is returned.

Unless I misunderstood the issue, I would say that the library behaves as documented.

askr0x123456789 commented 5 days ago

Shouldn't the correct behavior be throwing an exception?

I'm reading millions of records from a database and the available string value might be wrong. If I'm not sure about the string values, converting a string to enum, is better be done by if statements.

nlohmann commented 5 days ago

I understand. The current macro behaves as documented, and changing it would break existing code. One possibility would be adding a throwing version of the macro.