Skip to content

Commit

Permalink
Fix: serializing unknown types using JS release
Browse files Browse the repository at this point in the history
Also had to update kotlinx serialization typescript wrapper due to new method call which was added in `UnknownPolymorphicSerializer` and caused the exported names to change.

Closes #473
  • Loading branch information
Whathecode committed Apr 14, 2024
1 parent bd4806b commit 86f1edd
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package dk.cachet.carp.common.infrastructure.serialization

import dk.cachet.carp.common.infrastructure.reflect.AccessInternals
import dk.cachet.carp.common.infrastructure.reflect.reflectIfAvailable
import kotlinx.serialization.*
import kotlinx.serialization.descriptors.*
Expand Down Expand Up @@ -58,18 +57,30 @@ abstract class UnknownPolymorphicSerializer<P : Any, W : P>(
{
throw unsupportedException
}
getClassDiscriminator( encoder.json ) // Throws error in case array polymorphism is used.
val classDiscriminator = getClassDiscriminator( encoder.json ) // Throws error in case of array polymorphism.

// Get the unknown JSON object.
check( value is UnknownPolymorphicWrapper )
val unknown = Json.parseToJsonElement( value.jsonSource ) as JsonObject
val unknownTypeFields = unknown.filter { it.key != classDiscriminator }

// Create a serial descriptor which contains all elements of the unknown JSON object, except type discriminator.
// If the encoder is in polymorphic writing mode, a class discriminator field will automatically be added using
// the serial name of the descriptor.
val unknownType = checkNotNull( unknown[ classDiscriminator ]?.jsonPrimitive?.content )
val jsonSerializer = JsonElement.serializer()
val overrideDescriptor = buildClassSerialDescriptor( unknownType )
{
unknownTypeFields.keys.forEach { element( it, jsonSerializer.descriptor ) }
}

// 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, "polymorphicDiscriminator", null )

// Output the originally wrapped JSON.
encoder.encodeJsonElement( unknown )
// Write the JSON object.
encoder.encodeStructure( overrideDescriptor )
{
var id = 0
for ( field in unknownTypeFields.values )
encodeSerializableElement( overrideDescriptor, id++, JsonElement.serializer(), field )
}
}

override fun deserialize( decoder: Decoder ): P
Expand All @@ -85,7 +96,8 @@ abstract class UnknownPolymorphicSerializer<P : Any, W : P>(
// Get raw JSON for the unknown type.
val jsonElement = decoder.decodeJsonElement()
val jsonSource = jsonElement.toString()
val className = jsonElement.jsonObject[ classDiscriminator ]!!.jsonPrimitive.content
val className = requireNotNull( jsonElement.jsonObject[ classDiscriminator ]?.jsonPrimitive?.content )
{ "Can't deserialize type which was serialized non-polymorphically." }

return createWrapper( className, jsonSource, decoder.json )
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import extendJson from "@cachet/kotlinx-serialization-kotlinx-serialization-json
// Facade with better method names and type conversions for internal types.
export namespace kotlinx.serialization
{
export function getSerializer( type: any ) { return type.Companion.t16() }
export function getSerializer( type: any ) { return type.Companion.m16() }
}
export namespace kotlinx.serialization.json
{
Expand Down
2 changes: 1 addition & 1 deletion typescript-declarations/tests/carp-protocols-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ describe( "carp-protocols-core", () => {
expect( parsed ).is.instanceOf( StudyProtocolSnapshot )
} )

it.skip( "can deserialize and serialize unknown types", () => {
it( "can deserialize and serialize unknown types", () => {
const snapshotWithUnknownTypes = serializedSnapshot.replace(
"dk.cachet.carp.common.infrastructure.test.StubTaskConfiguration",
"com.unknown.CustomTaskConfiguration"
Expand Down

0 comments on commit 86f1edd

Please sign in to comment.