javax.json的奇怪行为

5
我不明白为什么这段代码的最后一行返回一个空字符串。
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());

这是输出结果:

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

我期望第二个JSON是{"test1":"test1"}。我错了吗?
问题似乎与.build()函数有关,该函数将添加到HASH_MAP的所有元素的valueMap设置为null(请参见图像)。 enter image description here 如何让HASH_MAP中的值保持不变?

尝试进行测试:将System.out.println("JSON2: " + HASH_MAP.get("one").build().toString());放置在HASH_MAP.put("one", one);这一行之后。 - Jesus Zavarce
这是输出结果:JSON: {"test1":"test1"} # JSON: {"l1":[{},{"test2":"test2"}],"otherParam":"value2"} # JSON: {} - user72708
3个回答

5

使用JsonObjectBuilder构建JsonObject后,构建器将被清空以准备重用。为了说明这一点:

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()); // {}

当您进行操作时,
l1.add(l.getValue()); // l.getValue() is (JsonObjectBuilder) one at some time

one上,build()方法被隐式地调用,因此它被清空。

然后在这里:

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

您需要构建一个空的JsonObject对象。

为了解决这个问题,您可以将JsonObjects存储在哈希映射中,而不是JsonObjectBuilders:

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());

现在它应该按照你期望的方式工作。

3
请记住,调用build()将刷新存储在您的对象one JSonObjectBuilder中的值,因此您只能调用一次build()方法。如果您再次调用它,您将得到一个空的JSonObject表示。例如:
one.add("test1","test1");   
System.out.println(one.build())
System.out.println(one.build())

输出结果:

{"test1":"test1"}
{}

如果你真的想再次调用它,你需要再次添加你想要的值。例如:

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

输出结果:

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

正如@Ctx所说,您可以在地图中放置JsonObjects而不是JsonObjectBuilders,因此将方法build()的调用返回的JsonObject作为地图值。

例如:

HASH_MAP.put("one", one.build());

0

如已经回答,JsonObjectBuilder提供的实现在调用build()时会刷新。

最好的解决方案是基于JsonObjectBuilder接口实现自己的非刷新构建器:

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.
    }
}

整篇文章在这里:http://www.amihaiemil.com/2017/06/14/non-flushable-jsonobjectbuilder.html

强烈建议将整个解决方案带到这里,以免链接失效。 - yakobom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接