Sazonally, I improve my knowledge through a little app I have, called Words. It was my first Android app, which the main purpose is to be a hangman game. The user will have a tip category and a word to guess. Very simple.
When I created Words two years ago, the words and category were just a mocked list with 1000 words in English and 1000 words in Portuguese. But today, seeking to apply new things to it, the words are generated through Firebase AI Logic APIs, and it generates words for all Latin languages available. With all this context, now I can start to talk about the title of this post.

The way I was using Vertex AI (from Firebase AI Logic) was really poor. The prompt was really big, and it was causing token exhaustion and a lot of costs for nothing. After reading the Firebase docs, I found that I can configure the AI to return in a JSON-like way. Pretty helpful! With this, I could reduce the prompt from 30 lines to 2, and as you can imagine, to parse the JSON-like string returned, I chose the GSON library. It was pretty cool since we usually test these things through the debug build, which does not have R8 enabled.
Here’s the problem. Test was performed in debug build. I just realized the problem with GSON after attempt to Android Expert Proguard class managed by Neto Marin, and he told us exactly about GSON.
The problem with GSON is that it uses reflection under the hood, and R8 was enabled in my project. Reflection is frequently a problem because R8 think the class is not being used in build time, and erases it; the moment Gson tries to access it, we’ll get an error.
To be more visual, I created two data classes:
data class CategoryWrapper(
val name: String,
val words: List<String>
)
data class CategoriesWrapper(
val categories: List<CategoryWrapper>
)
And used it like this:
val responseText = contentResponse.text ?: return emptyMap()
val gson = Gson()
val categoriesWrapper = gson.fromJson(responseText,CategoriesWrapper::class.java)
fromJson will call CategoriesWrapper thourgh reflection, and the following logging appears (only when R8 minify is enabled):
Error generating words: Abstract classes can't be instantiated! Adjust the R8 configuration or register an InstanceCreator or a TypeAdapter for this type. Class name: com.machado001.words.domain.CategoriesWrapper
See https://github.com/google/gson/blob/main/Troubleshooting.md#r8-abstract-class
Thankfully, the fromJson call was inside a try-catch block, so the user wouldn’t face an ANR, but a core part of my app’s logic stopped working silently.
There are a lot of solutions, like manually configuring R8 not to remove this class (by using @Keep or configuring your proguard file), but the one I’ve chosen was to just replace Gson with Kotlinx Serialization. Since the main advantage of R8 is obfuscate your code, create rules to bypass a runtime crash sounds like a workaround for me. That’s the reason i’ve preferred switch to kotlinx serialization.
I also decided to create a new build type called debugR8, which just extends the debug build enabling R8 minify, just for convenience and avoiding sign a release build with my debug key only for test every time:
buildTypes {
...
debugR8 {
initWith(getByName("debug"))
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
Thanks to Neto Marin’s class I could catch this bug and fix it, and started to look more criteriously to libraries that use reflection.
If you’re curious about Words App, take a look here:
https://words-ai.app/