Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

javax.json strange behavior

Tags:

java

json

I don't understand why the last row of this code return a empty string.

Map<String, JsonObjectBuilder> HASH_MAP = new HashMap<>();

JsonObjectBuilder one = Json.createObjectBuilder();
one.add("test1","test1");
HASH_MAP.put("one", one);

JsonObjectBuilder two = Json.createObjectBuilder();
two.add("test2","test2");
HASH_MAP.put("two", two);

JsonObjectBuilder toReturn = Json.createObjectBuilder();
JsonArrayBuilder l1 = Json.createArrayBuilder();
for (Map.Entry<String, JsonObjectBuilder> l : HASH_MAP.entrySet()) {
    l1.add(l.getValue());
}

toReturn.add("l1", l1);
toReturn.add("otherParam", "value2");
String strJSON = toReturn.build().toString();
System.out.println("JSON1: " + strJSON);
System.out.println("JSON2: " + HASH_MAP.get("one").build().toString());

This is the output:

Info:   JSON1: {"l1":[{"test1":"test1"},{"test2":"test2"}],"otherParam":"value2"}
Info:   JSON2: {}

I am espetting that the second JSON is {"test1":"test1"}. I am wrong?
The problem seems to be link with the .build() function that sets all the valueMap of elements added to the HASH_MAP to null (see the image). enter image description here

How can I leave the value inside the HASH_MAP untouched?

like image 570
user72708 Avatar asked Feb 03 '16 20:02

user72708


2 Answers

After build()ing a JsonObject from a JsonObjectBuilder the builder is cleared to be ready for reuse. To illustrate this:

JsonObjectBuilder b = Json.createObjectBuilder();
b.add("foo", "bar");
JsonObject o = b.build();
JsonObject p = b.build();
System.out.println(o.toString()); // {"foo":"bar"}
System.out.println(p.toString()); // {}

When you do

l1.add(l.getValue()); // l.getValue() is (JsonObjectBuilder) one at some time

build() is called implicitly on one, hence it is emptied.

Then here:

System.out.println("JSON2: " + HASH_MAP.get("one").build().toString());

you build the representation of an empty JsonObject.

To migitate this, you could for example store JsonObjects instead of JsonObjectBuilders in your hashmap:

Map<String, JsonObject> HASH_MAP = new HashMap<>();

JsonObjectBuilder one = Json.createObjectBuilder();
one.add("test1","test1");
HASH_MAP.put("one", one.build());

JsonObjectBuilder two = Json.createObjectBuilder();
two.add("test2","test2");
HASH_MAP.put("two", two.build());

JsonObjectBuilder toReturn = Json.createObjectBuilder();
JsonArrayBuilder l1 = Json.createArrayBuilder();
for (Map.Entry<String, JsonObject> l : HASH_MAP.entrySet()) {
    l1.add(l.getValue());
}

toReturn.add("l1", l1);
toReturn.add("otherParam", "value2");
String strJSON = toReturn.build().toString();
System.out.println("JSON1: " + strJSON);
System.out.println("JSON2: " + HASH_MAP.get("one").toString());

Now it should work as you expect.

like image 125
Ctx Avatar answered Oct 20 '22 21:10

Ctx


Keep in mind that the call to build() flush the value stored in your object one JSonObjectBuilder, so you can call only one time the method build(), If you call it again you go to have the representation of an empty JSonObject. Ex:

one.add("test1","test1");   
System.out.println(one.build())
System.out.println(one.build())

the output:

{"test1":"test1"}
{}

If you really want to call it again, you have to add again the value that you want. Ex:

one.add("test1","test1");
System.out.println(one.build())
one.add("test1","test1")
System.out.println(one.build())

the output:

{"test1":"test1"}
{"test1":"test1"}

As @Ctx says, you could put in your map JsonObjects instead of JsonObjectBuilders, so put as value of your map the JsonObject returned by the call of the method build().

Ex:

HASH_MAP.put("one", one.build());
like image 34
Jesus Zavarce Avatar answered Oct 20 '22 23:10

Jesus Zavarce