본문 바로가기
안드로이드/코틀린

Gson의 기본적인 사용법(with kotlin)

by 나이아카 2021. 5. 29.
728x90

 이전 게시글 중 하나에 Gson과 Json의 차이점이라는 제목으로 Gson을 짧게 다룬 적이 있습니다. 그때와는 조금 다르게 이번에는 Gson을 어떻게 코틀린에서 사용하는지에 대해서 공부한 내용을 기록해두려고 합니다.

https://github.com/google/gson

 

 

google/gson

A Java serialization/deserialization library to convert Java Objects into JSON and back - google/gson

github.com

 


 Gson은 Json 데이터를 가공하는데 있어 좀 더 편하고 효율적으로 관리할 수 있도록 도와주는 라이브러리로 google에서 제공하는 Json을 줄여 Gson이라고 부른다고 보면 되겠습니다.

Json이 무엇인지 간단하게 설명하자면, Key-Value 형태로 구성되어진 데이터 타입이며 사람이 읽을 수 있도록 텍스트 타입으로 지원되는 데이터 오브젝트입니다. Json은 여러가지 언어에서 지원이 가능해 각기 다른 언어로 제작된 프로그램 - 서버의 통신도 원활하게 이루어지게 만드는 효과가 있습니다.

 이러한 Json 데이터를 Gson에서는 어떻게 사용할 수 있는지 알아보겠습니다.

{ 
    "name":"Douglas Crockford",
    "age": 66,
    "from" : "USA",
    "education" : ["San Francisco State University", "Newport Harbor High School"] 
}

 위의 Json 객체를 담기 위한 data class를 생성해보겠습니다.

data class PersonData(
    val name : String,
    val age : Int,
    val from : String,
    val education : JSONArray
)

 이 예제를 class 객체에 담기 위해서는 먼저 jsonObject의 key 값을 이용해 각각의 데이터를 매핑해야 합니다.

728x90
val jsonObject = JSONObject("{
    \"name\":\"Douglas Crockford\",
    \"age\": 66,
    \"from\" : \"USA\",
    \"education\" : [\"San Francisco State University\", \"Newport Harbor High School\"]
}")

//각각의 키를 직접 가져와서 객체에 매핑

val data = PersonData(
    jsonObject.getString("name"),
    jsonObject.getInt("age"),
    jsonObject.getString("from"),
    jsonObject.getJSONArray("education")
)
   

 물론 jsonObject.keys()를 이용해 키값을 한 번에 불러와 객체로 만들지 않고 각 데이터를 이용할 수도 있습니다! 하지만 지금은 객체로 만드는 것에 중점을 둘 것이기 때문에 이에 대해서 다루도록 하겠습니다.

 물론 JSONObject 클래스에는 get대신 opt를 사용해 default 값을 정의해줄 수 있습니다. 이는 get방식보다 훨씬 좋은 부분인 것이 만약 키 값에 오류가 있어 받은 jsonObject가 제대로 키 값을 다 전달하지 못했거나 혹은 nullable한 데이터라 전달하지 않는 경우 에러를 발생시킬 수 있습니다. 이를 방지해주기 위해 optString, optInt와 같은 타입을 이용해 줄 수 있습니다.

 

 다음은 Gson을 이용해보겠습니다.

data class PersonData(
    val name : String,
    val age : Int,
    val from : String,
    val education : ArrayList<String>
)

 Gson을 이용하기 위해서는 살짝 데이터 클래스의 변경이 필요합니다. Gson에서 자동변환해주는 경우에는 JsonArray가 들어가지 않기 때문입니다.

val jsonObject : JsonObject = JsonParser.parse("{
    \"name\":\"Douglas Crockford\",
    \"age\": 66,
    \"from\" : \"USA\",
    \"education\" : [\"San Francisco State University\", \"Newport Harbor High School\"]
}").asJsonObject

//Gson을 이용한 생성

val data = Gson().fromJson(jsonObject, PersonData::class.java)

 Gson의 converter를 이용하면 각각을 매핑하지 않아도 바로 객체를 생성할 수 있습니다. 이때 첫 번째 파라미터에는 json 형태를 띈 String이나 JsonObject를 가지고, 두 번째에는 변환할 class를 파라미터로 주면 되겠습니다. 단, dataClass의 변수 이름과 키 값이 동일해야 제대로 값이 들어갈 수 있습니다. 만약 변수의 이름을 바꿔야 하는 경우가 있다면 @SerializedName("~~") 주석을 통해 매핑해줄 수 있습니다.

 키 값이 매핑되지 않으면 default 값이 들어가게 되니(nullable한 타입이 아님에도 불구하고 String의 경우에는 null이 들어가게 됩니다!) 매핑이 제대로 되어 있는지 확인 과정은 필수입니다. 그러나 exception의 위험은 class를 생성하는 것으로는 일어나지 않으니 데이터 처리 과정에서 제대로 된 처리를 할 수 있다면 프로그램의 강제종료를 막을 수 있습니다.

 이건 이제 기본적인 object를 원하는 data class로 전환하는 방법입니다. 그렇다면 jsonArray도 class 파라미터에 ArrayList를 제공하는 것으로 동일하게 사용할 수 있습니다.

 

 그 다음은 data class의 리스트를 다시 json 데이터로 변환하는 예제입니다.

val jsonData = Gson().toJsonTree(classData, object : TypeToken<ArrayList<PersonData>>(){}.type)
var arrayData = jsonData.asJsonArray

 사실 이 글을 작성하는 가장 큰 이유 중 하나입니다. data class 내부의 ArrayList를 Gson으로 변환하는 것은 toJson이나 fromGson으로 쉽게 왔다갔다 할 수 있지만, Collection의 범주에 속하는 list 내부에 들어있는 class를 변환하는 것은 TypeToken이 필요로 합니다.

 되게 간단하지만, 의외로 자주 사용하지 않으니 잊기 쉽습니다. 물론 직접 jsonElement를 가져와서 그걸 array로 만든 후 for문을 이용해서 직접 list를 생성하는 것도 가능합니다!(이 경우는 모든 jsonArray 내부 데이터를 가져오는 것이 아니라 조건에 맞춰 가져오고 싶거나 내부 로직보다 더 빠르게 가져올 수 있을 때 사용하면 효과적이겠네요!)


 의외로 블로그를 운영하면서 느낀 점은 어려운 내용보다는 자주 사용하고 이미 아는 내용이라고 생각하는 부분이 드문드문 문법적으로 헷갈리거나 오래 사용하지 않아 다시금 막히는 경우가 많다는 것입니다. 그래서 블로그를 운영하면서 제가 다뤘던 기술이나 코드들을 블로그에 부분적이나마 남겨놓는 행동이 나중에 저에게 큰 도움이 될 것 같다는 생각을 하게 되네요.

반응형

'안드로이드 > 코틀린' 카테고리의 다른 글

Live data와 ObservableField는 무엇일까?  (1) 2021.07.26
(android - jetPack) bindingAdapter  (0) 2021.06.06
(android) skydoves - Balloon  (0) 2021.05.27
(android) SoundPool 사용법  (0) 2021.05.02
(android-jetpack)LiveData  (0) 2021.04.13

댓글