【问题标题】:Modify json with GSON without using a POJO使用 GSON 修改 json 而不使用 POJO
【发布时间】:2013-01-24 10:46:08
【问题描述】:

我想修改 json 内容而不将其转换为 POJO。我正在使用 GSON 库。

以下是用例:

String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]";

JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class);     

有没有什么方法可以在每个数组中将 key1 的值设置为某个值(比如说“测试”),而无需将内容转换为 POJO

【问题讨论】:

    标签: java json gson


    【解决方案1】:

    这是我想出的最短的。

    JsonElement je = new Gson().fromJson(jsonString, JsonElement.class);
    JsonObject jo = je.getAsJsonObject();
    jo.add("key", value);
    

    一旦你有了 JsonObject,gson 就有很多方法来操作它。

    【讨论】:

    • 能否请您发布完整的解决方案,我不明白 gson 对象是如何创建的?
    【解决方案2】:

    您始终可以获取与 JsonElement 不同的类型,或使用 JsonElement.getAsJsonObject 强制转换为 Object(如果可能)。

    String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"}, ...]";
    
    JsonArray jsonArray = gson.fromJson(jsonString, JsonElement.class).getAsJsonArray();
    JsonObject firstObject = jsonArray.get(i).getAsJsonObject();
    firstObject.addProperty("key1", "Test");
    

    我之前错了;似乎没有 JsonArray 适配器;你必须得到一个 JsonElement 并使用转换工具。

    【讨论】:

    • 支持阵列解决方案。请同时更新答案中的循环。
    【解决方案3】:

    一种方法是将 JSON 转换为 java.util.Map,修改 Map,然后从那里开始(这可能意味着将 Map 序列化回 JSON)。

    这种方法符合我的偏好,即使用正确的 API 来完成正确的工作,最大限度地减少使用 Gson 等工具来处理序列化/反序列化(我理解它的设计目的)。也就是说,不使用 Gson API 作为替代数据结构。

    【讨论】:

    • 如何将 JSON 转换为 Map?
    【解决方案4】:

    GSON 有两个独立的 API(可以组合使用):一个用于序列化和反序列化,另一个用于流式传输。如果您想在没有内存开销或使用动态结构(而不​​是静态 POJO)的情况下处理 JSON 流,您可以执行以下操作:

    • 创建一个 JsonWriter(在我的示例中我使用 StringWriter);
    • 创建一个 JsonReader;
    • 创建一个循环,使用来自阅读器的事件并将它们提供给编写器,可能会进行更改、添加、省略等。

    循环将包含一个 switch 语句,该语句必须包含所有可能的事件(其中 10 个)。即使是最简单的示例也必须包含所有这些,因此下面的代码看起来相当冗长。但它很容易扩展,进一步的扩展不会让它变得更长。

    将“test”附加到每个对象的示例如下所示:

    public class Whatever {
    
    static void streamandmodify(JsonReader reader, JsonWriter writer) throws IOException {
        while (true) {
            JsonToken token = reader.peek();
            switch (token) {
            // most cases are just consume the event
            // and pass an identical one to the writer
            case BEGIN_ARRAY:
                reader.beginArray();
                writer.beginArray();
                break;
            case END_ARRAY:
                reader.endArray();
                writer.endArray();
                break;
            case BEGIN_OBJECT:
                reader.beginObject();
                writer.beginObject();
    
                // this is where the change happens:
                writer.name("test");
                writer.value(1);
                break;
            case END_OBJECT:
                reader.endObject();
                writer.endObject();
                break;
            case NAME:
                String name = reader.nextName();
                writer.name(name);
                break;
            case STRING:
                String s = reader.nextString();
                writer.value(s);
                break;
            case NUMBER:
                String n = reader.nextString();
                writer.value(new BigDecimal(n));
                break;
            case BOOLEAN:
                boolean b = reader.nextBoolean();
                writer.value(b);
                break;
            case NULL:
                reader.nextNull();
                writer.nullValue();
                break;
            case END_DOCUMENT:
                return;
            }
        }
    }
    
    
    public static void main(String[] args) throws IOException {
        // just for test:
        JsonReader jr = new JsonReader(new StringReader("{\"a\":1, \"b\":{\"c\":[1,2,3,{},{}]}}"));
        StringWriter sw = new StringWriter();
        JsonWriter jw = new JsonWriter(sw);
        streamandmodify(jr, jw);
        System.out.println(sw.getBuffer().toString());
    }
    }
    

    【讨论】:

    • JsonWriter 可以做的很好的例子,这是肯定的。但是对于 OP 的任务,没有理由通过流式传输而不是使用经过充分测试的 gson.fromJson() 来重新创建 JSON 对象。请参阅 Jeff 的回答。
    • @teejay:“没有理由”?你怎么知道的?为什么会有这样的评论?我可以找到一些很好的理由,不为任意大的 JSON 文档构建整个内存表示,只是为了添加一些属性,例如,将整个内容序列化回文件。我们都不知道这个问题的背景,所以流式和粗暴的方法似乎都可能更好。
    • 好吧,我假设访问此页面的人想要解决他们的问题 - 即从他们已经完全可用的字符串修改 JSON(= 没有理由进行流式传输)。您的回答“有效”,但在另一种情况下会更合适。没有冒犯:)
    • @teejay:我知道你是“人民”的声音?并以某种方式从作者的脑海中读取问题的确切上下文?好吧,在这种情况下 - 我很抱歉写了这样的答案,它不会再发生了。但请允许我为自己辩护:在我居住的陌生土地上,Java 应用程序主要使用 JSON 与外部系统通信,使用网络或文件。我使用的 java.io 和 javax.servlet 包的外来版本包括一些使数据仅作为字符串弹出到内存中的方法,这迫使我使用流。我真的,真的以为我并不孤单。
    • 我知道你是流媒体的人:) 我们只是假设不同的上下文“默认”,没关系。只是想知道这种方法有什么缺点......你有没有遇到过性能问题?还是输出 JSON 无效?你有单元测试过吗?迁移到较新的 GSON 版本怎么样,至少有点面向未来吗?
    【解决方案5】:

    jsonString 是一个普通的、普通的 Java 字符串;因此您可以使用 Java 的标准字符串函数随意修改它,并将子字符串 key1 替换为 Test1

    jsonString = "[{\"key1\":\"Test\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]";
    

    当然,Java 中的 String 是不可变的,因此首先将其转换为 StringBuilder 可能会在内存使用方面为您提供更好的性能。

    【讨论】:

    • 在测试代码中这是一个不错的策略,但如果原始或字符串或替换是用户提供的,则在生产中要小心。 JavaScript(和扩展的 JSON)在处理转义和特殊字符方面非常复杂。您可能希望让一个经过良好测试的库在生产环境中编辑您的 JSON。
    • 可能你的问题弄错了。我有兴趣修改 key1 而不是 key1 本身的值。所以在第一种情况下,key1 的值是 Hello,我想修改它。
    • 哦,答案还是一样的;这只是必须更改的示例。
    • 我认为,没有必要进一步讨论。如果您的答案保持不变,那么我无法管理动态值,它可以是任何东西,而我不知道用什么和何时替换什么。
    • 这是个坏主意。非常糟糕的主意。
    【解决方案6】:

    使用 GSON JsonArray Java 8 修改 json

    如何使用 GSON 修改 JSON 中的值的示例

    import com.google.gson.Gson;
    import com.google.gson.JsonArray;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonObject;
    
    public class ModifyJson {
        public static void main(String[] args) {
            String data = "[{\"ct_pk\":24,\"ct_name\":\"SISTEMA DE PRUEBAS\"},"
                    + "{\"ct_pk\":1,\"ct_name\":\"CAPITAL FEDERAL\"}," +
                    "{\"ct_pk\":5,\"ct_name\":\"SISTEMA DE PRUEBAS DOS\"}]";
    
            System.out.println("before................." + data);
    
            JsonArray jsonArray = new Gson().fromJson(data, JsonElement.class).getAsJsonArray();
            JsonArray jsonArray2 = new JsonArray();
            for (JsonElement pa : jsonArray) {
                JsonObject jsonObject2 = pa.getAsJsonObject();
                String ct_name = jsonObject2.get("ct_name").getAsString();
                if (ct_name.equals("SISTEMA DE PRUEBAS")) {
                    jsonObject2.addProperty("ct_name", "TODOS");
                }
                jsonArray2.add(jsonObject2);
            }
            System.out.println("after.................." +jsonArray2);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 1970-01-01
      • 2011-04-26
      • 2012-02-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多