I have a project that uses a library to save serialized objects in items and loads them again, when needed.
To do the de-/serialization, this library uses Gson.
Due to how Gson works and how the library is set up, I can't add support for custom types easily and thus have to rely heavily on reflection.
I don't like this, but it has to be like this, sadly.
I am asking, whether there is a way to make this code use more Kotlin idioms.
My issue is that because the fields I am accessing are private, the usual reflection using ::
doesn't work.
Anyways, here is my code:
/**
* Registers a custom GSON handler to handle the [Location] class.
*/
private fun registerGsonHandlers() {
logger.entering(LobbyMain::class, "registerGsonHandlers")
// Gets private static final Gson gson = new Gson();
val fGson = NBTReflectionUtil::class.java.getDeclaredField("gson")
fGson.isAccessible = true
val modifiersField = Field::class.java.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(fGson, fGson.modifiers and Modifier.FINAL.inv())
// Gets private final List<TypeAdapterFactory> factories;
val fFactories = Gson::class.java.getDeclaredField("factories")
fFactories.isAccessible = true
val factories = fFactories.get(fGson.get(null)) as List<*>
// Sets private static final Gson gson
fGson.set(null, GsonBuilder().apply {
registerTypeAdapter(Location::class.java, LocationTypeAdapter)
factories.forEach { this::registerTypeAdapterFactory }
}.create())
logger.exiting(LobbyMain::class, "registerGsonHandlers")
}
It pulls the Gson
object out of the NBTReflectionUtil
class, makes it modifiable and gets its list of TypeAdapterFactories
.
I then create a new Gson
object with all the old TypeAdapter
s and mine added and set it as the new Gson
object for the library.
1 Answer 1
I'd group your code to make it more readable. Something like this:
fun getGson(): Field {
val fGson = NBTReflectionUtil::class.java.getDeclaredField("gson")
fGson.isAccessible = true
}
fun removeFinalModifier(field: Field) {
val modifiersField = Field::class.java.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(fGson, fGson.modifiers and Modifier.FINAL.inv())
}
// etc