Java的核心库中没有内置JSON库。这不是一个问题,因为您可以从许多不同的第三方JSON库中进行选择。常用的库是Jackson和Gson,在这篇博客文章中,我们将看看JSON- p(用于JSON处理的Java API, JSR 374) 来自甲骨文的一个标准的JSON接口。

JSR 374指定了一个非常底层的处理库。该规范没有描述JSON和Java对象之间的数据绑定。为此,创建了第二个基于JSR 374的JSON绑定规范(JSON- b, JSR 367)。

与许多JSR一样,JSR 374只描述库必须实现的接口。对于下面的示例,我们使用Glassfish参考实现。

<dependency>
      <groupId>org.glassfish</groupId>
      <artifactId>javax.json</artifactId>
      <version>1.1.4</version>
</dependency>

JSR 374为JSON处理提供了两个model。Object Model API和Streaming API。对象模型API提供了一种使用JSON的简单方法,并将所有数据保存在内存中。流API是一种低级API,旨在高效地处理大量JSON数据。 API的主要入口点是类Json。该类提供静态方法来创建解析器、读取器、生成器和写入器。

Object Model API(对象模型API)

这个API为JSON对象和数组结构提供了不可变的对象模型。API使用构建器模式创建这些对象模型,API使用JsonReader从输入源读取JSON, JsonWriter将其写入输出源。

Write(写入)

要使用对象模型API创建JSON,您需要使用静态方法JSON.createobjectbuilder()创建JsonObjectBuilder的一个实例。 JsonObjectBuilder实例最初是空的,您需要调用add()来添加键/值对。该库为所有受支持的JSON数据类型提供add()变量。特殊的addNull()方法插入一个值为null的属性。 要创建一个数组,您需要一个JsonArrayBuilder实例,该实例由静态方法> Json.createArrayBuilder()返回。数组生成器提供add()方法来添加数组的各个条目。

package ch.rasc.jsonp;

import java.util.Map;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonWriter;
import javax.json.stream.JsonGenerator;

public class ObjectWrite {
  public static void main(String[] args) {
    JsonObject model = Json.createObjectBuilder()
        .add("id", 1234)
        .add("active", true)
        .add("name", "cmm")
        .addNull("password")
        .add("roles", Json.createArrayBuilder().add("admin").add("user").add("operator"))
        .add("phoneNumbers",
            Json.createArrayBuilder()
                .add(Json.createObjectBuilder().add("type", "mobile").add("number",
                    "111-111-1111"))
                .add(Json.createObjectBuilder().add("type", "home").add("number",
                    "222-222-2222")))
        .build();

    JsonWriter defaultWriter = Json.createWriter(System.out);
    defaultWriter.write(model);

//如果您需要一个可读的输出,您可以创建一个将PRETTY_PRINTING标志设置为on的写入器。
    Map<String, Boolean> properties = Map.of(JsonGenerator.PRETTY_PRINTING, Boolean.TRUE);
    JsonWriter customWriter = Json.createWriterFactory(properties)
        .createWriter(System.out);
    customWriter.write(model);
  }
}

整个JSON将在内存中创建,可以用JsonWriter将其写入输出流。使用静态方法Json.createWriter创建writer。默认情况下,编写器以紧凑的形式在一行中打印JSON:

JsonWriter defaultWriter = Json.createWriter(System.out);
    defaultWriter.write(model);

//{"id":1234,"active":true,"name":"cmm","password":null,"roles":["admin","user","operator"],"phoneNumbers":[{"type":"mobile","number":"111-111-1111"},{"type":"home","number":"222-222-2222"}]}

{
    "id": 1234,
    "active": true,
    "name": "cmm",
    "password": null,
    "roles": [
        "admin",
        "user",
        "operator"
    ],
    "phoneNumbers": [
        {
            "type": "mobile",
            "number": "111-111-1111"
        },
        {
            "type": "home",
            "number": "222-222-2222"
        }
    ]
}


Read(读取)

要使用对象模型API读取JSON,可以使用静态方法JSON.createreader()创建一个JsonReader实例。该方法需要InputStream或Reader作为参数。根据JSON的形式,将带有readObject()readArray()的JSON读入内存。这些方法返回一个JsonObject resp。JsonArray实例,允许访问数据。这些类提供get…()方法来检索键和数组条目的值。 JsonObject实现了Map接口,因此您可以使用从Map中知道的所有方法,例如JsonObject . keyset()来列出所有键。JsonArray是Collection、Iterable和List的子接口。 注意,如果您试图访问一个不存在的密钥,get…()方法将返回NullPointerException。为了防止这种情况发生,您可以使用containsKey()检查密钥是否存在。

package ch.rasc.jsonp;

import java.io.StringReader;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;
import javax.json.JsonValue.ValueType;

public class ObjectRead {

  public static void main(String[] args) {

    String input = "{\"id\":1234,\"active\":true,\"name\":\"cmm\",\"password\":null,\"roles\":[\"admin\",\"user\",\"operator\"],\"phoneNumbers\":[{\"type\":\"mobile\",\"number\":\"111-111-1111\"},{\"type\":\"home\",\"number\":\"222-222-2222\"}]}";

    try (JsonReader reader = Json.createReader(new StringReader(input))) {
      JsonObject root = reader.readObject();
      int id = root.getInt("id");
      boolean active = root.getBoolean("active");
      String name = root.getString("name");

      System.out.println("id: " + id);
      System.out.println("active: " + active);
      System.out.println("name: " + name);

      JsonValue password = root.get("password");
      if (password == JsonValue.NULL) {
        System.out.println("password is null");
      }

      JsonArray roles = root.getJsonArray("roles");
      for (int i = 0; i < roles.size(); i++) {
        String role = roles.getString(i);
        System.out.println("  " + role);
      }

      if (!root.containsKey("firstName")) {
        System.out.println("does not contain firstName");
      }

      // String firstName = root.getString("firstName");
      // throws NullPointerException

      JsonArray phoneNumbers = root.getJsonArray("phoneNumbers");
      for (JsonValue phoneNumber : phoneNumbers) {
        if (phoneNumber.getValueType() == ValueType.OBJECT) {
          JsonObject obj = phoneNumber.asJsonObject();
          System.out.println(obj.getString("type"));
          System.out.println(obj.getString("number"));
        }
      }
    }

  }
}

Streaming API(流)

Streaming API由JsonParser和JsonGenerator接口组成。解析器用于以流方式读取JSON,生成器用于创建JSON。

Write

要使用StreamingAPI编写JSON,您需要一个JsonGenerator实例,它是静态方法JSON.createGenerator创建。该方法需要OutputStream或Writer作为参数。正如API的名称所暗示的那样,您将以流的方式创建JSON,并且生成器将持续地写入给定的输出流或写入器。例如writeStartObject()在被调用时写入字符{和writeStartArray()写入[。 生成器为每种JSON数据类型提供重载的write()方法。如果希望创建一个值为null的键,可以使用writeNull()方法。 确保使用writeEnd()关闭每个start对象(writeStartObject)和数组(writeStartArray)。如果writeStart*和writeEnd调用的数量不匹配,生成器将抛出异常。


package ch.rasc.jsonp;

import java.util.Map;

import javax.json.Json;
import javax.json.stream.JsonGenerator;

public class StreamWrite {
  public static void main(String[] args) {

    var properties = Map.of(JsonGenerator.PRETTY_PRINTING, Boolean.FALSE);
    try (JsonGenerator jg = Json.createGeneratorFactory(properties)
        .createGenerator(System.out)) {

      jg.writeStartObject()
          .write("id", 1234)
          .write("active", true)
          .write("name", "cmm")
          .writeNull("password")
          .writeStartArray("roles")
             .write("admin")
             .write("user")
             .write("operator")
          .writeEnd()
          .writeStartArray("phoneNumbers")
             .writeStartObject()
               .write("type", "mobile")
               .write("number", "111-111-1111")
             .writeEnd()
             .writeStartObject()
               .write("type", "home")
               .write("number", "222-222-2222")
             .writeEnd()
          .writeEnd()
        .writeEnd();
    }
  }
}

Output:

{
    "id": 1234,
    "active": true,
    "name": "cmm",
    "password": null,
    "roles": [
        "admin",
        "user",
        "operator"
    ],
    "phoneNumbers": [
        {
            "type": "mobile",
            "number": "111-111-1111"
        },
        {
            "type": "home",
            "number": "222-222-2222"
        }
    ]
}


Read

要使用Streaming API读取JSON,需要使用JSON.createparser静态方法创建一个JsonParser实例。这个类需要InputStream或Reader作为参数。有了JsonParser,应用程序就可以通过JSON从一个标记转移到下一个标记。与对象模型API相反,流API不会将整个JSON读入内存,而是应用程序使用next()请求下一个令牌,或者使用skip*()跳过JSON的一部分,解析器在需要时从Reader/InputStream加载数据。 对于每个令牌,解析器返回一个描述当前令牌的Event对象。next()返回当前事件。要读取该值,然后从JsonParser对象调用get…()方法。 JsonParser还提供了skipArray()skipObject()方法,它们指示解析器跳过整个数组/对象,并将解析器推进到数组resp的末尾对象。

package ch.rasc.jsonp;

import java.io.StringReader;

import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;

public class StreamRead {
  public static void main(String[] args) {

    String input = "{\"id\":1234,\"active\":true,\"name\":\"Duke\",\"password\":null,\"roles\":[\"admin\",\"user\",\"operator\"],\"phoneNumbers\":[{\"type\":\"mobile\",\"number\":\"111-111-1111\"},{\"type\":\"home\",\"number\":\"222-222-2222\"}]}";

    try (JsonParser parser = Json.createParser(new StringReader(input))) {
      while (parser.hasNext()) {
        Event event = parser.next();

        switch (event) {
        case START_OBJECT:
          System.out.println("START_OBJECT");
          break;
        case END_OBJECT:
          System.out.println("END_OBJECT");
          break;
        case START_ARRAY:
          System.out.println("START_ARRAY");
          break;
        case END_ARRAY:
          System.out.println("END_ARRAY");
          break;
        case KEY_NAME:
          System.out.print("KEY_NAME: ");
          System.out.println(parser.getString());
          break;
        case VALUE_NUMBER:
          System.out.print("VALUE_NUMBER: ");
          System.out.println(parser.getLong());
          break;
        case VALUE_STRING:
          System.out.print("VALUE_STRING: ");
          System.out.println(parser.getString());
          break;
        case VALUE_FALSE:
          System.out.println("VALUE_FALSE");
          break;
        case VALUE_TRUE:
          System.out.println("VALUE_TRUE");
          break;
        case VALUE_NULL:
          System.out.println("VALUE_NULL");
          break;
        default:
          System.out.println("something went wrong: " + event);
          break;
        }
      }
    }

  }
}

下面的另一个例子演示了如何使用流API从JSON中读取数据。该示例从usgs.gov加载一个GeoJSON文件,其中包含了过去30天发生的地震。该程序提取每次地震的震级和位置,并将其打印到控制台。

package ch.rasc.jsonp;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

import javax.json.Json;
import javax.json.stream.JsonParser;
import javax.json.stream.JsonParser.Event;

public class StreamReadEarthquakes {
  public static void main(String[] args) throws IOException, InterruptedException {

    String url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_month.geojson";

    var client = HttpClient.newHttpClient();
    var request = HttpRequest.newBuilder().GET().uri(URI.create(url)).build();

    HttpResponse<InputStream> response = client.send(request,
        BodyHandlers.ofInputStream());

    try (JsonParser parser = Json.createParser(response.body())) {
      while (parser.hasNext()) {
        Event event = parser.next();
        if (event == Event.KEY_NAME) {
          String key = parser.getString();
          if (key.equals("mag")) {
            parser.next();
            System.out.println(parser.getBigDecimal());
          }
          else if (key.equals("place")) {
            parser.next();
            System.out.println(parser.getString());
            System.out.println();
          }
        }
      }
    }

  }
}

JSON Pointer(指针)

JSON指针是JavaScript对象表示法(JSON)指针标准的实现。 JSON指针是引用JSON对象中的元素的字符串。使用JSON指针,应用程序可以检索值,还可以修改JSON对象。 要创建指针,可以调用静态方法Json.createPointer()并将指针表达式作为参数传递,factory方法返回一个JsonPointer实例。

Read

下面的示例从usgs.gov读取地震GeoJSON文件。文件是这样的:

{
  type: "FeatureCollection",
  metadata: {
    ...
  },
  bbox: [
    ...
  ],
  features: [
    {
      type: "Feature",
      properties: {
        mag: Decimal,
        place: String,
        time: Long Integer,
        updated: Long Integer,
        ...

应用程序使用三个JSON指针访问完整的features数组,并读取数组第一个元素的大小和位置。注意,每个指针表达式都以/开头,/表示根对象。特殊的//语法可用于访问数组的第n个元素。

package ch.rasc.jsonp;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.http.HttpResponse.BodyHandlers;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonPointer;
import javax.json.JsonReader;

public class PointerGet {
  public static void main(String[] args) throws IOException, InterruptedException {
    String url = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/1.0_month.geojson";

    var client = HttpClient.newHttpClient();
    var request = HttpRequest.newBuilder().GET().uri(URI.create(url)).build();

    HttpResponse<InputStream> response = client.send(request,
        BodyHandlers.ofInputStream());

    JsonPointer allPointer = Json.createPointer("/features");
    JsonPointer magPointer = Json.createPointer("/features/0/properties/mag");
    JsonPointer placePointer = Json.createPointer("/features/0/properties/place");

    try (JsonReader reader = Json.createReader(response.body())) {
      JsonObject root = reader.readObject();

      JsonArray all = (JsonArray) allPointer.getValue(root);
      System.out.println("number of earthquakes: " + all.size());

      System.out.println(magPointer.getValue(root));
      System.out.println(placePointer.getValue(root));
    }

  }
}

Modify

JSON指针不仅可以用于检索值,应用程序还可以使用JSON指针修改JSON元素。注意:JSON指针API只与对象模型API一起工作,因为它需要访问整个JSON元素。

Add

要插入一个新的键/值对,需要创建一个指向不存在键的指针,并调用add()方法。该方法需要一个JsonObject实例和一个value对象。 下面的示例将新密钥电子邮件插入JSON元素。

package ch.rasc.jsonp;

import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonPointer;
import javax.json.JsonValue;

public class PointerOperations {

  public static void main(String[] args) {
    JsonObject jsonObject = Json.createObjectBuilder().add("id", 1234).add("active", true)
        .addNull("password").add("roles", Json.createArrayBuilder().add("admin")).build();
    System.out.println(jsonObject);
    // {"id":1234,"active":true,"password":null,"roles":["admin"]}

    // add
    JsonPointer emailPointer = Json.createPointer("/email");
    JsonObject modifiedJsonObject = emailPointer.add(jsonObject,
        Json.createValue("test@test.com"));
    System.out.println(modifiedJsonObject);
    // {"id":1234,"active":true,"password":null,"roles":["admin"],"email":"test@test.com"}

   //要删除键,请创建指向现有键的指针并调用remove()。
    // remove
    JsonPointer passwordPointer = Json.createPointer("/password");
    modifiedJsonObject = passwordPointer.remove(jsonObject);
    System.out.println(modifiedJsonObject);
    // {"id":1234,"active":true,"roles":["admin"]}
     //若要替换值,请调用replace()并将新值作为第二个参数传递。
    // replace
    JsonPointer activePointer = Json.createPointer("/active");
    modifiedJsonObject = activePointer.replace(jsonObject, JsonValue.FALSE);
    System.out.println(modifiedJsonObject);
    // {"id":1234,"active":false,"password":null,"roles":["admin"]}

//JSON指针API提供containsValue()方法来检查指针表达式是否指向JSON元素中存在的键
    // containsValue
    System.out.println(activePointer.containsValue(jsonObject));

    JsonPointer lastNamePointer = Json.createPointer("/lastName");
    if (!lastNamePointer.containsValue(jsonObject)) {
      System.out.println("lastName does not exist");
    }

//向数组添加值
//对于向数组添加元素,API支持特殊的-语法。负号表示一个元素应该被推到数组的末尾。
//下面的代码将dev添加到现有数组中。如果没有-语法,则需要重复所有现有的数组元素。如果不这样做,add()方法将覆盖现有数组值。
//使用特殊的/roles/-指针,您只需要指定新值并add()将新元素插入数组的末尾。
    // Arrays
    JsonPointer rolesPointer = Json.createPointer("/roles");
    modifiedJsonObject = rolesPointer.add(jsonObject,
        Json.createArrayBuilder().add("admin").add("dev").build());
    System.out.println(modifiedJsonObject);
    // {"id":1234,"active":true,"password":null,"roles":["admin","dev"]}

    JsonPointer addRolesPointer = Json.createPointer("/roles/-");
    modifiedJsonObject = addRolesPointer.add(jsonObject, Json.createValue("dev"));
    System.out.println(modifiedJsonObject);
    // {"id":1234,"active":true,"password":null,"roles":["admin","dev"]}
  }

}

JSON Merge Patch(更新部分资源的部分数据)

JSON Merge Patch是更新部分资源的部分数据标准的实现。 merge patch是描述两个JSON元素之间差异的一种方法。JSON Merge patch本身就是一个JSON元素。它可以用于在两个或多个参与方之间保持两个JSON元素的同步。用于交换大型JSON对象。应用程序可以创建一个合并补丁并将其发送给其他方,而不是在每次发生更改时发送整个对象。然后,接收方将merge补丁应用到其版本的JSON元素中,并得到与源对象相同的最新JSON元素。 JSON Merge Patch只适用于对象模型API。要创建一个Merge Patch,您可以调用方法Json.createMergeDiff(),并将源对象和目标对象作为参数传递。 下面的示例从元素中删除活动键,并向roles数组添加一个新值。

package ch.rasc.jsonp;

import java.io.StringReader;

import javax.json.Json;
import javax.json.JsonMergePatch;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.JsonValue;

public class Merge {

  public static void main(String[] args) {
    JsonObject source = Json.createObjectBuilder().add("id", 1234).add("active", true)
        .add("roles", Json.createArrayBuilder().add("admin")).build();
    System.out.println(source);
    // {"id":1234,"active":true,"roles":["admin"]}

    JsonObject target = Json.createObjectBuilder().add("id", 1234)
        .add("roles", Json.createArrayBuilder().add("admin").add("dev")).build();
    System.out.println(target);
    // {"id":1234,"roles":["admin","dev"]}

    JsonMergePatch mergePatch = Json.createMergeDiff(source, target);
    System.out.println(mergePatch.toJsonValue());
    // {"active":null,"roles":["admin","dev"]}

//还可以使用JSON . createmergepatch()从JSON字符串创建合并资源。
    try (JsonReader reader = Json.createReader(
        new StringReader("{\"active\":null,\"roles\":[\"admin\",\"dev\"]}"))) {
      JsonMergePatch createdMergePatch = Json.createMergePatch(reader.readValue());

      JsonValue modifiedSource = createdMergePatch.apply(source);
      System.out.println(modifiedSource);
      // {"id":1234,"roles":["admin","dev"]}
    }

  }

}

想要要应用合并资源数据,可以调用JsonMergePatch实例的apply()方法。该方法期望JSON对象并返回更改后的元素。

Shortcomings(缺点)

在上面的例子中,我们看到了merge patch对象{"active":null,"roles":["admin","dev"]},它描述了两个JSON对象之间的区别:

  • Source: {"id":1234,"active":true,"roles":["admin"]}
  • Target: {"id":1234,"roles":["admin","dev"]} 这揭示了JSON Merge Patch格式的一些缺点。 特殊的空值用于删除键/值对,因此无法将键设置为空值。 另一个缺点是合并参数不能描述数组操作。如果应用程序添加、删除或更改数组的元素,则合并参数必须包含整个数组。在上面的示例中,我们只向roles数组添加了dev,但是合并补丁必须在合并补丁中包含整个数组的内容。如果在包含数百或数千个元素的数组中添加或删除一个元素,情况会更糟。 另一个问题是应用合并参数不会导致错误。任何奇怪的参数都将被合并。

JSON Patch

JSON Patch是JavaScript对象符号(JSON)Patch 标准的实现。 与JSON Merge Patch一样,JSON Patch也是描述两个JSON对象之间变化的标准。JSON Patch通过在源对象中列出应用于目标JSON对象的操作数组来实现这一点。 JSON Patch本身就是这样一个JSON对象。

[
 {
    "op":"replace",
    "path":"/id",
    "value":4321
 },
 {
     "op":"remove",
     "path":"/active"
 },
 {
     "op":"add",
     "path":"/roles/1",
     "value":"dev"
 }
]

JSONPatch JSON始终是包含op和路径键以及可选值键的对象数组。op描述应该执行的操作。JSON Patch支持添加、复制、移动、删除、替换和测试操作。 path键描述JSON对象的哪个部分受到操作的影响,它是一个JSON指针表达式。 可选值键是一个将在操作中使用的普通JSON值(字符串、数字、对象、数组、布尔值、null)。只需要添加和替换操作。 要创建一个JSON Patch,应用程序调用静态JSON.creatediff()方法,并传递两个文档作为参数。

package ch.rasc.jsonp;

import java.io.StringReader;

import javax.json.Json;
import javax.json.JsonException;
import javax.json.JsonObject;
import javax.json.JsonPatch;
import javax.json.JsonReader;
import javax.json.JsonValue;

public class Patch {

  public static void main(String[] args) {

    JsonObject source = Json.createObjectBuilder().add("id", 1234).add("active", true)
        .add("roles", Json.createArrayBuilder().add("admin")).build();
    System.out.println(source);
    // {"id":1234,"active":true,"roles":["admin"]}

    JsonObject target = Json.createObjectBuilder().add("id", 4321)
        .add("roles", Json.createArrayBuilder().add("admin").add("dev")).build();
    System.out.println(target);
    // {"id":4321,"roles":["admin","dev"]}

    JsonPatch patch = Json.createDiff(source, target);
    System.out.println(patch.toString());
    // [{"op":"replace","path":"/id","value":4321},{"op":"remove","path":"/active"},{"op":"add","path":"/roles/1","value":"dev"}]
//还可以使用JSON字符串创建JSON Patch对象。createPatch方法。
    try (JsonReader reader = Json.createReader(new StringReader(
        "[{\"op\":\"replace\",\"path\":\"/id\",\"value\":4321},{\"op\":\"remove\",\"path\":\"/active\"},{\"op\":\"add\",\"path\":\"/roles/1\",\"value\":\"dev\"}]"))) {
      JsonPatch createdPatch = Json.createPatch(reader.readArray());
      JsonValue modifiedSource = createdPatch.apply(source);
      System.out.println(modifiedSource);
      // {"id":4321,"roles":["admin","dev"]}
    }
    //要应用更改,应用程序必须调用JsonPatch实例的apply()方法。该方法期望JSON文档作为参数并返回更改后的文档。
//创建JSON补丁的另一种方法是使用JsonPatchBuilder。使用构建器,您可以通过编程方式创建补丁。
    JsonPatch builtPatch = Json.createPatchBuilder()
                             .replace("/id", 4321)
                             .add("/roles/1", "dev")
                             .remove("/active")
                             .build();    
    JsonValue modifiedSource = builtPatch.apply(source);
    System.out.println(modifiedSource);
    // {"id":4321,"roles":["admin","dev"]}
    //特殊的JSON指针语法——可以用来将一个新元素推到数组的末尾。
    builtPatch = Json.createPatchBuilder()
      .add("/roles/-", "dev")
      .copy("/uuid", "/id")
      .move("/enabled", "/active")
      .build();
    modifiedSource = builtPatch.apply(source);
    System.out.println(modifiedSource);
    // {"id":1234,"roles":["admin","dev"],"uuid":1234,"enabled":true}
    
//test()操作可用于在应用补丁之前检查值。以下代码仅在id包含值4321时应用更改。
    try {
      builtPatch = Json.createPatchBuilder()
          .test("/id", 4321)
          .add("/roles/-", "dev")
          .copy("/uuid", "/id")
          .move("/enabled", "/active")
          .build();
      modifiedSource = builtPatch.apply(source);
      System.out.println(modifiedSource);
    }
    catch (JsonException e) {
      System.out.println(e.getMessage());
      // The JSON Patch operation 'test' failed for path '/id' and value '4321'
    }
  }

}

本文示例的源代码存储在GitHub库中:https://github.com/ralscha/blog2019/tree/master/json-p

原文链接:https://golb.hplar.ch/2019/08/json-p.html