티스토리 뷰
최근에는 대부분 API 응답이 JSON 형식으로 다양한 데이터를 전달합니다.
Rest API 통신 Data로 다양한 형태를 받을 수 있습니다.
하나의 예시를 들어보겠습니다. 만약, API 응답이 다음과 같은 형태로 주어진다면 이를 어떻게 처리할 수 있을까요
[
{
"type": "TRUCK",
"waterCannon": true
},
{
"type": "PLANE",
"wingsSpanInMeters": 20
}
]
Response Dto 를 다음과 같이 구성해서 받을 준비는 하고 있지 않은지 묻고 싶습니다.
class Veichle {
type : String
waterCannon : Boolean
wingsSpanInMeters : Int
}
예시로 TRUCK 과 PLANE 을 두었는데요.
만약 BIKE, TAXI 와 같이 계속 증가한다면 Veichle class의 값들은 많아지고 Veichle의 역할은 모호해지게 됩니다.
어떻게 하면 다형성을 유지하면서 Single Json Response 을 받을 수 있을까요?
이 고민을 풀어줄 3th part libray 인 Moshi 를 제공하고 있습니다. 이번 시간은 Moshi 라이브러리에 대해서 간단히 알아보겠습니다.
Moshi Library 맛보기
Moshi 는 Signle Json Response 에서 다형성을 유지하도록 도와주는 3th part Library 입니다.
Moshi를 사용하기 위해 app.bundle
에 dependencies Moshi 를 등록해보겠습니다.
dependencies{
// Moshi
implementation 'com.squareup.moshi:moshi:1.14.0'
implementation 'com.squareup.moshi:moshi-adapters:1.14.0'
implementation 'com.squareup.moshi:moshi-kotlin:1.12.0'
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
}
Dependencies 구성이 완료 되었으면, Vehicle의 JSON 데이터를 Moshi를 사용하여 가져오기 위한 DataContainer 설정 방법을 설명드리겠습니다.
먼저, VehicleType enum class 를 선언하여 TRUCK 과 PLANE 을 설정합니다. 이렇게 하면 Mosh에서 VehicleType 을 활용해서 타입을 구분 할 수 있습니다.
그 다음 JSON 파싱을 위한 Data class 을 생성합니다. 여기서 주의할 점은 @JsonClass(generateAdpater) 인 Annotation을 선언하는 것입니다. 또한, 각 JSON 필드는 @JSON Annotation 을 선언하여 파싱할 수 있도록 합니다.
지금까지 설명한 DataContainer 는 다음과 같습니다.
/***
* Vehicle
*/
enum class VehicleType {
TRUCK,
PLANE
}
interface Vehicle {
val type: VehicleType
}
@JsonClass(generateAdapter = true)
data class Truck(
@Json(name = "waterCannon") val waterCannon: Boolean
) : Vehicle {
override val type = VehicleType.TRUCK
}
@JsonClass(generateAdapter = true)
data class Plane(
@Json(name = "wingsSpanInMeters") val wingsSpanInMeters: Int
) : Vehicle {
override val type = VehicleType.PLANE
}
inline fun <reified T> Moshi.parseList(jsonString: String): List<T>? {
return adapter<List<T>>(Types.newParameterizedType(List::class.java, T::class.java)).fromJson(jsonString)
}
이제 데이터 파싱을 위한 Moshi 설정 방법을 설명하겠습니다.
Moshi 는 다형성을 지원하기 위해 PolymorphicJsonAdapterFacotry
를 사용할 수 있습니다.
이를 통해 JSON 데이터의 특정 필드 값을 기준으로 여러 타입의 객체를 구분할 수 있습니다.
Vehicle
클래스를 설정하고, type
필드를 구분자로 사용하여 waterCannon
과 wingsSpanInMeters
설정할 수 있습니다.
val vehicleFactory = PolymorphicJsonAdapterFactory.of(Vehicle::class.java, "type")
.withSubtype(Truck::class.java, VehicleType.TRUCK.name)
.withSubtype(Plane::class.java, VehicleType.PLANE.name)
val moshi = Moshi.Builder()
.add(vehicleFactory)
.add(KotlinJsonAdapterFactory())
.build()
val response = "[\n" +
" {\n" +
" \"type\": \"TRUCK\",\n" +
" \"waterCannon\": true\n" +
" },\n" +
" {\n" +
" \"type\": \"PLANE\",\n" +
" \"wingsSpanInMeters\": 20\n" +
" }\n" +
" ]"
val vehicleList = moshi.parseList(response) ?: kotlin.run {
print("Error Null")
return
}
for ((index, vehicle) in vehicleList.withIndex()) {
when (vehicle.type) {
VehicleType.PLANE -> {
val wingsSpanInMeters = (vehicle as Plane).wingsSpanInMeters
Log.d("@@@ VehicleTest @@@", "inedx = $index, wingsSpanInMeters = $wingsSpanInMeters")
}
VehicleType.TRUCK -> {
val waterCannon = (vehicle as Truck).waterCannon
Log.d("@@@ VehicleTest @@@", "inedx = $index, waterCannon = $waterCannon")
}
}
}
Q. key 로 선언 한 값이 없는 경우 어떻게 동작하나요? A. Moshi 를 사용 했을 때 API Response 에서 key 가 존재하지 않으면 Exception 발생하게됩니다. 만약 Retrofit 을 활용하여 Moshi 를 구현 하였을 경우는 API Fail 처리 됩니다. |
Retrofit 을 활용한 Moshi 구성 :Step-by-Step
Retrofit 에서 Moshi 을 활용해서 Data 의 다형성을 지원하는 환경 구성할 수 있습니다.
1. 의존성 추가
먼저, Moshi 라이브러리와 함께 Retrofit를 프로젝트에 추가해야 합니다. build.gradle
파일에 다음과 같이 추가합니다.
dependencies{
implementation "com.squareup.moshi:moshi:1.14.0"
implementation 'com.squareup.moshi:moshi-adapters:1.14.0'
implementation("com.squareup.moshi:moshi-kotlin:1.12.0")
// Retrofit2, Gson converter, Gson
implementation 'com.squareup.retrofit2:retrofit:2.9.
implementation 'com.squareup.retrofit2:converter-moshi:2.9.0'
}
2. Moshi 설정
Moshi를 설정합니다. 다형성을 지원하기 위해 PolymorphicJsonAdapterFactory
를 사용할 수 있습니다.
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import com.squareup.moshi.adapters.PolymorphicJsonAdapterFactory
val moshi = Moshi.Builder()
.add(
PolymorphicJsonAdapterFactory.of(Vehicle::class.java, "type")
.withSubtype(Truck::class.java, VehicleType.TRUCK.name)
.withSubtype(Plane::class.java, VehicleType.PLANE.name)
)
.add(KotlinJsonAdapterFactory())
.build()
3. Retrofit 설정
Retrofit을 설정하여 Moshi를 JSON 변환기로 사용합니다.
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("https://api.example.com/") // API의 기본 URL
.addConverterFactory(MoshiConverterFactory.create(moshi))
.build()
4. API 인터페이스 정의
API 엔드포인트를 정의하는 인터페이스를 작성합니다.
Retrofit의 애노테이션을 사용하여 HTTP 메서드와 엔드포인트를 지정합니다.
interface ApiService {
@GET("REST API PATH")
suspend fun getVehicles(): Response<List<Vehicle>>?
}
5. API 호출
Retrofit 인스턴스에서 API 인터페이스의 구현을 생성하고 API를 호출합니다.
class MainViewModel : ViewModel(){
fun startRestAPI(){
viewModelScope.launch {
val apiService: ApiService = retrofit.create(ApiService::class.java)
val model = apiService.getVehicles()
}
}
}
이렇게 구성하면 Moshi와 Retrofit을 사용하여 API 클라이언트를 구성하고 API를 호출할 수 있게 됩니다.
이로써Moshi의 다형성 지원 기능을 활용하여 다양한 타입의 JSON 데이터를 쉽게 파싱할 수 있습니다.
마무리
Moshi 를 활용하면 다양한 타입의 JSON 을 파싱 할 수 있습니다.
특히, 다형성 JSON 데이터를 다룰 때 PolymorphicJsonAdapterFactory
를 사용하여 쉽게 처리할 수 있습니다.
API 구성 시 type을 통한 데이터 구성이 많을 경우 Moshi의 도입은 생각해 볼 필요가 있습니다.
Moshi는 직관적인 설정과 강력한 기능 제공으로 복잡한 JSON 구조도 간단하게 파싱할 수 있도록 도와줍니다.
Retrofit 에서도 Moshi의 활용은 고려해볼 필요가 있습니다. Moshi의 어댑터를 통해 다양한 JSON 형식을 유연하게 처리할 수 있으며, Moshi는 Kotlin 지원도 뛰어나므로 Kotlin 프로젝트에서 자연스럽게 통합하여 사용 할 수 있습니다.
API 설계나 유지보수 시 다양한 타입의 JSON을 다뤄야하다면, Moshi 도입은 고려하는 것을 추천드립니다. 그로 인해 코드의 가독성 및 유지보수성이 높이고, 더 나은 데이터 파싱 경험을 할 수 있을것으로 생각됩니다.
참고
'프로그래밍 > Android' 카테고리의 다른 글
센서의 정확도 올리는 방법 (0) | 2024.08.27 |
---|---|
Data Binding 사용법 (0) | 2024.08.26 |
GitHub Copilot 사용해보기 (0) | 2024.04.20 |
AttributeSet 정의해서 사용해보기 (0) | 2023.08.22 |
Tasks 과 Back Stack 에 대해서 알아보자 (0) | 2023.08.17 |
- 미션차이나센터
- MCC
- missioon
- DI
- 패턴
- Kotlin
- 고시문
- Android
- 점수판
- push
- 코틀린
- missionchina
- RXjava
- 고시문헬퍼
- IT
- java
- view
- 안드로이드
- 스코어헬퍼
- 선교
- swift
- Android Studio
- 탁구
- 알고리즘
- flutter
- 디자인패턴
- IOS
- 임용고시
- issue
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |