admin管理员组

文章数量:1122846

Question

Why does the error java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType occur in the release build when making a request using Retrofit?

Context

  1. I am using the following libraries:

    • androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7
    • com.squareup.retrofit2:retrofit:2.9.0
    • com.squareup.retrofit2:converter-gson:2.9.0
    • com.google.code.gson:gson:2.10.1
  2. Here is the model code:

package com.byteflipper.ffsensitivities.data

import kotlinx.serialization.Serializable

@Serializable
data class Manufacturer(
    val showInProductionApp: Boolean,
    val isAvailable: Boolean,
    val name: String,
    val model: String
)

@Serializable
data class ManufacturerResponse(
    val manufacturers: List<Manufacturer>
)
  1. I am using Retrofit to fetch data:
package com.byteflipper.ffsensitivities.service

import com.byteflipper.ffsensitivities.data.ManufacturerResponse
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

interface ApiService {
    @GET("sensitivity_settings/manufacturers.json")
    suspend fun getManufacturers(): ManufacturerResponse
}

object RetrofitInstance {
    private const val BASE_URL = "/"

    val api: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}
  1. ViewModel
package com.byteflipper.ffsensitivities.viewmodel

import androidxpose.runtime.State
import androidxpose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.byteflipper.ffsensitivities.data.Manufacturer
import com.byteflipper.ffsensitivities.service.RetrofitInstance
import com.byteflipper.ffsensitivities.ui.UiState
import kotlinx.coroutines.launch
import java.UnknownHostException

class ManufacturerViewModel : ViewModel() {
    private val _uiState = mutableStateOf<UiState<List<Manufacturer>>>(UiState.Loading)
    val uiState: State<UiState<List<Manufacturer>>> = _uiState

    init {
        fetchManufacturers()
    }

    private fun fetchManufacturers() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val response = RetrofitInstance.api.getManufacturers()
                _uiState.value = UiState.Success(response.manufacturers)
            } catch (e: UnknownHostException) {
                _uiState.value = UiState.NoInternet
            } catch (e: Exception) {
                _uiState.value = UiState.Error("Ошибка загрузки данных: ${e.message}")
            }
        }
    }

    fun retry() {
        fetchManufacturers()
    }
}
  1. Release build config
buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        debug {
            applicationIdSuffix = ".debug"
        }
    }
  1. Everything works fine in the debug build, but the error occurs in the release build.
  2. Minify and Proguard are enabled (Gradle 8.10.2)

All source code here:

I tried to fix the error by changing Proguard rules to preserve the type information in Manufacturer and ManufacturerResponse:

# Gson requires keeping data classes and fields for serialization/deserialization.
-keep class com.byteflipper.ffsensitivities.data.** { *; }
-keepclassmembers class com.byteflipper.ffsensitivities.data.** {
    <fields>;
}

# Keep generic type information for Retrofit/Gson.
-keepattributes Signature
-keepclassmembers class * {
    @retrofit2.http.* <methods>;
}

Question

Why does the error java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType occur in the release build when making a request using Retrofit?

Context

  1. I am using the following libraries:

    • androidx.lifecycle:lifecycle-viewmodel-compose:2.8.7
    • com.squareup.retrofit2:retrofit:2.9.0
    • com.squareup.retrofit2:converter-gson:2.9.0
    • com.google.code.gson:gson:2.10.1
  2. Here is the model code:

package com.byteflipper.ffsensitivities.data

import kotlinx.serialization.Serializable

@Serializable
data class Manufacturer(
    val showInProductionApp: Boolean,
    val isAvailable: Boolean,
    val name: String,
    val model: String
)

@Serializable
data class ManufacturerResponse(
    val manufacturers: List<Manufacturer>
)
  1. I am using Retrofit to fetch data:
package com.byteflipper.ffsensitivities.service

import com.byteflipper.ffsensitivities.data.ManufacturerResponse
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET

interface ApiService {
    @GET("sensitivity_settings/manufacturers.json")
    suspend fun getManufacturers(): ManufacturerResponse
}

object RetrofitInstance {
    private const val BASE_URL = "https://raw.githubusercontent.com/ByteFlipper-58/FFSensitivities/refs/heads/master/app/src/main/assets/"

    val api: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }
}
  1. ViewModel
package com.byteflipper.ffsensitivities.viewmodel

import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.byteflipper.ffsensitivities.data.Manufacturer
import com.byteflipper.ffsensitivities.service.RetrofitInstance
import com.byteflipper.ffsensitivities.ui.UiState
import kotlinx.coroutines.launch
import java.net.UnknownHostException

class ManufacturerViewModel : ViewModel() {
    private val _uiState = mutableStateOf<UiState<List<Manufacturer>>>(UiState.Loading)
    val uiState: State<UiState<List<Manufacturer>>> = _uiState

    init {
        fetchManufacturers()
    }

    private fun fetchManufacturers() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val response = RetrofitInstance.api.getManufacturers()
                _uiState.value = UiState.Success(response.manufacturers)
            } catch (e: UnknownHostException) {
                _uiState.value = UiState.NoInternet
            } catch (e: Exception) {
                _uiState.value = UiState.Error("Ошибка загрузки данных: ${e.message}")
            }
        }
    }

    fun retry() {
        fetchManufacturers()
    }
}
  1. Release build config
buildTypes {
        release {
            isMinifyEnabled = true
            isShrinkResources = true
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
        debug {
            applicationIdSuffix = ".debug"
        }
    }
  1. Everything works fine in the debug build, but the error occurs in the release build.
  2. Minify and Proguard are enabled (Gradle 8.10.2)

All source code here: https://github.com/ByteFlipper-58/FFSensitivities2/tree/master/app/src/main/java/com/byteflipper/ffsensitivities

I tried to fix the error by changing Proguard rules to preserve the type information in Manufacturer and ManufacturerResponse:

# Gson requires keeping data classes and fields for serialization/deserialization.
-keep class com.byteflipper.ffsensitivities.data.** { *; }
-keepclassmembers class com.byteflipper.ffsensitivities.data.** {
    <fields>;
}

# Keep generic type information for Retrofit/Gson.
-keepattributes Signature
-keepclassmembers class * {
    @retrofit2.http.* <methods>;
}
Share Improve this question asked Nov 23, 2024 at 13:38 IbremMiner837IbremMiner837 12 bronze badges
Add a comment  | 

2 Answers 2

Reset to default 0

you need to use moshi library for this case,

You can read all document for Moshi: https://github.com/square/moshi

Can you try this code

1: impl

implementation("com.squareup.moshi:moshi-kotlin:1.15.0")

2:

android.enableR8.fullMode=true

3:

object RetrofitInstance {
private const val BASE_URL = "https://raw.githubusercontent.com/ByteFlipper-58/FFSensitivities/refs/heads/master/app/src/main/assets/"

private val moshi: Moshi by lazy {
    Moshi.Builder()
        .add(KotlinJsonAdapterFactory()) 
        .build()
}

val api: ApiService by lazy {
    Retrofit.Builder()
        .baseUrl(BASE_URL)
        .addConverterFactory(MoshiConverterFactory.create(moshi))
        .build()
        .create(ApiService::class.java)
   }
}

4:

data class Manufacturer(
@Json(name = "showInProductionApp") val showInProductionApp: Boolean,
@Json(name = "isAvailable") val isAvailable: Boolean,
@Json(name = "name") val name: String,
@Json(name = "model") val model: String
)

5:

# Keep metadata for serialization
-keepattributes *Annotation*
-keep class kotlinx.serialization.** { *; }
-keepclassmembers class **$Companion { *; }
-keepclasseswithmembers class * {
@kotlinx.serialization.Serializable <fields>;
}
-keep @kotlinx.serialization.Serializable class *

# Keep your data models
-keep class com.byteflipper.ffsensitivities.data.** { *; }

6: in build.gradle

buildTypes {
release {
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
  }
 }

The same error, but I managed to get slightly more detailed logs:

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
                                                                                                        at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:46)
                                                                                                        at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:39)
                                                                                                        at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:202)
                                                                                                        at retrofit2.Retrofit$1.invoke(Retrofit.java:160)
                                                                                                        at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
                                                                                                        at $Proxy3.getManufacturers(Unknown Source)
                                                                                                        at com.byteflipper.ffsensitivities.viewmodel.ManufacturerViewModel$fetchManufacturers$1.invokeSuspend(ManufacturerViewModel.kt:26)
                                                                                                        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
                                                                                                        at kotlinx.coroutines.internal.DispatchedContinuationKt.resumeCancellableWith(DispatchedContinuation.kt:256)
                                                                                                        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable(Cancellable.kt:30)
                                                                                                        at kotlinx.coroutines.intrinsics.CancellableKt.startCoroutineCancellable$default(Cancellable.kt:25)
                                                                                                        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:110)
                                                                                                        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
                                                                                                        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
                                                                                                        at kotlinx.coroutines.BuildersKt.launch(Unknown Source:1)
                                                                                                        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch$default(Builders.common.kt:47)
                                                                                                        at kotlinx.coroutines.BuildersKt.launch$default(Unknown Source:1)
                                                                                                        at com.byteflipper.ffsensitivities.viewmodel.ManufacturerViewModel.fetchManufacturers(ManufacturerViewModel.kt:23)
                                                                                                        at com.byteflipper.ffsensitivities.viewmodel.ManufacturerViewModel.<init>(ManufacturerViewModel.kt:19)
package com.byteflipper.ffsensitivities.viewmodel

import android.util.Log
import androidx.compose.runtime.State
import androidx.compose.runtime.mutableStateOf
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.byteflipper.ffsensitivities.data.Manufacturer
import com.byteflipper.ffsensitivities.service.RetrofitInstance
import com.byteflipper.ffsensitivities.ui.UiState
import kotlinx.coroutines.launch
import java.net.UnknownHostException

class ManufacturerViewModel : ViewModel() {
    private val _uiState = mutableStateOf<UiState<List<Manufacturer>>>(UiState.Loading)
    val uiState: State<UiState<List<Manufacturer>>> = _uiState

    init {
        fetchManufacturers()
    }

    private fun fetchManufacturers() {
        viewModelScope.launch {
            _uiState.value = UiState.Loading
            try {
                val response = RetrofitInstance.api.getManufacturers()
                _uiState.value = UiState.Success(response.manufacturers)
            } catch (e: UnknownHostException) {
                _uiState.value = UiState.NoInternet
            } catch (e: Exception) {
                Log.e("RetrofitError", "Ошибка загрузки данных", e)
                _uiState.value = UiState.Error("Ошибка загрузки данных: ${e.localizedMessage}")
            }
        }
    }

    fun retry() {
        fetchManufacturers()
    }
}

本文标签: kotlinError javalangClass cannot be cast to javalangreflectParameterizedTypeStack Overflow