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

Suggest to add cJSONmapper to convert json to struct and struct to json directly #910

Open
coveyjorjet opened this issue Dec 9, 2024 · 5 comments

Comments

@coveyjorjet
Copy link

I would like to push my modification which includes Direct Conversion of json to c struct or struct to json.

Can someone suggest what t do add a new .h file cJSONmapper.h or Just append to cJSON.h with new function cJSON_J2C and or cJSON_c2J

@imaami
Copy link

imaami commented Jan 21, 2025

How do you plan to convert C structs exactly?

@pyorokun7
Copy link

I could envision a function where, given the JSON, a void pointer to a structure and a secondary JSON mapping name-value pairs to struct fields, it could go back and forth.

Probably a lot of coding and even more lots of case edges, but it might work, at least for plain structures/JSONs

@imaami
Copy link

imaami commented Jan 22, 2025

I could envision a function where, given the JSON, a void pointer to a structure and a secondary JSON mapping name-value pairs to struct fields, it could go back and forth.

Probably a lot of coding and even more lots of case edges, but it might work, at least for plain structures/JSONs

The problem in converting structs to JSON is that you can't do it at runtime. You can read out struct fields if you know the offset and type of each field, but even then it's pretty much yikes territory. But I'm not sure I even understood what your intention is.

The other way around is much less hairy: just print out C source code. There are various things that might come as a surprise even then, but at least it's doable at runtime.

If I had to implement an actual runtime mechanism for serializing in-memory C structs to JSON, I'd probably use something like libgccjit. But if you want to tell me more about your idea please do, my intent here isn't to shoot it down.

@coveyjorjet
Copy link
Author

I could envision a function where, given the JSON, a void pointer to a structure and a secondary JSON mapping name-value pairs to struct fields, it could go back and forth.
Probably a lot of coding and even more lots of case edges, but it might work, at least for plain structures/JSONs

The problem in converting structs to JSON is that you can't do it at runtime. You can read out struct fields if you know the offset and type of each field, but even then it's pretty much yikes territory. But I'm not sure I even understood what your intention is.

The other way around is much less hairy: just print out C source code. There are various things that might come as a surprise even then, but at least it's doable at runtime.

If I had to implement an actual runtime mechanism for serializing in-memory C structs to JSON, I'd probably use something like libgccjit. But if you want to tell me more about your idea please do, my intent here isn't to shoot it down.

Yes you are correct one way is to let cJSON know the offset of a struct it's type etc.
Although this is a lot for a user and will not be widely used it might be helpful for those in embedded systems using cJSON, Like us.
I used this technique in one of my project in a company I currently work and I must say this is so helpful and easier to understand.

Assume that there is a Json Products.json which contains

{
    "id": 1,
    "name": "Product A",
    "price": 99.99,
    "details": {
        "manufacturer": "Company X",
        "stock": 100
    },
    "tags": ["electronics", "sale"]
}

In this case We can implement a Filed mapping fo users to map it's respective members first like this,

typedef struct {
    char manufacturer[50];
    int stock;
} Details;

typedef struct {
    int id;
    char name[50];
    double price;
    Details details;
    char tags[5][20];
    int tag_count;
} Product;

FieldMapping details_fields[] = {
    {"manufacturer", FIELD_STRING, offsetof(Details, manufacturer), 0, NULL},
    {"stock", FIELD_INT, offsetof(Details, stock), 0, NULL}
};

FieldMapping product_fields[] = {
    {"id", FIELD_INT, offsetof(Product, id), 0, NULL},
    {"name", FIELD_STRING, offsetof(Product, name), 0, NULL},
    {"price", FIELD_DOUBLE, offsetof(Product, price), 0, NULL},
    {"details", FIELD_STRUCT, offsetof(Product, details), 0, details_fields},
    {"tags", FIELD_ARRAY, offsetof(Product, tags), 5, NULL},
    {"tag_count", FIELD_INT, offsetof(Product, tag_count), 0, NULL}
};

StructMapping product_mapping = {
    "Product",
    product_fields,
    sizeof(product_fields) / sizeof(FieldMapping)
};

So the usage will be like this

Product product;
cJSON *json = cJSON_Parse(json_string);

// Deserialize JSON to struct
json_to_struct(json, &product, &product_mapping);

// Serialize struct back to JSON
cJSON *new_json = struct_to_json(&product, &product_mapping);
char *serialized = cJSON_Print(new_json);

printf("Serialized JSON:\n%s\n", serialized);

// Free memory
cJSON_Delete(json);
cJSON_Delete(new_json);
free(serialized);

Now, what is the problem? Handling nested structs and arrays increases complexity. Users must define recursive mappings for nested structs and manage array sizes manually. Memory constraints in embedded systems add to this challenge, especially with dynamic allocations.

Possible Solutions:

  1. Automate Field Mapping: Provide tools to auto-generate mappings from JSON schemas or structs.

  2. Fallback Mode: Include dynamic parsing for users who prefer not to define mappings, trading off some performance.

  3. Optimized Array Handling: Offer utility functions for fixed-size arrays with error handling for overflows.

  4. Error Reporting: Add robust checks for mismatched fields and unsupported types.

This balances flexibility and performance while keeping the library embedded-friendly.

Personally I can code the implementation in my custom .h and .c file in my app/daemon but it is a plus for cJSON to include this. Anyways if you all thought this is unnecessary you can close this issue and move on. Cheers😊

@imaami
Copy link

imaami commented Jan 25, 2025

I can't speak on behalf of the cJSON project about whether or not this should be closed or pursued. But it's an interesting subject.

What are the definitions of FieldMapping and StructMapping?

Btw, any reason you're using fixed-length arrays instead of a string pointer or a pointer wrapper? Something like:

struct str {
	char   *ptr;
	size_t  len;
};

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

No branches or pull requests

3 participants