I'm encountering the following error:
Serializer for class 'Any' is not found.
Please ensure that class is marked as '@Serializable' and that the serialization compiler plugin is applied.
I tried the solution mentioned here, but it didn't work for me.
Here’s the code where the error occurs:
class UserAuthentication {
private val supabase = createSupabaseClient(
supabaseKey = "MySupabaseKey",
supabaseUrl = "MySupabaseUrl"
) {
install(io.github.jan.supabase.auth.Auth)
install(Postgrest)
}
private lateinit var credentialManager: CredentialManager
fun initializeCredentialManager(context: Context) {
credentialManager = CredentialManager.create(context)
val rawNonce = UUID.randomUUID().toString()
val bytes = rawNonce.toByteArray()
val messageDigest = MessageDigest.getInstance("SHA-256")
val digest = messageDigest.digest(bytes)
val hashedNonce = digest.fold("") { str, it -> str + "%02x".format(it) }
val googleIdOption: GetGoogleIdOption =
GetGoogleIdOption.Builder().setFilterByAuthorizedAccounts(false)
.setServerClientId("MyServerClientID")
.setNonce(hashedNonce).build()
val credentialRequest: GetCredentialRequest =
GetCredentialRequest.Builder().addCredentialOption(googleIdOption).build()
GlobalScope.launch {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
try {
val result = credentialManager.getCredential(
request = credentialRequest,
context = context,
)
val credential = result.credential
val googleIdTokenCredential =
GoogleIdTokenCredential.createFrom(credential.data)
val googleIdToken = googleIdTokenCredential.idToken
supabase.auth.signInWith(IDToken) {
idToken = googleIdToken
provider = Google
nonce = rawNonce
}
// Retrieve the user_id from Supabase
val session = supabase.auth.currentSessionOrNull()
// Extract user details from credential
val email = googleIdTokenCredential.id
val userName = googleIdTokenCredential.displayName
val userId = session?.user?.id // This is the Supabase UUID
// Check if the user exists in Supabase and add if not
handleUserAuthentication(context,userId, userName, email)
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Log.d("Error initializeCredentialManager", e.message.toString())
Toast.makeText(context, "Error:-"+e.message, Toast.LENGTH_SHORT).show()
}
}
}
}
}
private suspend fun handleUserAuthentication(
context: Context,
userId: String?,
userName: String?,
email: String?
) {
if (userId == null || userName == null) {
withContext(Dispatchers.Main) {
Toast.makeText(context, "User ID or Username is missing!", Toast.LENGTH_SHORT).show()
}
return
}
try {
// Check if the user exists
val userExists = withContext(Dispatchers.IO) {
supabase.from("Table_User_Data")
.select { filter { eq("user_id", userId) } }
.decodeList<Map<String, Any>>()
.isNotEmpty()
}
// If user does not exist, insert a new record
if (!userExists) {
val newUser = mapOf(
"user_id" to userId,
"UserName" to userName,
"EmailID" to email,
"LatestScanDate" to null,
"LatestPurchaseTokensTimestamp" to null,
"LatestPurchaseToken" to null,
"SubscriptionActive" to false
)
val insertResult = withContext(Dispatchers.IO) {
supabase.from("Table_User_Data")
.insert(newUser) {
select() // This ensures that the inserted data is returned
}
.decodeSingle<Map<String, Any>>() // Decodes the result into the expected type to confirm success
}
// Notify user of successful insertion
withContext(Dispatchers.Main) {
Toast.makeText(context, "New user added successfully!", Toast.LENGTH_SHORT).show()
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(context, "User already exists!", Toast.LENGTH_SHORT).show()
}
}
} catch (e: Exception) {
// Handle exceptions
withContext(Dispatchers.Main) {
Log.d("Error handleUserAuthentication", e.message.toString())
Toast.makeText(context, "Error: ${e.message}", Toast.LENGTH_SHORT).show()
}
}
}
}
Additional Context:
Any suggestions on how to resolve this issue?
EDIT:- When i debug, this line is returning the code to catch block and showing me the error
.decodeList<Map<String, Any>>()
I resolved the issue by creating a data class
for the user data and marking it with the @Serializable
annotation from Kotlinx Serialization:
import kotlinx.serialization.Serializable
@Serializable
data class UserData(
val user_id: String,
val UserName: String?,
val EmailID: String?,
val LatestScanDate: String?,
val LatestPurchaseTokensTimestamp: String?,
val LatestPurchaseToken: String?,
val SubscriptionActive: Boolean
)
Then, I updated the code to use this UserData
class in the decoding operation:
// Check if the user exists
val userExists = withContext(Dispatchers.IO) {
supabase.from("Table_User_Data")
.select { filter { eq("user_id", userId) } }
.decodeList<UserData>() // Specify UserData as the type
.isNotEmpty()
}
This ensures the decodeList
function knows the type it's working with, resolving the error.