Proper and clean way to declare, init and destroy a Json object.

2,031 views
Skip to first unread message

Frederic

unread,
Sep 8, 2014, 4:19:19 AM9/8/14
to jansso...@googlegroups.com
Hi,
I'm new to the Jansson Library, and I'd like some enlightenments. Let's say I want to declare, init and cleanly destroy this JSON object : 

{
 
"anObject" : {
   
"aSubObject" : {
     
"anInt" : 12,
   
}
 
}
}


I would write it that way : 

json_t * root = NULL;
if ((root = json_object()) == NULL) {
  perror
("json_object");
 
return -1;
}

json_t
* anObject = NULL;
if ((anObject = json_object()) == NULL) {
  perror
("json_object");
  json_decref
(root);
 
return -1;
}

if (json_object_set_new(root, "anObject", anObject) < 0) {
  perror
("json_object");
  json_decref
(anObject);
  json_decref
(root);
 
return -1;
}

json_t
* aSubObject = NULL;
if ((aSubObject = json_object()) == NULL) {
  perror
("json_object");
  json_decref
(anObject);
  json_decref
(root);
 
return -1;
}

if (json_object_set_new(anObject, "aSubObject", aSubObject) < 0) {
  perror
("json_object");
  json_decref
(aSubObject);
  json_decref
(anObject);
  json_decref
(root);
 
return -1;
}

json_t
* anInt = NULL;
if ((anInt = json_integer(12)) == NULL) {
  perror
("json_object");
  json_decref
(aSubObject);
  json_decref
(anObject);
  json_decref
(root);
 
return -1;
}

if (json_object_set_new(aSubObject, "anInt", anInt) < 0) {
  perror
("json_object");
  json_decref
(anInt);
  json_decref
(aSubObject);
  json_decref
(anObject);
  json_decref
(root);
 
return -1;
}

char * myDump = json_dumps(root, JSON_INDENT(2));
printf
("%s\n", myDump);

free
(myDump);

json_decref
(anInt);
json_decref
(aSubObject);
json_decref
(anObject);
json_decref
(root);

Is that correct ? 
In the case of an object containing others objects and/or arrays, and themselves containing others objects and/or arrays, and so on, do I need to 'json_decref' all of them in order to properly clean the memory ? Or just the 'json_decref' on the root is correct ?

Thanks.
B.R.

Roman Matzutt

unread,
Sep 8, 2014, 4:42:29 AM9/8/14
to jansso...@googlegroups.com
Hi,

please excuse that I have not thoroughly read through your code as it is
utterly complicated for what you want to achieve in your example.

Nevertheless, I will try and answer your questions.
You have to distinguish two kinds of incorporating JSON objects (json_t
*) into other JSON objects.

Depending on these two kinds the reference to the JSON object being
"consumed" by the other one can either be stolen or not.
Stealing a reference means that the reference counter of the "consumed"
object is decreased immediately after performing the operation.
Therefore, you are only in need to maintain the other JSON object
thereafter (if you only created one JSON object in order to add it to
another).

For further details, see
http://jansson.readthedocs.org/en/2.6/apiref.html#reference-count.

It is worth mentioning that the function json_object_set_new that you
use to construct your object is such a function that steals the
reference to the added object. Hence, you are NOT required to free each
object in case of error. Once json_object_set_new has been called
successfully, you are not required to keep track of the added object
anymore.

You probably would like to write:

if (json_object_set_new(json_obj, "value", json_val) < 0) {
/* Error handling */
json_decref(json_val);
json_decref(json_obj);
}

But you are not required to free anything that you added successfully
before.

If you used the function json_object_set (without "_new"), you probably
are required to do just what you are doing in your code.



So far regarding the reference count. But as I stated that your code is
very complicated for what you want to achieve in your example, I will
now give you a shorter example using the function json_pack(). For
further details, see
http://jansson.readthedocs.org/en/2.6/apiref.html#building-values.

You can use json_pack() to generate a (json_t *) variable using a format
string just like in printf() as follows:

json_t *root = NULL;
root = json_pack("{s:{s:{s:i}}}",
"anObject",
"aSubObject"
"anInt",
12
);

Basically, you just give the basic structure of your object (and could
leave out some formatting symbols like colons, commas or whitespace
characters) and fill in the values. What confused me a bit in the
beginning was that you do not use constant values directly in the format
string but *only* specify types there.

I hope this helps you to get into jansson!

Kind regards,
Roman

On 09/08/2014 10:19 AM, Frederic wrote:
> Hi,
> I'm new to the Jansson Library, and I'd like some enlightenments. Let's
> say I want to declare, init and cleanly destroy this JSON object :
>
> |
> {
> "anObject":{
> "aSubObject":{
> "anInt":12,
> }
> }
> }
>
> |
>
> I would write it that way :
>
> |
> json_t *root =NULL;
> if((root =json_object())==NULL){
> perror("json_object");
> return-1;
> }
>
> json_t *anObject =NULL;
> if((anObject =json_object())==NULL){
> perror("json_object");
> json_decref(root);
> return-1;
> }
>
> if(json_object_set_new(root,"anObject",anObject)<0){
> perror("json_object");
> json_decref(anObject);
> json_decref(root);
> return-1;
> }
>
> json_t *aSubObject =NULL;
> if((aSubObject =json_object())==NULL){
> perror("json_object");
> json_decref(anObject);
> json_decref(root);
> return-1;
> }
>
> if(json_object_set_new(anObject,"aSubObject",aSubObject)<0){
> perror("json_object");
> json_decref(aSubObject);
> json_decref(anObject);
> json_decref(root);
> return-1;
> }
>
> json_t *anInt =NULL;
> if((anInt =json_integer(12))==NULL){
> perror("json_object");
> json_decref(aSubObject);
> json_decref(anObject);
> json_decref(root);
> return-1;
> }
>
> if(json_object_set_new(aSubObject,"anInt",anInt)<0){
> perror("json_object");
> json_decref(anInt);
> json_decref(aSubObject);
> json_decref(anObject);
> json_decref(root);
> return-1;
> }
>
> char*myDump =json_dumps(root,JSON_INDENT(2));
> printf("%s\n",myDump);
>
> free(myDump);
>
> json_decref(anInt);
> json_decref(aSubObject);
> json_decref(anObject);
> json_decref(root);
> |
>
> Is that correct ?
> In the case of an object containing others objects and/or arrays, and
> themselves containing others objects and/or arrays, and so on, do I need
> to 'json_decref' all of them in order to properly clean the memory ? Or
> just the 'json_decref' on the root is correct ?
>
> Thanks.
> B.R.
>
> --
> --
> Jansson users mailing list
> jansso...@googlegroups.com
> http://groups.google.com/group/jansson-users
> ---
> You received this message because you are subscribed to the Google
> Groups "Jansson users" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to jansson-user...@googlegroups.com
> <mailto:jansson-user...@googlegroups.com>.
> For more options, visit https://groups.google.com/d/optout.

Frederic

unread,
Sep 8, 2014, 6:00:20 AM9/8/14
to jansso...@googlegroups.com, roman....@rwth-aachen.de
Ok, I understand now, thanks.
And yes, the 'json_pack' is much easier. 
By the way, how could I fill an array object through a for loop, using the 'json_pack' ?

Roman Matzutt

unread,
Sep 8, 2014, 8:31:26 AM9/8/14
to Frederic, jansso...@googlegroups.com
Hi,
I think that this is not possible, although you can use json_pack() in
order to pack a "pre-constructed" array into a potentially complicated
JSON object.

You will probably create two JSON objects and incorporate the array into
the larger object:


// Create JSON array [0, 1, 2, ..., 9] and add to another object

json_t *root = NULL;
json_t *array = json_array();
int i;

for (i = 0; i < 10; i++) {
json_array_append_new(array, json_integer(i));
// Note: Since I use json_array_append_new(), no json_decref() is
// needed.
}

root = json_pack("{ssso}",
"description",
"This object contains an array of small integers",
"integer_array",
array
);

Using this code snippet, you generate the following JSON object:

{
"description":"This object contains an array of small integers",
"integer_array":[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
}

Note that I left out auxiliary colons and commas in the format string of
json_pack() this time, but you could also use "{s:s,s:o}".

Using "o" in the format string tells jansson that you want to place
another json_t at this point and that the reference to that variable
should be stolen, i.e., you don't need to worry about json_decref() again.

If you explicitly want to keep the reference to the consumed object, use
"O" instead (upper-case "o").

Additionally, you can use "[]" in the format string if you know how your
array must look like:

array = json_pack("[iiiiiiiiii]", 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);

But I think this is not valuable when considering potential dynamic arrays.

Best regards,
Roman

Frederic

unread,
Sep 8, 2014, 3:57:37 PM9/8/14
to jansso...@googlegroups.com, nou...@gmail.com, roman....@rwth-aachen.de
All right, I got it now,
Thank you very much Roman !

Sunil Kay

unread,
May 18, 2016, 1:35:09 PM5/18/16
to Jansson users, roman....@rwth-aachen.de
Hi Roman

At the risk of sounding repetitive, I want to clarify a point.

In the OP's example, is it necessary to call json_decref on every individual member/submember of the root?
Would it work if the decref is called on the root? Does the cleanup then happen recursively for all members who reach the reference count of zero after a decrement?


Petri Lehtinen

unread,
May 19, 2016, 12:02:38 AM5/19/16
to jansso...@googlegroups.com
You should only call json_decref() on the root value. Objects and
arrays manage the reference count of their children, so the cleanup
happens recursively.

Petri
signature.asc
Reply all
Reply to author
Forward
0 new messages