: non-null 변수에 null이 들어감;;
data class Employee(
val id: Int,
val name: String,
)
여기서 {"name":"Marketing"} 이런식으로 보내면 Employee(null, “Sangeun”) 와 같이 들어감.
여기서 포인트는 no 변수가 non-null이라는 것. 개무시하고 null이 들어가는데, 문법상 저 변수는 non-null이기 때문에 코드 작성시 널체크가 무의미하다고 lint가 경고를 해댐~
data class Employee(
val id: Int,
val name: String = "상은",
)
이렇게 디폴트 밸류를 해놔도 응답에서 {”id”:13, "name":"Sangeun"} 이렇게 준다면 Employee(13, “Sangeun”)이 됨.
→ non-null변수에 null이 들어왔을때 에러 (Gson이랑의 차이점)
data class Employee(
val id: Int,
val name: String, // null이 들어오면 에러뱉음.
)
이렇게 디폴트 밸류를 해놔도 응답에서 {”id”:13, "name":"null"} 이렇게 준다면 응답이 우선이니까 null이 들어가겠죠? 근데 타입을 중요하게 생각하는 kotlinx-serialization은 에러를 뱉음!(name은 non-null변수이므로)
→ 이때는 val json = Json { coerceInputValues = true }
옵션을 이용하면 됩니다용 (코드 하단 참조)
data class Employee(
val id: Int,
val name: String,
)
{"no":13,"name":"상은","nickName":"Wow!!!"} 여기서 nickName처럼 모델에 없는 키값이 들어온다면 에러를 뱉는다. val json = Json { ignoreUnknownKeys = true }
옵션을 쓰면 댐!
요청시와 응답시 디폴트밸류를 처리하는게 조금 다름.
data class Employee(
val id: Int,
val name: String = "상은",
)
Employee(id = 13)으로 보내면 {”id”:13} 이렇게 보내는 셈.
→ 이때는 val json = Json { encodeDefaults = true }
옵션을 이용하면 됩니다용 (코드 하단 참조)
data class Employee(
val id: Int,
val name: String = "상은",
)
{”id”:13} 이렇게만 받아도 Employee(13, “상은”)으로 받는셈이 된다!
package com.example.kotlinxserializationexample
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import com.example.kotlinxserializationexample.model.Dept
import com.example.kotlinxserializationexample.model.Dept2
import com.example.kotlinxserializationexample.model.Employee
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
@ExperimentalSerializationApi
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
makeDeptToJson()
makeJsonToDept()
makeDept2Json()
makeDeptIgnoreJson()
makeCoerceJson()
makeEncodeDefaultJson()
}
private fun makeDeptToJson() {
val dept = Dept(1, "Marketing", "USA/Seattle") // data class 생성
val deptJson = Json.encodeToString(dept) // data class -> Json 으로 변환
Log.d(
TAG,
deptJson
) // D/MainActivity: {"no":1,"name":"Marketing","location":"USA/Seattle"}
}
private fun makeJsonToDept() {
val dept = Dept(1, "Marketing", "USA/Seattle")
val deptJson = Json.encodeToString(dept)
val deptFromJson = Json.decodeFromString<Dept>(deptJson) // json string -> data class 로 변환
Log.d(TAG, deptFromJson.toString()) // Dept(no=1, name=Marketing, location=USA/Seattle)
}
private fun makeDept2Json() {
val employees = listOf(
Employee(0, "Smith"),
Employee(1, "Mike"),
Employee(2, "John")
)
val dept = Dept2(1, "Marketing", "USA/Seattle", employees)
val deptJson = Json.encodeToString(dept)
Log.d(TAG, deptJson)
/**
* { "no":1,
* "name":"Marketing",
* "location":"USA/Seattle",
* "employees":
* [{"no":0,"name":"Smith"},
* {"no":1,"name":"Mike"},
* {"no":2,"name":"John"}
* ]
* }
*/
val deptFromJson = Json.decodeFromString<Dept2>(deptJson)
Log.d(TAG, deptFromJson.toString())
/**
* Dept2(
* no=1,
* name=Marketing,
* location=USA/Seattle,
* employees=
* [Employee(no=0, name=Smith),
* Employee(no=1, name=Mike),
* Employee(no=2, name=John)]
* )
*/
// Json Option 1. pretty Json
val prettyJson = Json { prettyPrint = true }
val deptPrettyJson = prettyJson.encodeToString(dept)
Log.d(TAG, deptPrettyJson)
val deptFromPrettyJson = prettyJson.decodeFromString<Dept2>(deptPrettyJson)
Log.d(TAG, deptFromPrettyJson.toString())
}
private fun makeDeptIgnoreJson() {
val json = Json { ignoreUnknownKeys = true }
val deptJson = """ {"no":"1","name":"Marketing","location":"USA/Seattle","nickName":"Wow!!!"} """
val deptFromJson = json.decodeFromString<Dept>(deptJson)
Log.d(TAG, deptFromJson.toString()) // ept(no=1, name=Marketing, location=USA/Seattle)
}
/**
* Coercing input values (decoding: json -> data class)
* 강력한 type check 를 느슨하게 조정 (default 값 할당)
* - non null property 에 null 이 입력될 경우
* - enum 값을 담는 property 에 정해지지 않은 enum 이 들어오는 경우
*/
private fun makeCoerceJson() {
val json = Json { coerceInputValues = true }
val deptJson = """ {"no":"1","name":"Marketing","location":null} """
val deptFromJson = json.decodeFromString<Dept>(deptJson)
Log.d(TAG, deptFromJson.toString())
// default 값이 model 에 지정되어 있어야 null 이 들어와도 default 값으로 들어감
// D/MainActivity: Dept(no=1, name=Marketing, location=default)
// ** coerceInputValues 옵션이 설정되어있지 않으면? 에러남
}
/**
* Encoding defaults (encoding: data class -> json)
* 값이 설정되지 않도라도 data class 의 default 값이 json 에 기본값으로 출력되도록 하기 위해 사용
*/
private fun makeEncodeDefaultJson() {
val json = Json { encodeDefaults = true }
val dept = Dept(no = 1, name = "Marketing")
val deptFromJson = json.encodeToString(dept)
Log.d(TAG, deptFromJson)
// Dept 는 no, name 만 선언하고 이상태로 json 으로 encoding 하면 data class 의 location default 값이 나옴
// D/MainActivity: {"no":1,"name":"Marketing","location":"default"}
// ** encodeDefaults 옵션이 설정되어있지 않으면? 값이 없는 property 는 json 에 포함되지 않음 -> D/MainActivity: {"no":1,"name":"Marketing"}
}
companion object {
const val TAG = "MainActivity"
}
}
package com.example.kotlinxserializationexample.model
import kotlinx.serialization.Serializable
@Serializable
data class Dept(
val no: Int,
val name: String,
val location: String = "default"
)
@Serializable
data class Dept2(
val no: Int,
val name: String,
val location: String,
val employees: List<Employee>
)