Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/356.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用GSON修改json而不使用POJO_Java_Json_Gson - Fatal编程技术网

Java 使用GSON修改json而不使用POJO

Java 使用GSON修改json而不使用POJO,java,json,gson,Java,Json,Gson,我想修改json内容而不将其转换为POJO。我正在使用GSON图书馆 以下是用例: String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]"; JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class); 是否有任何方法可以在每个数组中将key1的值设置为某

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

以下是用例:

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

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

是否有任何方法可以在每个数组中将key1的值设置为某个值(比如说“Test”),而无需将内容转换为POJO

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


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

Gson有两个单独的API(可以组合):一个用于序列化和反序列化,另一个用于流式处理。如果希望在不增加内存开销的情况下处理JSON流,或者使用动态结构(而不是静态POJO),可以执行以下操作:

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(在我的示例中,我使用StringWriter)
  • 创建一个JsonReader
  • 创建一个循环,使用来自读者的事件并将其提供给作者,可能进行更改、添加、省略等
循环将由一个switch语句组成,该语句必须包含所有可能事件(其中10个)的case。即使是最简单的示例也必须包含所有这些代码,因此下面的代码看起来相当冗长。但它很容易扩展,进一步扩展不会使它变得更长

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

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

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

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

当然,Java中的字符串是不可变的,因此首先将其转换为StringBuilder可能会在内存使用方面给您带来更好的性能。

您总是可以获得不同于JsonElement的类型,或者使用JsonElement.getAsJsonObject强制转换为对象(如果可能)


我之前错了;似乎没有JsonArray适配器;您必须获得一个JsonElement并使用铸造工具。

这是我想出的最短的

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

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

使用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);
    }
}

在测试代码中,这是一个不错的黑客策略,但如果原始或字符串或替换项由用户提供,则在生产中要小心。JavaScript(以及扩展的JSON)在处理转义和特殊字符方面相当复杂。您可能想让一个经过良好测试的库在生产中编辑JSON。可能您的问题搞错了。我感兴趣的是修改key1的值,而不是key1本身。在第一种情况下,key1的值是Hello,我想修改它;这只是一个必须改变的例子。我认为,进一步讨论没有意义。如果你的答案保持不变,那么我无法管理动态值,它可以是任何东西,而我不知道用什么和什么时间替换什么。这是个坏主意。非常糟糕的主意。你将如何将JSON转换为Map?这是JsonWriter可以做的很好的例子,这是肯定的。但是对于OP的任务,没有理由通过流而不是使用经过良好测试的gson.fromJson()来重新创建JSON对象。看看杰夫的回答。@teejay:“没有理由”?你怎么知道?为什么会有这样的评论?我可以找到一些很好的理由,不构建一个任意大的JSON文档的完整内存表示,而只是为了添加一些属性,比如说,将整个内容序列化回一个文件。我们都不知道问题的来龙去脉,所以streamish和domish两种方法似乎都更好。好吧,我假设提交到这个页面的人想要解决他们的问题——即从他们已经完全可用的字符串修改JSON(=没有理由流式处理)。你的答案“有效”,但在另一种情况下更合适。无意冒犯:)@teejay:我知道你是“人民”的声音?从作者的脑海中读出问题的确切背景?那么,在这种情况下,我很抱歉写了这样一个答案,不会再发生了。但请允许我为自己辩护:在我居住的陌生地方,Java应用程序主要使用JSON与外部系统通信,使用网络或文件。我使用的java.io和javax.servlet包的奇特版本中包含一些方法,这些方法使数据以字符串形式弹出到内存中,这迫使我使用流。我真的,真的以为我不是一个人。我知道你是流媒体的人:)我们只是“默认”假设不同的上下文,没关系。只是想知道这种方法的缺点是什么。。你在表现上有过问题吗?还是输出JSON无效?你有单元测试吗?迁移到较新的GSON版本怎么样,至少有一点未来的证据吗?请发布完整的解决方案,我不明白GSON对象是如何创建的?请投票支持阵列解决方案。请在您的答案中更新循环。