3

Is it possible to encode / decode any valid json objects in string format in a custom serializer. For example the code below but not let it serialize as json string but as any valid JSON with unknown structure?

object JsonObjectSerializer : KSerializer<JsonObject> {

    override val descriptor = PrimitiveSerialDescriptor("JsonObject", PrimitiveKind.STRING)

    override fun deserialize(decoder: Decoder): JsonObject =
        JsonObject(decoder.decodeString())

    override fun serialize(encoder: Encoder, value: JsonObject): Unit =
        encoder.encodeString(value.encode())
}

Out would be something like..

{
    "some": "data",
    "jsonObject": "{\"this\": \"should not be a string\"}"
}

But wanted output would be..

{
    "some": "data",
    "jsonObject": {"this": "should not be a string"}
}
Chris
  • 8,168
  • 8
  • 36
  • 51
  • Have you found any solutions to this? It seems like Jackson provides this (at least in the serialization side) through the `@JsonRawValue` annotation, but I can't seem to find the same in `kotlinx.serialization`. – Michele Palmia Nov 04 '21 at 16:48
  • @MichelePalmia yes it's possible to use JsonElement as serializable value https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#json-elements – Chris Nov 05 '21 at 16:12

1 Answers1

1

encoder.encodeJsonElement might do what you want.

I use encodeJsonElement myself in the implementation of UnknownPolymorphicSerializer<P, W>

A serializer for polymorph objects of type [P] which wraps extending types unknown at runtime as instances of type [W].

I extract the known structure and wrap the the unknown structure. Maybe a similar use case than you are after? The specifics, and use case, are fairly complicated, but documented in "UnknownPolymorphicSerializer: (De)serializing unknown types".

@InternalSerializationApi
override fun serialize( encoder: Encoder, value: P )
{
    // This serializer assumes JSON serialization with class discriminator configured for polymorphism.
    // TODO: It should also be possible to support array polymorphism, but that is not a priority now.
    if ( encoder !is JsonEncoder )
    {
        throw unsupportedException
    }
    getClassDiscriminator( encoder.json ) // Throws error in case array polymorphism is used.

    // Get the unknown JSON object.
    check( value is UnknownPolymorphicWrapper )
    val unknown = Json.parseToJsonElement( value.jsonSource ) as JsonObject

    // HACK: Modify kotlinx.serialization internals to ensure the encoder is not in polymorphic mode.
    //  Otherwise, `encoder.encodeJsonElement` encodes type information, but this is already represented in the wrapped unknown object.
    AccessInternals.setField( encoder, "writePolymorphic", false )

    // Output the originally wrapped JSON.
    encoder.encodeJsonElement( unknown )
}

P.s. AccessInternals is an expected implementation of mine to be able to use kotlin reflect, not supported on JS, since this is a multiplatform library.

Steven Jeuris
  • 18,274
  • 9
  • 70
  • 161