Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

when enum is used as key in a map the json format is not an expected format #4378

Open
2 tasks
ordit1985 opened this issue May 22, 2024 · 7 comments · May be fixed by #4531
Open
2 tasks

when enum is used as key in a map the json format is not an expected format #4378

ordit1985 opened this issue May 22, 2024 · 7 comments · May be fixed by #4531

Comments

@ordit1985
Copy link

ordit1985 commented May 22, 2024

Description

I would expect map to be parsed as json objects eg.
{"aa":"completed","bb":"running"}

In fact this json format is dependent on the key type. When the key type is string, the json is created as expected.
When the key type is an enum, the map is parsed as json array eg.
[["stopped","aa"],["completed","bb"]]

Reproduction steps

#include <iostream>
#include <string>
#include <map>
#include "common/include/json/json.h"

using njson = nlohmann::json;

// example enum type declaration
enum TaskState {
    TS_STOPPED,
    TS_RUNNING,
    TS_COMPLETED,
    TS_INVALID=-1,
};

// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
    {TS_INVALID, nullptr},
    {TS_STOPPED, "stopped"},
    {TS_RUNNING, "running"},
    {TS_COMPLETED, "completed"},
})

int main(int argc, char ** argv) {

	std::map<TaskState, std::string> t1 = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
	std::map<std::string, TaskState> t2 = {{"aa", TS_COMPLETED}, {"bb", TS_RUNNING}};

	printf("enum_in_key_nohlman: %s\n", njson(t1).dump().c_str());
	printf("enum_in_val_nohlman: %s\n", njson(t2).dump().c_str());


// when enum is in key the json format changes to unexpected json format.
// enum_in_key_nohlman: [["stopped","aa"],["completed","bb"]]
// enum_in_val_nohlman: {"aa":"completed","bb":"running"}
}

Expected vs. actual results

I would expect both cases to look in same format:
enum_in_key_nohlman: {"stopped","aa","completed","bb"}
enum_in_val_nohlman: {"aa":"completed","bb":"running"}

Minimal code example

#include <iostream>
#include <string>
#include <map>
#include "common/include/json/json.h"

using njson = nlohmann::json;

// example enum type declaration
enum TaskState {
    TS_STOPPED,
    TS_RUNNING,
    TS_COMPLETED,
    TS_INVALID=-1,
};

// map TaskState values to JSON as strings
NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
    {TS_INVALID, nullptr},
    {TS_STOPPED, "stopped"},
    {TS_RUNNING, "running"},
    {TS_COMPLETED, "completed"},
})

int main(int argc, char ** argv) {

	std::map<TaskState, std::string> t1 = {{TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"}};
	std::map<std::string, TaskState> t2 = {{"aa", TS_COMPLETED}, {"bb", TS_RUNNING}};

	printf("enum_in_key_nohlman: %s\n", njson(t1).dump().c_str());
	printf("enum_in_val_nohlman: %s\n", njson(t2).dump().c_str());


// when enum is in key the json format changes to unexpected json format.
// enum_in_key_nohlman: [["stopped","aa"],["completed","bb"]]
// enum_in_val_nohlman: {"aa":"completed","bb":"running"}
}

Error messages

unexpected format
enum_in_key_nohlman: [["stopped","aa"],["completed","bb"]]

Compiler and operating system

linux

Library version

3.6.1

Validation

@Abastien1734
Copy link

If I wanted to work on this, would I just fork and then submit a PR? Do I need to be assigned to work on this?

@t-b
Copy link
Contributor

t-b commented Jun 6, 2024

If I wanted to work on this, would I just fork and then submit a PR?

Yes!

Do I need to be assigned to work on this?

Nope.

@amirghaz
Copy link

amirghaz commented Nov 7, 2024

I'm planning to look into this issue.

@nlohmann
Copy link
Owner

@amirghaz

Call njson(t1) uses

inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)

and njson(t2) uses

inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)

It seems is_constructible_object_type_impl needs to be adjusted to detect TaskState has a conversion to string so it can be used as object key.

@amirghaz
Copy link

@nlohmann Sorry for the lack of update, some stuffs came up that prevent me from focusing on this issue. Thanks for the insight, I will look into it right away to see what can be done.

@amirghaz
Copy link

@nlohmann
I tried to modify is_compatible_object_type_impl to detect if there is any conversion to string, but there seems to be other error that arise after this modification.

The error messages that I get is:
Screenshot 2024-11-29 154725

Also, I notice that this issue only arise if we use a map object as an argument to njson. Using njson({ {TS_STOPPED, "aa"}, {TS_COMPLETED, "bb"} }).dump().c_str() directly will result in the expected conversion to a json object. Any idea why this is the case?

@nlohmann
Copy link
Owner

Passing an initializer list vs. passing a std::map use different basic_json constructors.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants