Javax.json weird behavior

I do not understand why the last line of this code returns an 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 conclusion:

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

I submit that the second JSON is {"test1":"test1"} . Am I mistaken? It seems that the problem is with the .build() function, which sets the entire valueMap of the elements added in HASH_MAP to null (see image). enter image description here

How can I leave the value inside the HASH_MAP untouched?

+5
source share
3 answers

After build() with JsonObject from JsonObjectBuilder builder will be cleaned up 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 , so it will be empty.

Then here:

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

you are creating a view of an empty JsonObject .

To perform a migration, you can, for example, store JsonObjects instead of JsonObjectBuilders in your hash file:

 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.

+4
source

Keep in mind that calling build() resets the value stored in your one JSonObjectBuilder, so you can only call the build () method once. If you call it again, you get a view of an empty JSonObject . Example:

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

output:

 {"test1":"test1"} {} 

If you really want to call it again, you need to add the value you want again. Example:

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

output:

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

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

Example:

 HASH_MAP.put("one", one.build()); 
+3
source

As already mentioned, the provided implementation of JsonObjectBuilder is reset when calling build ().

The best solution is to implement your own non-flushing builder based on the JsonObjectBuilder interface:

 public final class NfJsonObjectBuider implements JsonObjectBuilder { private Map<String, Object> values = new LinkedHashMap<>(); @Override public JsonObjectBuilder add(String name, JsonValue value) { this.values.put(name, value); return this; } @Override public JsonObjectBuilder add(String name, String value) { this.values.put(name, value); return this; } @Override public JsonObjectBuilder add(String name, BigInteger value) { this.values.put(name, value); return this; } //other add(...) methods with the same implementation @Override public JsonObject build() { //HERE: reuse their building logic. final JsonObjectBuilder builder = Json.createObjectBuilder(); for(final Entry<String, Object> pair : this.values.entrySet()) { this.addToBuilder(pair, builder); } return builder.build(); } private void addToBuilder(Entry<String, Object> pair, JsonObjectBuilder builder) { if(pair.getValue() instanceof JsonValue) { builder.add(pair.getKey(), (JsonValue) pair.getValue()); } if(pair.getValue() instanceof String) { builder.add(pair.getKey(), (String) pair.getValue()); } if(pair.getValue() instanceof Boolean) { builder.add(pair.getKey(), (Boolean) pair.getValue()); } //A couuple more ifs to cover all the add(...) methods. } } 

The whole article is here: http://www.amihaiemil.com/2017/06/14/non-flushable-jsonobjectbuilder.html

0
source

Source: https://habr.com/ru/post/1242240/


All Articles