知識庫 / JSON / Jackson RSS 訂閱

讀取 JSON 文檔作為映射並進行比較

Jackson
HongKong
11
09:45 PM · Dec 05 ,2025

1. 概述

在本教程中,我們將探討如何以 Map 格式讀取 JSON 文檔,並進行比較。 此外,我們還將研究如何查找兩個 Map 之間的差異。

2. 轉換為Map

首先,我們將探討如何將 JSON 文檔轉換為 Map。讓我們先來看一下我們將用於測試的 JSON 對象。

讓我們創建一個名為 first.json 的文件,內容如下:

{
  "name": "John",
  "age": 30,
  "cars": [
    "Ford",
    "BMW"
  ],
  "address": {
    "street": "Second Street",
    "city": "New York"
  },
  "children": [
    {
      "name": "Sara",
      "age": 5
    },
    {
      "name": "Alex",
      "age": 3
    }
  ]
}

同樣,我們創建一個名為 second.json 的文件,內容如下:

{
  "name": "John",
  "age": 30,
  "cars": [
    "Ford",
    "Audi"
  ],
  "address": {
    "street": "Main Street",
    "city": "New York"
  },
  "children": [
    {
      "name": "Peter",
      "age": 5
    },
    {
      "name": "Cathy",
      "age": 10
    }
  ]
}

如我們所見,以上JSON文檔之間存在兩個差異:

  • cars數組的值不同
  • street鍵在address對象中的值不同
  • children數組存在多個差異

2.1. 使用 Jackson

Jackson 是一個流行的用於 JSON 操作的庫。我們可以使用 Jackson 將 JSON 轉換為一個 Map</em title="Map>。

讓我們先添加 Jackson 依賴項:https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.15.2</version>
</dependency>

現在我們可以使用 Jackson 將 JSON 文檔轉換為 Map

class JsonUtils {
    public static Map<String, Object> jsonFileToMap(String path) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.readValue(new File(path), new TypeReference<Map<String, Object>>() {});
    }
}

在這裏,我們使用ObjectMapper類中的readValue()方法將JSON文檔轉換為Map。該方法接受JSON文檔作為File對象以及TypeReference對象作為參數。

2.2. 使用 Gson

同樣,我們也可以使用 Gson 將 JSON 文檔轉換為一個 Map。 為了實現這一點,我們需要包含以下依賴項:依賴項

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.11.0</version>
</dependency>

現在讓我們來看一下用於轉換 JSON 的代碼:

public static Map<String, Object> jsonFileToMapGson(String path) throws IOException {
    Gson gson = new Gson();
    return gson.fromJson(new FileReader(path), new TypeToken<Map<String, Object>>() {}.getType());
}

在這裏,我們使用 Gson 類中的 fromJson() 方法將 JSON 文檔轉換為 Map。它接受 JSON 文檔作為 FileReader 對象以及 TypeToken 對象作為參數。

3. 比較 Map 結構

現在我們已經將 JSON 文檔轉換為 Map 結構,接下來讓我們看看不同的比較方法。

3.1. 使用 Guava 的 <em >Map.difference()</em >

Guava 提供了一個 <em >Maps.difference()</em > 方法,可用於比較兩個 <em >Map</em > 對象。 要使用此方法,請將 Guava 依賴項添加到您的項目:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>33.2.1-jre</version>
</dependency>

現在,讓我們來看一下代碼以比較Map

@Test
void givenTwoJsonFiles_whenCompared_thenTheyAreDifferent() throws IOException {
    Map<String, Object> firstMap = JsonUtils.jsonFileToMap("src/test/resources/first.json");
    Map<String, Object> secondMap = JsonUtils.jsonFileToMap("src/test/resources/second.json");

    MapDifference<String, Object> difference = Maps.difference(firstFlatMap, secondFlatMap);
    difference.entriesDiffering().forEach((key, value) -> {
        System.out.println(key + ": " + value.leftValue() + " - " + value.rightValue());
    });
    assertThat(difference.areEqual()).isFalse();
}

Guava 只能比較一個級別的 Map 這不適用於我們的情況,因為我們有一個嵌套的 Map

讓我們看看如何比較我們上面的嵌套 Map。 我們使用 entriesDiffering() 方法來獲取兩個 Map 之間的差異。 這將返回一個包含差異的 Map,其中鍵是值的路徑,值是 MapDifference.ValueDifference 對象。 這個對象包含來自兩個 Map 的值。 如果運行測試,我們將看到兩個 Map 之間的不同鍵及其值:

cars: [Ford, BMW] - [Ford, Audi]
address: {street=Second Street, city=New York} - {street=Main Street, city=New York}
children: [{name=Sara, age=5}, {name=Alex, age=3}] - [{name=Peter, age=5}, {name=Cathy, age=10}]

如我們所見,這表明 車輛、地址兒童 字段不同,並且這些差異已列出。然而,這並不能説明哪些嵌套字段導致了這些差異。例如,它並沒有指出 街道 字段在 地址 對象中的差異。

3.2. 平鋪 Maps</h3

為了準確地指出嵌套 Maps 之間的差異,我們將 Maps 平鋪,使每個鍵都指向其值。例如,street 鍵在 address 對象中將被平鋪為 address.street,以此類推。

下面是對此的示例代碼:

class FlattenUtils {
    public static Map<String, Object> flatten(Map<String, Object> map) {
        return flatten(map, null);
    }

    private static Map<String, Object> flatten(Map<String, Object> map, String prefix) {
        Map<String, Object> flatMap = new HashMap<>();
        map.forEach((key, value) -> {
            String newKey = prefix != null ? prefix + "." + key : key;
            if (value instanceof Map) {
                flatMap.putAll(flatten((Map<String, Object>) value, newKey));
            } else if (value instanceof List) {
                // check for list of primitives
                Object element = ((List<?>) value).get(0);
                if (element instanceof String || element instanceof Number || element instanceof Boolean) {
                    flatMap.put(newKey, value);
                } else {
                    // check for list of objects
                    List<Map<String, Object>> list = (List<Map<String, Object>>) value;
                    for (int i = 0; i < list.size(); i++) {
                        flatMap.putAll(flatten(list.get(i), newKey + "[" + i + "]"));
                    }
                }
            } else {
                flatMap.put(newKey, value);
            }
        });
        return flatMap;
    }
}

在這裏,我們使用遞歸來扁平化 Map。對於任何字段,以下條件之一將為真:

  • 值可以是 Map(嵌套 JSON 對象)。在這種情況下,我們將使用值作為參數遞歸調用 flatten() 方法。例如,address 對象將被扁平化為 address.streetaddress.city
  • 接下來,我們可以檢查值是否為 List(JSON 數組)。如果數組包含原始值,我們將鍵和值添加到扁平化後的 Map 中。
  • 如果數組包含對象,我們將使用每個對象作為參數遞歸調用 flatten() 方法。例如,children 數組將被扁平化為 children[0].namechildren[0].agechildren[1].namechildren[1].age
  • 如果值既不是 Map 也不是 List,我們將鍵和值添加到扁平化後的 Map 中。

這將遞歸進行,直到我們到達 Map 的最後一層。此時,我們將會得到一個扁平化後的 Map,其中每個鍵都表示指向值的路徑。

3.3. 測試

現在我們已經對地圖進行了扁平化,接下來讓我們看看如何使用Maps.difference()方法比較它們:

@Test
void givenTwoJsonFiles_whenCompared_thenTheyAreDifferent() throws IOException {
    Map<String, Object> firstFlatMap = FlattenUtils.flatten(JsonUtils.jsonFileToMap("src/test/resources/first.json"));
    Map<String, Object> secondFlatMap = FlattenUtils.flatten(JsonUtils.jsonFileToMap("src/test/resources/second.json"));

    MapDifference<String, Object> difference = Maps.difference(firstFlatMap, secondFlatMap);
    difference.entriesDiffering().forEach((key, value) -> {
        System.out.println(key + ": " + value.leftValue() + " - " + value.rightValue());
    });
    assertThat(difference.areEqual()).isFalse();
}

再次,我們將打印出不同的鍵和值。這會導致以下輸出:

cars: [Ford, BMW] - [Ford, Audi]
children[1].age: 3 - 10
children[1].name: Alex - Cathy
address.street: Second Street - Main Street
children[0].name: Sara - Peter

4. 結論

在本文中,我們探討了如何在 Java 中比較兩個 JSON 文檔。我們研究了將 JSON 文檔轉換為 Map 的不同方法,然後使用 Guava 的 Maps.difference() 方法進行比較。我們還研究瞭如何扁平化 Map 以進行嵌套 Map 的比較。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.