본문 바로가기

ANDROID/JSON

[안드로이드 | JSON] Json 파일 Parsing해 List로 만들기

프로젝트 리소스에 포함된 Json 파일을 불러와 List로 만들 일이 생겼다.

 

이 과정을 위해 해준 일들을 우선 나열해보면 4단계 정도가 있다.

 

 

1. 프로젝트에 Assets 폴더를 만들고 불러오고자 하는 json 파일을 집어넣는다.

2. GSON 라이브러리 및 Room Database import

3. Json 파일로부터 만들고자 하는 Data class를 정의

(3-1) 필요한 경우에 따라 TypeConverter 추가 정의

4. Json 파일을 String 객체로 Parsing > Gson 사용해 List 뽑아내기

 

 

Json Parsing을 위해 Gson과 AAC의 Room을 사용했다.

 

그러면 1번부터 쭉 밟아보자.

 

굉장히 쓸데없이 큰 짤

 

1. 프로젝트에 Assets 폴더를 만들고 불러오고자 하는 json 파일을 집어넣는다.

 

최상단 App 폴더를 우클릭 >  New 섹션으로 가면 하단에서 Assets Folder를 찾을 수 있다

 

2. GSON 라이브러리 및 Room Database import

 

아래 항목들을 app수준 gradle의 dependency 내에 추가한다.

 

- GSON

implementation 'com.google.code.gson:gson:2.8.6'

- Room

// Room
    def room_version = "2.2.2"

    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor

    // optional - Kotlin Extensions and Coroutines support for Room
    implementation "androidx.room:room-ktx:$room_version"

    // optional - RxJava support for Room
    implementation "androidx.room:room-rxjava2:$room_version"

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation "androidx.room:room-guava:$room_version"

    // Test helpers
    testImplementation "androidx.room:room-testing:$room_version"

여기서 Room 셋업을 하면서 조금 애를 먹었는데, 이를 해결하기 위해 상단의 android / defaultConfig 내에 하단 코드를 추가했다.

android {
	...
    
    defaultConfig { 
    
    	...
		
        // Room 설정을 위해 추가한 부분
        javaCompileOptions {
            annotationProcessorOptions {
                arguments = [
                        "room.schemaLocation":"$projectDir/schemas".toString(),
                        "room.incremental":"true",
                        "room.expandProjection":"true"]
            }
        }
        
        ...
    }

 

3. Json 파일로부터 만들고자 하는 Data class를 정의

@Entity(tableName= "sample")
data class SampleData(

    @PrimaryKey(autoGenerate = false)
    @ColumnInfo(name = "name")
    var name: String,

    @ColumnInfo(name = "location")
    var location: String,

    @ColumnInfo(name = "initial")
    @TypeConverters(SampleTypeConverter::class)
    @SerializedName("reservations")
    var reservations: List<Reservations>?,

    @ColumnInfo(name = "is_full")
    var is_full: Int
)

Json파일로부터 Parsing해 받아올 데이터를 Room 데이터 클래스로 정의한다.

이때 컬럼들은 Json이 담고있는 형식 및 이름을 같게 해준다.

 

혹 json의 특정 부분이 배열을 포함하고 있는 경우에는 상단 코드와 같이 List<배열의내용을담은클래스> 를 선언하고,

이를 TypeConvert를 달아 처리를 해주어야만 문제없이 Parsing이 가능해진다.

 

 

(3-1) 필요한 경우에 따라 TypeConverter 추가 정의

class SampleTypeConverter {
    companion object {

        @TypeConverter
        @JvmStatic
        fun fromString(value: String?): List<Reservations?>? {
            val listType: Type =
                object : TypeToken<List<Reservations?>?>() {}.type
            return Gson().fromJson(value, listType)
        }

        @TypeConverter
        @JvmStatic
        fun listToString(list: List<Reservations?>?): String? {
            val gson = Gson()
            return gson.toJson(list)
        }
     }
}

TypeConverter는 리스트 형식의 데이터를 Room에 저장하고, 또 불러올 수 있게 해주는 클래스로 리스트가 포함된 경우 참조해

필수적으로 구현하자.

 

4. Json 파일을 String 객체로 Parsing > Gson 사용해 List 뽑아내기

private fun parseJson(): List<SampleData> {
        val gson = Gson()
        val testString: String

        // 파일 입력에 오류가 있을 경우의 예외처리
       try {
            testString = applicationContext.assets.open("FILE.json")
            .bufferedReader()
            .use {it.readText()}
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
            return emptyList()
        }

        return gson.fromJson(testString, Array<SampleData>::class.java).toList()
    }

이제 데이터 정의가 다 끝났으면 function을 적당히 정의해 집어넣어둔 Json 파일을 가져오자.

gson 객체를 정의하고, testString에 1차적으로 Json파일을 String화 > 이를 gson.fromJson()메소드를 사용해 List형태로 뽑아낼 수 있게 된다.