From 884b0ffc9993bd3b8a0f9a8b40ecab116ff34872 Mon Sep 17 00:00:00 2001 From: Romain Marcadier Date: Mon, 13 Mar 2023 15:45:05 +0100 Subject: [PATCH] fix(kernel): json deserialization fails on `null` value (#4000) The JSON serialization class is a quasi-synonym for `Map`, except it is meant to accept any valid JSON object, including one with `null` values. The serializer was however interpreting these as `Map` when wired as a `$jsii.map` envelope, and this serialization class does NOT allow for null values. Addresses the "easy" part of aws/aws-cdk#14639 (more complicated is that it would need to preserve `null` across the process boundary, which is currently not possible). --- By submitting this pull request, I confirm that my contribution is made under the terms of the [Apache 2.0 license]. [Apache 2.0 license]: https://www.apache.org/licenses/LICENSE-2.0 --- packages/@jsii/kernel/src/serialization.ts | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/@jsii/kernel/src/serialization.ts b/packages/@jsii/kernel/src/serialization.ts index 0b0d66d8ce..27b6be1a99 100644 --- a/packages/@jsii/kernel/src/serialization.ts +++ b/packages/@jsii/kernel/src/serialization.ts @@ -111,6 +111,7 @@ interface Serializer { value: unknown, type: OptionalValueOrVoid, host: SerializerHost, + options?: { allowNullishMapValue?: boolean }, ): any; } @@ -236,7 +237,6 @@ export const SERIALIZERS: { [k: string]: Serializer } = { return SERIALIZERS[SerializationClass.Map].deserialize( value, { - optional: false, type: { collection: { kind: spec.CollectionKind.Map, @@ -245,6 +245,7 @@ export const SERIALIZERS: { [k: string]: Serializer } = { }, }, host, + { allowNullishMapValue: true }, ); } @@ -266,9 +267,7 @@ export const SERIALIZERS: { [k: string]: Serializer } = { host, 'deserialize', toMap, - { - type: { primitive: spec.PrimitiveType.Json }, - }, + { type: { primitive: spec.PrimitiveType.Json } }, typeof key === 'string' ? `key ${inspect(key)}` : `index ${key}`, ); } @@ -387,7 +386,12 @@ export const SERIALIZERS: { [k: string]: Serializer } = { ), }; }, - deserialize(value, optionalValue, host) { + deserialize( + value, + optionalValue, + host, + { allowNullishMapValue = false } = {}, + ) { if (nullAndOk(value, optionalValue)) { return undefined; } @@ -401,7 +405,10 @@ export const SERIALIZERS: { [k: string]: Serializer } = { host, 'deserialize', v, - { type: mapType.collection.elementtype }, + { + optional: allowNullishMapValue, + type: mapType.collection.elementtype, + }, `key ${inspect(key)}`, ), ); @@ -411,7 +418,10 @@ export const SERIALIZERS: { [k: string]: Serializer } = { host, 'deserialize', v, - { type: mapType.collection.elementtype }, + { + optional: allowNullishMapValue, + type: mapType.collection.elementtype, + }, `key ${inspect(key)}`, ), ); @@ -1112,7 +1122,7 @@ export function process( context: string, ) { const wireTypes = serializationType(type, host.lookupType); - host.debug(serde, value, wireTypes); + host.debug(serde, value, ...wireTypes); const errors = new Array(); for (const { serializationClass, typeRef } of wireTypes) {