Kotlin에서 Gson과 함께 TypeToken + 제네릭을 사용하는 방법


108

사용자 지정 클래스 (Turns)에서 제네릭 유형 목록을 가져올 수 없습니다.

val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)

그것은 말했다 :

cannot access '<init>' it is 'public /*package*/' in 'TypeToken'

답변:


236

이 인라인 재미를 만드십시오.

inline fun <reified T> Gson.fromJson(json: String) = fromJson<T>(json, object: TypeToken<T>() {}.type)

다음과 같이 호출 할 수 있습니다.

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

이전 대안 :

대안 1 :

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

당신은 넣어야 object :하고 특정 유형을fromJson<List<Turns>>


대안 2 :

@cypressious에서 언급했듯이 다음과 같은 방법으로도 달성 할 수 있습니다.

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

로 사용:

val turnsType = genericType<List<Turns>>()

4
: 당신은 또한 당신을 위해 수행하는 도우미 메서드 만들 수 있습니다inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
키릴 Rakhman

1
또는 Gson을 확장하여이를 수행하는 fromJson의 새로운 과부하를 갖습니다. Kotlin은 확장하도록 설계되었으므로 Gson을 확장하여 더 멋지게 만들고 TypeToken을 숨 깁니다.
Jayson Minard

이 답변은 Gson을 사용하는 많은 사람들이 볼 수 있기 때문에 답변을 더 완전하고 형식적으로 만드는 제안 된 편집을 만들었습니다. 답변에 설명을 추가하고 문제를 해결하는 데 사용 된 주제에 대한 Kotlin 참조 링크를 추가했습니다. 따라서 사람들은 여기에 포함 된 다른 모든 답변이나 댓글을 읽을 필요가 없습니다. 수정을 수락하면 아래에서 내 답변을 삭제할 수 있습니다.
Jayson Minard 2015

편집이 거부되었습니다. 모든 답변과 댓글을 하나의 일관된 답변으로 결합하는 전체 버전은 아래 내 답변을 참조하십시오. 자신의 대답을 수락했지만 완전하지 않습니다.
Jayson Minard 2015

kotlin 경고 제거 : inline fun <reified T> genericType () : Type? = 개체 : TypeToken <T> () {} .type
후안 멘데즈

28

이것은 문제를 해결합니다.

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

첫 번째 줄은 그로부터 내려온 객체 표현식 을 생성하고 그로부터 TypeTokenJava를 가져옵니다 Type. 그런 다음 Gson().fromJson메서드는 함수 결과에 대해 지정된 유형 ( TypeToken생성 된 것과 일치해야 함 )이 필요합니다. 이 작품의 두 가지 버전은 위와 같습니다.

val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)

더 쉽게 만들 수 있도록 TypeToken도움말 함수를 만들 수 있습니다.이 함수는 수정 된 유형 매개 변수를 사용할 수 있도록 인라인 이어야합니다 .

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

그런 다음 다음 방법 중 하나로 사용할 수 있습니다.

val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()

그리고 전체 프로세스는 Gson인스턴스 의 확장 함수로 래핑 될 수 있습니다 .

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)

따라서 Gson에 전화를 걸고 전혀 걱정하지 않아도 TypeToken됩니다.

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

여기서 Kotlin은 할당의 한쪽 또는 다른 쪽에서 유형 추론을 사용하고 인라인 함수가 전체 유형을 통과하도록 제네릭을 수정하고 (지우기없이)이를 사용하여 a를 생성하고 TypeTokenGson을 호출합니다.


1
안녕하세요 @Jayson, Android Studio에서 인라인으로 재미있게 작동하도록 만들 수 없습니다. 확인을하는 것 같지만 내가 할 때이 인식되지 않습니다Gson().fromJson<kotlin.List<Turns>>(pref.turns)
후안 Saravia

@juancho "인식되지 않음"이 무엇을 의미하는지 말해 줄 수 있습니까? 컴파일러 오류? 위에서 가져온 확장 방법이 있습니까?
Jayson Minard 2015

2
Android Studio에서 코드를 복사하여 붙여넣고 kotlin 클래스에서 재미를 가져 왔습니다. 나는 당신이 말한 것을 시도했지만 어떤 이유로 컴파일러는이 재미가 존재하지 않는다고 말합니다. 나는 이미 다른 확장 기능을 사용하고 있지만 귀하의 제안이 작동하지 않는지 모르겠습니다. 사용중인 AS 및 Kotlin 버전은 무엇입니까? 다시 시도해보세요.
Juan Saravia 2015

이것은 Android 스튜디오와 직접 관련이 없으며 Kotlin은 내부 또는 외부에서 동일합니다. 인스턴스를 생성하고 있습니까 Gson()아니면 Gson정적 인 것처럼 보이십니까? 첫 번째 인스턴스가 필요합니다.
Jayson Minard

21

다른 옵션 (다른 것보다 더 우아하게 보이는지 확실하지 않음)은 다음과 같은 호출 일 수 있습니다.

turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()

따라서 "pure Kotlin"대신 Java Array 클래스 1 개 라이너를 사용하고 있습니다.


2
TypeToken은 모든 전화기에서 안정적으로 작동하지 않기 때문에 이것이 저에게 가장 좋은 솔루션입니다. 순수한 코 틀린을 사용한 간편한 원 라이너.
LuckyMalaka

11
val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
    object : TypeToken<List<SaleItemResponse>>() {}.type)

kotlin에서 데이터 배열을 구문 분석하는 방법입니다.


이 대답은 짧고 간단해야합니다.
Umar Ata

6

나는 변환하려면이 같은 것을 사용 Tstring& String다시 T사용 Gson. 정확히 당신이 찾고있는 것이 아니라 혹시라도.

확장 선언

inline fun <reified T : Any> T.json(): String = Gson().toJson(this, T::class.java)
inline fun <reified T : Any> String.fromJson(): T = Gson().fromJson(this,T::class.java)

용법

// Passing an object to new Fragment
companion object {    
        private const val ARG_SHOP = "arg-shop"

        @JvmStatic
        fun newInstance(shop: Shop) =
                ShopInfoFragment().apply {
                    arguments = Bundle().apply {
                        putString(ARG_SHOP, shop.json())
                    }
                }
    }

// Parsing the passed argument
private lateinit var shop: Shop

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {
            shop = it.getString(ARG_SHOP).fromJson() ?: return
        }
    }

5

이것도 작동하며 더 간단합니다.

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)

반환 유형은 nullable이어야합니다. 그렇지 않으면 Gson 라이브러리의 자바 코드가 null을 반환 할 수 있지만 Kotlin은 유형이 null이 아닌 것으로 간주합니다. 결과적으로 Kotlin에서 NPE를 얻게됩니다.
fdermishin dec

1

generic reified functionGson의 Kotlin ArrayList<T>은이 코드 를 사용하도록 역 직렬화 합니다.

 inline fun <reified T> get( ... ): ArrayList<T>{
    
    val str = "[{},{}]"
    
    val type = TypeToken.getParameterized(ArrayList::class.java, T::class.java).type
    
    val t = Gson().fromJson<ArrayList<T>>(str, type)
    

    return t
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.