Gson JsonObject复制值影响了其他JsonObject实例

时间:2015-04-22 01:34:21

标签: java gson

我对gson有一些奇怪的问题(我的gson版本是2.3.1) 我有一个名为jsonObject的JsonObject实例(JsonObject jsonObject) jsonObject有值,不是空的 我创建另一个,JsonObject tempOject = jsonObject; 所以,当我尝试删除tempObject中的元素时,让我们说, tempObject.remove("的子&#34);

然后该代码影响了jsonObject实例。

以下是代码段:

jsonObject              = element.getAsJsonObject();
        JsonElement tempElement = element;
        JsonObject tempObject   = jsonObject;
        String tempJson;

        if(tempObject.has("children")){
            tempObject.remove("children");
            tempJson = tempObject.toString();
            tempElement = new JsonParser().parse(tempJson);
        }

        if(nodes.isEmpty()){
            elements = new ArrayList<>();
            nodes.put(iterator, elements);
        }
        if(!nodes.containsKey(iterator)){
            elements = new ArrayList<>();
            nodes.put(iterator, elements);
        }
        nodes.get(iterator).add(tempElement);

        if (jsonObject.has("children")){
            tempNextJson        = jsonObject.get("children").toString();
            tempCurrJson        = jsonObject.toString();

            tempIterator++;
            metaDataProcessor(tempNextJson, tempCurrJson, tempNextJson, tempIterator, maxLevel);
        }

我已经阅读了gson JsonObject类,它使用了深层复制方法。因为JsonObject使用深度值复制,所以不应该影响引用,因此返回的JsonObject对象是新的。

但为什么会这样呢?

无论如何...... JsonObject类中有deepCopy方法

JsonObject deepCopy() {
    JsonObject result = new JsonObject();
    Iterator i$ = this.members.entrySet().iterator();

    while(i$.hasNext()) {
        Entry entry = (Entry)i$.next();
        result.add((String)entry.getKey(), ((JsonElement)entry.getValue()).deepCopy());
    }

    return result;
}

但那是JsonElement类中的一个抽象方法,它在JsonObject上实现,并且该属性未设置为public,因此我无法调用该方法。但我猜这种方法应该在我进行实例复制时直接调用。

那怎么样?

提前致谢

5 个答案:

答案 0 :(得分:12)

这可以用来复制任何类型的任何对象! 只需要使用Gson。

public <T> T deepCopy(T object, Class<T> type) {
    try {
        Gson gson = new Gson();
        return gson.fromJson(gson.toJson(object, type), type);
    } catch (Exception e) {
        e.printStackTrace();
        return null;
    }
}

在你的情况下,你可以这样称呼:

JsonObject jsonObject = deepCopy(oldJsonObject, JsonObject.class);

答案 1 :(得分:3)

从版本2.8.2开始,Gson deepCopy()中的JsonElement是公共的,因此您现在可以使用它来制作JSON对象的深层副本。

答案 2 :(得分:1)

看起来Gson开发人员决定不公开deepCopy()。您可以将JsonElement此序列化为字符串并返回,但是,我认为在JsonObject之外实施深度克隆效率要高得多。这是我的解决方案:

@Nonnull
public static JsonObject deepCopy(@Nonnull JsonObject jsonObject) {
    JsonObject result = new JsonObject();
    for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
        result.add(entry.getKey(), deepCopy(entry.getValue()));
    }
    return result;
}

@Nonnull
public static JsonArray deepCopy(@Nonnull JsonArray jsonArray) {
    JsonArray result = new JsonArray();
    for (JsonElement e : jsonArray) {
        result.add(deepCopy(e));
    }
    return result;
}

@Nonnull
public static JsonElement deepCopy(@Nonnull JsonElement jsonElement) {
    if (jsonElement.isJsonPrimitive() || jsonElement.isJsonNull()) {
        return jsonElement;       // these are immutables anyway
    } else if (jsonElement.isJsonObject()) {
        return deepCopy(jsonElement.getAsJsonObject());
    } else if (jsonElement.isJsonArray()) {
        return deepCopy(jsonElement.getAsJsonArray());
    } else {
        throw new UnsupportedOperationException("Unsupported element: " + jsonElement);
    }
}

答案 3 :(得分:0)

设置tempObject = jsonObject不会为您创建第二个对象。所做的只是创建对原始jsonObject的另一个引用。

你想要做的是:

JSONObject tempObject = new JSONObject(jsonObject.toString());
tempObject.remove("children");

这将创建一个 new JsonObject,它是原始json的副本。


如果只能使用GSON库,则有JsonObject.deepyCopy()方法。这是在r855中添加的:https://code.google.com/p/google-gson/source/detail?r=855

使用deepCopy()方法,它将是

JsonObject tempObject = jsonObject.deepCopy();
tempObject.remove("children");

答案 4 :(得分:0)

我找到了最简单的解决方案。由于JsonObject中的deepCopy()方法似乎不起作用,所以我只是从JsonObject值转换为string,然后使用JsonParser()转换为JsonElement。 然后从我们的新JsonObject中创建一些新的JsonObject。看起来更简单,而不是创建一些需要重新实现deepCopy的辅助方法。如果我们重新实现迭代,必须考虑JsonObject的深度。由于JsonObject是hashmap(LinkedTreeMap),并且值是JsonElement,因此需要通过JsonElement递归解析。