How i can make a custom encode/decode for CHAR type using GSON library with Kotlin?
My current code don't work and it don't stop on debug.
Appear that type don't match.
My code:
data class Test(
var typeChar: Char,
)
private fun createGson(): Gson {
val builder = GsonBuilder()
// char
builder.registerTypeAdapter(
Char::class.java,
JsonDeserializer<Any?> { json, _, _ ->
try {
Char(json.asJsonPrimitive.asInt)
} catch (e: Exception) {
// ignore
}
null
},
)
builder.registerTypeAdapter(
Char::class.java,
com.google.gson.JsonSerializer<Char?> { value, _, _ ->
JsonPrimitive(value.code)
},
)
return builder.create()
}
Can anyone help me?
I tried a sample code above and search on github gson repository for infos.
CodePudding user response:
The problem is that there are two different types representing characters in Java, char
, the primitive type, and Character
, the wrapper. The Kotlin type Char
can be mapped to either, depending on whether the field is nullable or not. As a result, you have to map both types. This is also mentioned by docs for the registerTypeAdapter
method,
This registers the type specified and no other types: you must manually register related types! For example, applications registering boolean.class should also register Boolean.class.
In your case, this means that you need to register your serializer and deserializer for both Char::class.java
and Character::class.java
:
private fun createGson(): Gson {
val builder = GsonBuilder()
builder.registerTypeAdapter(
Char::class.java,
JsonDeserializer<Any?> { json, _, _ ->
try {
Char(json.asJsonPrimitive.asInt)
} catch (e: Exception) {
null
}
},
)
builder.registerTypeAdapter(
Character::class.java,
JsonDeserializer<Any?> { json, _, _ ->
try {
Char(json.asJsonPrimitive.asInt)
} catch (e: Exception) {
null
}
},
)
builder.registerTypeAdapter(
Char::class.java,
JsonSerializer<Char?> { value, _, _ ->
JsonPrimitive(value.code)
},
)
builder.registerTypeAdapter(
Character::class.java,
JsonSerializer<Char?> { value, _, _ ->
JsonPrimitive(value.code)
},
)
return builder.create()
}
Also, note the implementation of JsonDeserializer
, the null
has to be inside the catch, otherwise, it would always return null
.
With some refactoring, we can simplify this in the following way:
private fun createGson(): Gson {
val builder = GsonBuilder()
val customCharSerializer = object : JsonDeserializer<Any?>, JsonSerializer<Char?> {
override fun deserialize(json: JsonElement, typeOfT: Type?, context: JsonDeserializationContext?): Any? {
return try {
Char(json.asJsonPrimitive.asInt)
} catch (e: Exception) {
null
}
}
override fun serialize(src: Char?, typeOfSrc: Type?, context: JsonSerializationContext?): JsonElement? {
return src?.let { JsonPrimitive(it.code) }
}
}
builder.registerTypeAdapter(Char::class.java, customCharSerializer,)
builder.registerTypeAdapter(Character::class.java, customCharSerializer,)
return builder.create()
}