C# JSON 파싱(parsing): 직렬화 및 역직렬화 개념

Wookoa 2024. 4. 8.

C# JSON 직렬화 및 역직렬화 개념
C# JSON 직렬화 및 역직렬화 개념

 

머리말

  C# 개발환경에서 JSON을 다루기 위한 두 번째 포스팅이다. 첫 번째 포스팅에서는 JSON 배경과 구조에 대해서 설명했는데, JSON 파싱을 위해 유용한 개념을 다루었으니 상단의 도움이 될만한 포스팅을 참고 바란다. 본 포스팅에서는 C# 환경에서 널리 사용되는 JSON 라이브러리를 비교한 뒤, 직렬화 및 역직렬화의 개념에 대해서 설명하도록 한다. 라이브러리 사용에 앞서 어떤 라이브러리를 사용해야 될지 고민이 될 수 있다. 자신의 소중한 프로그램에 사용할 라이브러리인데 아무거나 대충 사용할 수 없다. 대표적으로 사용되는 라이브러리는 두 가지 정도만 기억해도 좋다. NewtonSoft에서 배포하는 Newtonsoft.Json 라이브러리와 .NET Core 개발팀에서 배포하는 System.Text.Json 라이브러리다.

Newtonsoft.Json vs System.Text.Json

  머리말에서 언급한 두 개의 라이브러리 모두 패키지 관리자에서 추가로 설치해야 된다. 아직까지 .NET 4.0 개발환경에서는 추가 설치 없이 기본 패키지만으로 JSON을 다루지 못한다. 하지만 두 개의 라이브러리 모두 선택할만한 장점이 있어서 본 포스팅에서 비교해 본다.

  먼저 Newtonsoft.Json 라이브러리는 매우 저명하다. 닷넷 코어 개발팀에서 제공하기 이전부터 오랫동안 발전해 온 라이브러리며, 실제로 패키지 관리자 콘솔에서 패키지가 사용된 수치만 봐도 압도적으로 선두를 지키고 있다. 그만큼 많은 개발자로부터 큰 관심을 받고 있는 라이브러리며 버그 패치도 활발하다. 본 포스팅을 작성하는 시점이 벌써 12 버전까지 배포된 상황이다. Newtonsoft.Json 라이브러리는 기존의 XML 직열화/역직렬화를 처리해 주던 기능에서 JSON으로 영역을 확장한 것이다. 그렇기 때문에 수많은 검증이 이루어졌을 것이며 더욱 신뢰가 가는 라이브러리라 생각된다.

  다음으로 System.Text.Json 라이브러리는 다소 늦은 감이 있지만 이제라도 적극적으로 배포하고 있다. 본 포스팅을 작성하는 시점이 5 버전까지 배포된 상황이다. 아무래도 .NET framework 환경에서 개발하는 마당에, 닷넷 코어 개발팀이 배포하는 라이브러리가 심리적으로 주는 안정감도 무시할 수 없다. 궁극적으로는 .NET Framework 환경에 가장 밀접하게 동작할 가능성이 높은 라이브러리라 생각되기도 한다.

JSON 역직렬화 비교 (input)

 Name  Data Size  Response Per Second  Memory(MB)
 Newtonsoft.Json  500 Byte  136,435  172
 System.Text.Json  500 Byte  167,861  169
 Newtonsoft.Json  2.4 KByte  97,137  174
 System.Text.Json  2.4 KByte  132,026  169
 Newtonsoft.Json  40 KByte  7,712  212
 System.Text.Json  40 KByte  16,625  193

JSON 직렬화 비교 (output)

 Name  Data Size  Response Per Second  Memory(MB)
 Newtonsoft.Json  500 Byte  120,273  174
 System.Text.Json  500 Byte  145,631  173
 Newtonsoft.Json  2.4 KByte  35,408  187
 System.Text.Json  2.4 KByte  56,424  184
 Newtonsoft.Json  40 KByte  8,416  202
 System.Text.Json  40 KByte  14,848  197

  두 라이브러리 간 비교 지표는 Microsoft 공식 블로그에서 발췌했다. Microsoft 공식 발표이기 때문에 당연히 주된 내용은 System.Text.Json 라이브러리가 우수하다는 내용의 글이었는데, 초당 반응 회수가 더 높거나 메모리 사용이 적다는 분석이다. 데이터 이동이 활발한 시스템을 개발한다면 면밀히 따져봐야겠지만 일반적인 애플리케이션을 개발한다면 별 차이가 없어 보인다. 뒤늦게 출시한 System.Text.Json 라이브러리가 Newtonsoft.Json 라이브러리의 점유율을 의식한 것 같다. 결론적으로는 닷넷 코어 개발팀에서 말하길, .NET framework 환경에서 테스트해 본 결과 .NET 라이브러리가 더욱 우수하다고 하니 신규 프로젝트에서는 System.Text.Json 라이브러리를 선택하는 것도 나쁜 선택은 아니다.

  위 사실을 정리해 보면 새로운 프로젝트를 시작한다면 .NET 라이브러리 사용이 좋을 것 같으며, 기존에 Newtonsoft 라이브러리를 사용하는 프로젝트라면 .NET 라이브러리가 안정화될 때까지 Newtonsoft 라이브러리를 그대로 사용하는 것이 좋을 것 같다. 만약 간단한 애플리케이션을 개발하는 정도라면 Newtonsoft 라이브러리를 추천한다. 이유는 관련된 정보가 이미 넘쳐나기 때문에 개발 생산성 향상에 용이하기 때문이다.

직렬화, 역직렬화 및 파싱의 개념

  지금까지 JSON에 대해서 많은 설명을 했는데 정리하기 쉽지 않은 부분이 직렬화, 역직렬화 개념이다. 개념 자체를 이해하는 데는 크게 어렵지 않다지만, 각종 라이브러리에서 제공되는 함수들 중 혼동되는 부분이 존재한다. 기본적으로 모든 라이브러리가 Serialize, Deserialize 함수를 제공하고 있다. 하지만 여기서 더욱 혼란을 가중시키는 것이 바로 Parse 함수의 존재 여부다. JSON을 소개하는 블로그마다 훌륭하게 JSON 데이터를 다루는 방법에 대해서 소개하고 있지만, 방법은 제각기 다르기 때문에 정확한 사용방법을 이해하는데 어려움이 있다. 그렇기 때문에 본 포스팅에서는 각 용어의 개념과 어떤 콘셉트로 제공된 함수를 사용해야 되는지 설명하고자 한다. 참고로 Microsoft 블로그에 따르면 JSON 포맷을 문자열에서 Native Object로 변환하는 것을 파싱(Parsing)이라고 하며, 네트워크를 통해 데이터를 전달할 수 있게 객체를 문자열로 변환하는 과정을 문자열화(Stringification/Serialize)이라고 설명한다.

  문자로면 설명하기 어려워 아래와 같이 그림을 그려 넣었다. 그림에 대해서 한 가지 부연 설명을 하자면, Native JSON은 사람이 보기 편한 구조로 작성된 JSON 문서를 의미한다. 사람이 이해하기 편하게 적절한 앤터 값과 라인피드가 추가된 JSON 데이터로 생각하면 좋을 것 같다. 자세한 설명은 그림 아래에서 설명하도록 한다.

직렬화 및 역직렬화, 파싱의 이해
직렬화 및 역직렬화, 파싱의 이해

  직렬화, 역직렬화 및 파싱을 이해하기 위해선 가장 먼저 역직렬화를 이해하면 좋을 것 같다. 역직렬화(Deserialize)란 JSON 포맷으로 생성된 문자열 데이터를 개발자가 정의한 클래스 구조로 변형하는 작업이다. 클래스 구조로 변경하기 위해서는 클래스의 구조가 JSON 포맷과 대응되도록 생성돼야 한다. 위의 그림으로 예를 들면, JSON 데이터를 역직렬화하기 위해서 Title, Address 필드를 갖고 있는 Wookoa 클래스가 필요하다는 의미다. JSON 포맷으로 생성된 데이터 중 HomPage, TistoryBlog 값은 Title 필드에 저장될 것이며 각각의 URL 주소 데이터는 Address 필드에 저장될 것이다. 이렇게 개발자가 정의해 놓은 클래스로 역직렬화가 수행되면 JSON의 데이터를 편리하게 접근해서 사용할 수 있기 때문에 역직렬화를 수행하게 된다.

  반대로 직렬화(Serialize)란 이미 역직렬화된 클래스의 데이터를 String 타입으로 변환하는 작업이다. 여기서 위 사진에서 표현한 Native JSON과는 다르게 모든 항목을 한 줄로 표현한다는 점이다. 앤터 값과 라인피드 등은 모두 없어진 JSON 데이터가 된다. 이렇게 변환해서 사용하는 이유는 JSON을 네트워크로 전송하는 상황을 고려했기 때문이다. 네트워크로 데이터를 전송하기 위해선 비용과 자원의 소모가 뒤 따른다. 그렇기 때문에 최대한 데이터를 축소해서 전송할 필요가 있으며 모든 데이터를 한 줄로 표현함으로써 자원의 낭비를 막을 수 있다.

  이제 직렬화와 역직렬화를 이해하는데 큰 어려움은 없을 것이다. 하지만 파싱(Parse)이라는 것이 존재하여 개발자를 혼란스럽게 한다. 직렬화와 역직렬화는 각각의 함수가 존재하는데 파싱은 또 무엇인지 혼란스럽다. 간단히 이해하기 위해 반대로 생각해 보면, 모든 JSON을 단순하게 읽어낼 뿐인데 그때마다 클래스를 생성하는 것은 효율적이지 못하다. 이러한 상황에서 라이브러리가 무언가 기능을 제공해 주면 좋은 상황이 연출될 것이다. 그럴 때 사용하는 것이 바로 Native Object이며, 각 라이브러리에서 JSON 구조를 접근하기 위해 제공되는 오브젝트를 의미한다. Native Object로 파싱 과정을 거치게 되면 JSON에 접근하기 위해선 변수명 및 하위 오브젝트명을 하드코딩으로 접근해야 한다. 라이브러리에서 제공하는 Native Object에서는 JSON이 어떤 데이터로 구성되었는지 알지 못하며 단순하게 JSON 포맷에 알맞게 파싱 해서 Native Object에 저장해 놓기 때문이다. 미리 정해진 JSON 데이터를 단순하게 읽어내는 것이라면 적합하겠으나, 변수명이나 하위 오브젝트명이 동적으로 변형되는 JSON을 처리하기 위해선 역직렬화 방법을 사용해야 한다.

꼬리말

  본 포스팅을 발행하기 위해 2박 3일 동안 고민하면서 작성했다. 본인이 알고 있는 지식과 다른 부분이 있는지 확인하고 검토하는 데에도 오랜 시간이 소요되었으며, 본인조차도 명확하게 정리되지 않은 개념을 포스팅하려니 더욱 시간이 오래 걸렸다. 글이 많아서 지루할 수 있지만, 너무 어렵게 써 내려간 문장이 없는지 여러 번 검토해 가면서 정성스레 작성한 포스팅이다. 조금이라도 JSON에 대해서 쉽게 이해하길 바라는 마음에 작성했지만, 과연 의도한 대로 잘 전달이 되었을지 본인도 궁금하다. 다음 세 번째 포스팅에서는 Newtonsoft.Json 라이브러리와 System.Text.Json 라이브러리 사용 방법에 대해서 설명한다. 상단의 도움이 될만한 포스팅 영역에 관련 포스팅을 게시했으니 참고하길 바란다.

인기있는 글

소중한 댓글 (0)