ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] JSONPath로 JSON 데이터 다루기
    Java/기타 2024. 8. 17. 10:07
    반응형

    JSONPath는 JSON 데이터를 효율적으로 탐색하고, 특정 값을 추출하거나 필터링하는 쿼리 언어입니다. 이번 포스트에서는 com.jayway.jsonpath 라이브러리 사용하여 Java에서 JSON 데이터를 다루는 방법을 살펴보겠습니다.


    JSONPath 개요

    JSONPath는 JSON 문서를 대상으로 SQL과 유사한 구문을 사용하여 JSON 데이터의 특정 값을 추출할 수 있습니다. 대표적인 JSONPath 구문은 다음과 같습니다.


    JSON 경로 설명

    JSON 경로 설명
    $ 루트 객체를 나타냅니다.
    @ 현재 객체를 나타냅니다.
    . 또는 []  자식을 나타냅니다.
    * 모든 요소를 나타냅니다.
    ..  모든 하위 요소를 재귀적으로 탐색합니다.
    ?() 필터링 조건을 나타냅니다.

     

    1. 라이브러리 추가

    com.jayway.jsonpath:json-path:2.9.0는 Java에서 JSON 데이터를 다루기 위해 사용하는 라이브러리입니다.
    Gradle 설정
    build.gradle 파일에 다음과 같이 의존성을 추가합니다.

    // JSON Path
    implementation 'com.jayway.jsonpath:json-path:2.9.0'

    Maven Repository : https://mvnrepository.com/artifact/com.jayway.jsonpath/json-path

     

    2. 샘플 JSON

    다음은 예제에서 사용할 store.json 파일입니다.

    {
      "store": {
        "book": [
          {
            "category": "reference",
            "author": "Nigel Rees",
            "title": "Sayings of the Century",
            "price": 8.95
          },
          {
            "category": "fiction",
            "author": "Evelyn Waugh",
            "title": "Sword of Honour",
            "price": 12.99
          },
          {
            "category": "fiction",
            "author": "Herman Melville",
            "title": "Moby Dick",
            "isbn": "0-553-21311-3",
            "price": 8.99
          },
          {
            "category": "fiction",
            "author": "J. R. R. Tolkien",
            "title": "The Lord of the Rings",
            "isbn": "0-395-19395-8",
            "price": 22.99
          }
        ],
        "bicycle": {
          "color": "red",
          "price": 19.95
        }
      },
      "expensive": 10
    }

     

    3. JSONPath를 사용한 테스트 코드

    3_1. JSONPath를 사용하여 JSON 파일에서 작가명을 추출
    $.store.book[*].author 표현식은 book 배열 내의 모든 author 필드를 찾아서 반환합니다.

    @DisplayName("getAuthorsFromJsonFile_Json 파일에서 작가명을 조회")
    @Test
    public void testGetAuthorsFromJsonFile() {
    
        // Given & When
        // book 배열 내의 모든 author 필드를 찾아서 반환
        List<String> authors = JsonPath.read(json, "$.store.book[*].author");
        log.debug("authors : {}", authors);
    
        // Then
        assertAll(
            () -> assertFalse(authors.isEmpty())
        );
    }

     

    3_2. JSON 문자열을 Document 객체로 파싱한 후, JSONPath를 사용하여 작가명 추출

    @DisplayName("getAuthorsFromDocument_Document 에서 작가명을 조회")
    @Test
    void testGetAuthorsFromDocument() {
    
        // Given
        // JSON 문자열을 Document 객체로 파싱
        Object document = Configuration.defaultConfiguration().jsonProvider().parse(json);
    
        // When
        // JSONPath를 사용하여 Document 객체에서 작가명을 추출
        List<String> authors = JsonPath.read(document, "$.store.book[*].author");
        log.debug("authors : {}", authors);
    
        // Then
        assertAll(
            () -> assertFalse(authors.isEmpty())
        );
    }


    3_3. ReadContext 객체를 이용하여 JSONPath를 통한 작가명 추출

    @DisplayName("getAuthorsFromReadContext_ReadContext 에서 작가명을 조회")
    @Test
    void testGetAuthorsFromReadContext() {
    
        // Given
        // JSON 문자열을 ReadContext 객체로 파싱
        ReadContext readContext = JsonPath.parse(json);
    
        // When
        // JSONPath를 사용하여 ReadContext 객체에서 작가명을 추출
        List<String> authors = readContext.read("$.store.book[*].author");
        log.debug("authors : {}", authors);
    
        // Then
        assertAll(
            () -> assertFalse(authors.isEmpty())
        );
    }


    3_4. 특정 조건을 만족하는 책 정보 추출
    $.store.book[?(@.category == 'fiction' && @.price > 10)] 표현식은 book 배열 내에서 category가 'fiction'이고 price가 10달러를 초과하는 책 객체들을 반환합니다.

    @DisplayName("getBooks_조건을 추가하여 10달러 초과의 비싼 책을 조회")
    @Test
    void testGetBooks() {
    
        // Given & When
        // JSONPath를 사용하여 조건에 따라 책 정보를 추출
        List<Map<String, Object>> books = JsonPath
            .using(Configuration.defaultConfiguration())
            .parse(json)
            .read("$.store.book[?(@.category == 'fiction' && @.price > 10)]", List.class);
        log.debug("books : {}", books);
    
        // Then
        assertAll(
            () -> assertFalse(books.isEmpty())
        );
    }


    3_5. JSONPath 필터를 사용하여 특정 조건을 만족하는 책 정보 추출
    JSONPath 필터를 사용하여 category가 'fiction'이고 price가 10달러를 초과하는 책 객체들을 반환합니다.

    @DisplayName("getBooksFiltered"
          + "_조건(?(@.category == 'fiction' && @.price > 10)을 추가하여 10달러 초과의 비싼 책을 조회")
    @Test
    void testGetBooksFiltered() {
    
        // Given
        // 필터 구문을 사용하여 조건을 정의
        Filter filter = filter(
            where("category").is("fiction").and("price").gt(10D)
        );
    
        // When
        // JSONPath 필터를 사용하여 조건에 맞는 책 정보를 추출
        List<Map<String, Object>> books = JsonPath
            .using(Configuration.defaultConfiguration())
            .parse(json)
            .read("$.store.book[?]", filter);
        log.debug("books : {}", books);
    
        // Then
        assertAll(
            () -> assertFalse(books.isEmpty())
        );
    }


    3_6. JSONPath를 이용하여 JSON 문자열을 객체로 변환
    JSONPath를 사용하여 첫 번째 책의 정보를 Book 객체로 변환하고 이를 검증합니다.

    @DisplayName("getBookDto_JSON 문자열을 BookDto 객체로 변환하여 반환")
    @Test
    void testGetBook() {
    
        // Given
        String jsonPath = "$.store.book[0]";
    
        // When
        // JSON 문자열을 Book 객체로 변환
        Book book = JsonPath.parse(json).read(jsonPath, Book.class);
        log.debug("book : {}", book.toString());
    
        // Then
        assertAll(
            () -> assertNotNull(book),
            () -> assertEquals("reference", book.getCategory()),
            () -> assertEquals("Nigel Rees", book.getAuthor()),
            () -> assertEquals("Sayings of the Century", book.getTitle()),
            () -> assertEquals(8.95, book.getPrice())
        );
    }


    3_7. JSONPath 옵션을 사용하여 JSON 데이터에서 경로 리스트를 추출
    Option.AS_PATH_LIST 옵션을 사용하여 JSON 데이터에서 모든 경로 리스트를 추출하고 이를 검증합니다.

    @DisplayName("getPathList_JSON 객체에서 경로 리스트를 조회")
    @Test
    void testGetPathList() {
    
        // Given
        // Option.AS_PATH_LIST는 JsonPath 표현식에 매칭되는 모든 경로를 리스트의 형태로 반환
        Configuration conf = Configuration.builder()
            .options(Option.AS_PATH_LIST)
            .build();
    
        String jsonPath = "$..author";
    
        List<String> expectedPathList = Arrays.asList(
            "$['store']['book'][0]['author']",
            "$['store']['book'][1]['author']",
            "$['store']['book'][2]['author']",
            "$['store']['book'][3]['author']");
    
        // When
        // 경로 리스트를 추출
        List<String> pathList = JsonPath
            .using(conf)
            .parse(json)
            .read(jsonPath);
        log.debug("pathList : {}", pathList);
    
        // Then
        assertAll(
            () -> assertFalse(pathList.isEmpty()),
            () -> assertArrayEquals(expectedPathList.toArray(), pathList.toArray())
        );
    }

     

    JsonPath - https://github.com/json-path/JsonPath

     

    소스 코드는 Github Repository - https://github.com/tychejin1218/blog/tree/main/json-modules/json-path 프로젝트를 참조하세요.

    반응형

    댓글

Designed by Tistory.