Làm cách nào để parse nested JSON trong Java?

4 min read

Đối tượng JSON là một tập hợp các cặp key/value không có thứ tự. Mảng JSON là một tập hợp các giá trị được sắp xếp theo thứ tự. Các giá trị có thể là object hoặc array. JSON lồng nhau là một tệp JSON có giá trị là các object JSON khác. Truy cập các object JSON lồng nhau rất giống truy cập các array lồng nhau.

Mình sẽ chuyển JSON sau đây làm ví dụ để lấy các value cho nhiều key bên ngoài và bên trong.

{
    "schemaVersion": "2.1",
    "userId": "16490fb4-c21c-496c-9b35-696171c49651",
    "body": {
        "requestId": "5374547d-2310-4190-8b63-0dcedc2138cb",
        "person": {
            "eeId": "EEID1",
            "personId": "080b3662-28d1-444b-87af-f79c7f3ebcde",
            "pendHire": {
                "pendHireId": "SESSION_ID"
            },
            "eeo": {
                "eeoId": "EEO_ID"
            },
            "acaFiling": {
                "nonEmployeeId": "ACA_ID",
                "aleMemberId": "Ale_ID"
            },
            "onboarding": {
                "personId": "ONB_ID"
            },
            "pdoc": {
                "employeeId": "f8e8a19b-d842-46ae-8906-3ec454d527c2",
                "cliendId": "f8e8a19b-d842-46ae-8906-3ec454d527c2"
            },
            "identity": {
                "accountStoreId": "ACCOUNT_ID"
            },
            "coreWorkflow": {
                "jobId": "JOB_ID"
            },
            "puuid": "0634a5f8-ad06-41f0-b176-0e25c24ce2ee",
            "userIntegrationKey": "59744513-0EE2-4EB9-A562-75855DDB02C8"
        },
        "products": "[BI]",
        "policy": {}
    },
    "dataCenter": "dlas1",
    "correlationId": "41c2b6a2-8693-4196-b745-a98a10131071",
    "user": "Marcus Mason"
}

Fetch the value from Nested Json

Đọc data từ tệp JSON bằng cách sử dụng đối tượng Mapper để mình tạo PACT với dữ liệu json động.

public MessagePact contract(String fileName, MessagePactBuilder builder) throws IOException {

    PactDslJsonBody body = new PactDslJsonBody();
    // jsonMap is a nested string json
    Map<String, Object> bodyAttribute =
        (Map<String, Object>) jsonMap.get(ConsumerContractConstants.body);
    for (Map.Entry<String, Object> entryJson : jsonMap.entrySet()) {
      if (entryJson.getKey().contains(ConsumerContractConstants.body)) {
        PactDslJsonBody bodyForPerson = new PactDslJsonBody();
        for (Map.Entry<String, Object> entryBody : bodyAttribute.entrySet()) {
          if (entryBody.getKey().contains(ConsumerContractConstants.person)) {
            PactDslJsonBody bodyForPersonId = new PactDslJsonBody();
            for (Map.Entry<String, Object> entryPerson :
                ((Map<String, Object>) bodyAttribute.get(ConsumerContractConstants.person))
                    .entrySet()) {
              bodyForPersonId.stringValue(entryPerson.getKey(), entryPerson.getValue().toString());
            }
            bodyForPerson.stringValue(entryBody.getKey(), bodyForPersonId.toString());
          } else {
            bodyForPerson.stringValue(entryBody.getKey(), entryBody.getValue().toString());
          }
          body.stringValue(entryJson.getKey(), bodyForPerson.toString());
        }
      } else {
        body.stringValue(entryJson.getKey(), entryJson.getValue().toString());
      }
    }
    MessagePact a_user_created_message =
        builder.expectsToReceive("a user created message").withContent(body).toPact();
    return a_user_created_message;
  }

Cách này được giải thích ở đây. Mình mô tả cơ bản cách sau đây.

Đầu tiên, hãy tách nó ra

Bây giờ nếu mình muốn tìm nạp bất kỳ giá trị thuộc tính cụ thể nào từ biến được tạo ở trên vào Object bằng HashMap thì chúng ta sử dụng code bên dưới.

public Map<String, Object> getStringObjectMap(MessagePact contract)
      throws JsonProcessingException {
    String pact = contract.getMessages().get(0).getContents().valueAsString();
    Map<String, Object> stringObjectMap =
        objectMapper.convertValue(
            objectMapper.readTree(pact), new TypeReference<Map<String, Object>>() {});
    return stringObjectMap;
  }

Nó trả về chuỗi json Vì vậy, nhờ việc này, chúng ta có thể tìm nạp mọi giá trị json của chuỗi.

Output

{schemaVersion=2.1, dataCenter=dlas1, correlationId=41c2b6a2-8693-4196-b745-a98a10131071, body={"requestId":"5374547d-2310-4190-8b63-0dcedc2138cb","person":"{"eeId":"EEID1","acaFiling":"{nonEmployeeId=ACA_ID, aleMemberId=Ale_ID}","identity":"{accountStoreId=ACCOUNT_ID}","coreWorkflow":"{jobId=JOB_ID}","onboarding":"{personId=ONB_ID}","personId":"080b3662-28d1-444b-87af-f79c7f3ebcde","puuid":"0634a5f8-ad06-41f0-b176-0e25c24ce2ee","pdoc":"{employeeId=f8e8a19b-d842-46ae-8906-3ec454d527c2, cliendId=f8e8a19b-d842-46ae-8906-3ec454d527c2}","pendHire":"{pendHireId=SESSION_ID}","eeo":"{eeoId=EEO_ID}","userIntegrationKey":"59744513-0EE2-4EB9-A562-75855DDB02C8"}","products":"[BI]","policy":"{}"}, userId=16490fb4-c21c-496c-9b35-696171c49651, user=Marcus Mason}

Lợi ích của PactDslJson

1. Giảm Thiểu rủi ro Bảo Trì

Một trong những lợi ích lớn nhất của việc sử dụng PactDslJson là giảm thiểu đáng kể rủi ro cần thiết để tạo và duy trì các pact so với các bài integration test truyền thống. Việc tạo các pact yêu cầu bạn phải định nghĩa các trường hợp sử dụng của user, điều này đã là một phần của quy trình phát triển mà bạn phải thực hiện ở một mức độ nào đó.

2. Document và Automated Verification

Khi bạn mã hóa các trường hợp sử dụng đó dưới dạng các bài Pact test, bạn có được document và xác automated verification một cách miễn phí. Pact đã trở thành một phần tiêu chuẩn trong quy trình công việc của mình khi phát triển các tương tác service mới. Việc có các pact được cập nhật đồng bộ với code, đồng thời có thể xác minh các pact đó tự động và độc lập, là một lợi ích lớn.

3. Hỗ Trợ Nhiều Ngôn Ngữ

Các thư viện Pact tồn tại cho nhiều ngôn ngữ lập trình khác nhau bao gồm Java, Python, Javascript và Ruby. Điều này cho phép bạn tích hợp Pact vào các dự án của mình bất kể ngôn ngữ bạn đang sử dụng.

4. Tối Ưu Hóa Việc Duy Trì Các Bài Test End-to-End

Nếu bạn gặp khó khăn trong việc duy trì các bài test tra end-to-end hoặc đang tìm cách làm cho việc phát triển các microservices dễ dàng hơn, hãy cân nhắc việc áp dụng Pact cho các pact service của bạn.

Reference

FIT, A Framework for Integrating Testing: Cunningham, W., online at http://fit.c2.com, and Mugridge, R. and Cunningham, W., ‘’Fit for Developing Software’’, Prentice-Hall PTR, 2005.

The ‘’Adapter’’ pattern: in Gamma, E., Helm, R., Johnson, R., Vlissides, J., ‘’Design Patterns’’, Addison-Wesley, 1995, pp. 139-150.

The ‘’Pedestal’’ pattern: in Rubel, B., “Patterns for Generating a Layered Architecture”, in Coplien, J., Schmidt, D., ‘’PatternLanguages of Program Design’’, Addison-Wesley, 1995, pp. 119-150.

The ‘’Checks’’ pattern: by Cunningham, W., online at http://c2.com/ppr/checks.html

The ‘’Dependency Inversion Principle’‘: Martin, R., in ‘’Agile Software Development Principles Patterns and Practices’’, Prentice Hall, 2003, Chapter 11: “The Dependency-Inversion Principle”, and online at http://www.objectmentor.com/resources/articles/dip.pdf

The ‘’Dependency Injection’’ pattern: Fowler, M., online at http://www.martinfowler.com/articles/injection.html

The ‘’Mock Object’’ pattern: Freeman, S. online at http://MockObjects.com

The ‘’Loopback’’ pattern: Cockburn, A., online at http://c2.com/cgi/wiki?LoopBack

‘’Use cases:’’ Cockburn, A., ‘’Writing Effective Use Cases’’, Addison-Wesley, 2001, and Cockburn, A., “Structuring Use Cases with Goals”, online at http://alistair.cockburn.us/crystal/articles/sucwg/structuringucswithgoals.htm

Avatar photo

Leave a Reply

Your email address will not be published. Required fields are marked *