Ayfri
04/04/2023, 2:08 PM"type": "kotlin.collections.ArrayList"
string value inside my list. I tried a thousands things to remove it but it still doesn't work, I don't understand how to remove it because I don't need it.
When I use a custom serializer for the list that just serialize as a JsonArray of my LootEntries I still get the value.
I even tried to create a JsonTransformingSerializer for my list but in this serializer I don't have the first string element when I print my elements.
What am I doing wrong or what should I do to fix this ?Adam S
04/04/2023, 3:47 PMBen Woodworth
04/04/2023, 4:01 PM@Serializable
(without specifying a custom serializer) it'll use
PolymorphicSerializer
, which adds that type
entry:
https://github.com/Kotlin/kotlinx.serialization/blob/v1.5.0/core/commonMain/src/kotlinx/serialization/PolymorphicSerializer.kt#L83
If you're using your own custom serializer though I'm not sure how that would happenAyfri
04/04/2023, 7:54 PMAyfri
04/07/2023, 1:52 PMtypealias LootEntry = @Serializable(LootEntrySerialized.Companion.LootEntrySerializer::class) LootEntrySerialized
@Serializable
sealed interface LootEntrySerialized {
companion object {
object LootEntrySerializer : KSerializer<LootEntrySerialized> by serializer() {
override fun serialize(encoder: Encoder, value: LootEntrySerialized) {
require(encoder is JsonEncoder) { "LootTable can only be serialized with Json" }
encoder.encodeJsonElement(buildJsonObject {
put("type", JsonPrimitive("minecraft:${value::class.simpleName!!.snakeCase()}"))
Json.encodeToJsonElement(value).jsonObject.forEach { (key, value) ->
if (key != "type") put(key, value)
}
})
}
}
}
}
And here is one example of a LootEntry implementation :
@Serializable
data class Empty(
var quality: Int? = null,
var weight: Int? = null,
) : LootEntry
And here is which object I try to serialize :
@Serializable
data class LootPool(
var rolls: NumberProvider,
var bonusRolls: NumberProvider? = null,
var conditions: PredicateConditions? = null,
var entries: List<LootEntry>? = null,
var functions: List<String>? = null,
)
Ben Woodworth
04/07/2023, 4:13 PM/**
* Serializes a polymorphic value with its concrete serializer directly,
* instead of e.g. serializing an extra "type" discriminator entry.
*
* Only encoding is supported, and the [serializer] must be the default/generated polymorphic serializer.
*/
@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class)
class DirectPolymorphicSerializer<T : Any>(serializer: KSerializer<T>) : KSerializer<T> {
private val serializer = run {
require(serializer is AbstractPolymorphicSerializer<T>) {
"Serializer must be a ${AbstractPolymorphicSerializer::class.simpleName}"
}
serializer
}
// PolymorphicSerializer and SealedClassSerializer (the only implementors of AbstractPolymorphicSerializer
// within kotlinx.serialization) both have their polymorphic descriptor element named `value`.
private val valueDescriptor = serializer.descriptor.getElementDescriptor(
serializer.descriptor.getElementIndex("value")
)
override val descriptor: SerialDescriptor = SerialDescriptor(
"${DirectPolymorphicSerializer::class}<${this.serializer.baseClass}>",
valueDescriptor
)
override fun serialize(encoder: Encoder, value: T) {
val actualSerializer = serializer.findPolymorphicSerializer(encoder, value)
val directActualSerializer = if (actualSerializer is AbstractPolymorphicSerializer) {
DirectPolymorphicSerializer(actualSerializer)
} else {
actualSerializer
}
encoder.encodeSerializableValue(directActualSerializer, value)
}
override fun deserialize(decoder: Decoder): Nothing {
throw SerializationException("${DirectPolymorphicSerializer::class.simpleName} only supports encoding")
}
}
Ben Woodworth
04/07/2023, 4:19 PM@Serializable
sealed interface MySealedInterfaceSurrogate // Your actual sealed interface, like LootEntrySerialized
typealias MySealedInterface = @Serializable(MySealedInterfaceSerializer::class) MySealedInterfaceSurrogate
object MySealedInterfaceSerializer : KSerializer<MySealedInterface> by DirectPolymorphicSerializer(
MySealedInterfaceSurrogate.serializer()
)
Ayfri
04/07/2023, 4:50 PM"type": "kotlin.collections.ArrayList"
inside my list as the first element, but maybe it's my fault, I sent the wrong code.
Here is the actual problem :
@Serializable
data class LootPoolSerialized(
var rolls: NumberProvider,
var bonusRolls: NumberProvider? = null,
var conditions: List<PredicateCondition>? = null,
var entries: List<LootEntry>? = null,
var functions: List<String>? = null,
)
When I try to serialize this class, with conditions
being a list of one element that should serialize to {"raining": true"}
, I get this :
"conditions": [
"type": "kotlin.collections.ArrayList",
{
"raining": true
}
]
And currently I have in the PredicateCondition file this content :
typealias PredicateCondition = @Serializable(PredicateConditionSerializer::class) PredicateConditionSurrogate
@Serializable
sealed interface PredicateConditionSurrogate
object PredicateConditionSerializer : KSerializer<PredicateCondition> by DirectPolymorphicSerializer(
PredicateConditionSurrogate.serializer()
)
Ben Woodworth
04/07/2023, 5:07 PMJson.encodeToString(predicateCondition)
?Ayfri
04/07/2023, 5:10 PMBen Woodworth
04/07/2023, 5:21 PMAyfri
04/08/2023, 1:32 AM