Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kernel: Serialization does ignore actual type when trying wireTypes in unions #4547

Open
mrgrain opened this issue Jun 19, 2024 · 1 comment
Labels
bug This issue is a bug. module/kernel Issues affecting the `jsii-kernel` module p2

Comments

@mrgrain
Copy link
Contributor

mrgrain commented Jun 19, 2024

Describe the bug

When sending a value from the jsii-kernel back to the caller (<), if the type is a union the serializer just uses a fixed order to try an serialize the type. However in a union type like CfnBucket.CorsConfigurationProperty | cdk.IResolvable, if the actual value is an cdk.IResolvable (e.g. a Lazy.Any) the code still serializes the value as the struct type.

This is wrong, but also doesn't work because a language runtime like Python might then recurse into the struct fields and request nested values to build a struct on the language-side. Instead this should be returned as a ReferenceType.

Expected Behavior

Serialize as a ReferenceType

Current Behavior

Serialized as a StructType

Reproduction Steps

Not quite sure, but the easiest seems to be if the jsii needs to return a Lazy.Any (<) that is typed as something like CfnBucket.CorsConfigurationProperty | cdk.IResolvable

Possible Solution

This fixes the issue on my end:

export function process(
  host: SerializerHost,
  serde: keyof Serializer,
  value: unknown,
  type: OptionalValueOrVoid,
  context: string,
) {
  const wireTypes = serializationType(type, host.lookupType).filter(
    ({ serializationClass }) => {
      if (
        serde === 'serialize' &&
        serializationClass === SerializationClass.Struct
      ) {
        return (value as any)?.constructor.name !== 'LazyAny';
        // return !isByReferenceOnly(value);
      }
      return true;
    },
  );

Unfortunately just always using return !isByReferenceOnly(value); causes more problems and for obvious reasons checking the constructor name is not a good idea. I suspect this check needs to be more clever in the way filters the proposed wireType in relation to the actual value.

SDK version used

1.99.0

Environment details (OS name and version, etc.)

any

@mrgrain mrgrain added bug This issue is a bug. needs-triage This issue or PR still needs to be triaged. module/kernel Issues affecting the `jsii-kernel` module p2 and removed needs-triage This issue or PR still needs to be triaged. labels Jun 19, 2024
@rix0rrr
Copy link
Contributor

rix0rrr commented Jun 19, 2024

Filtering the wiretypes based on the actual value probably means:

  • Reference types first, because those will be easier to check. We can probably check the jsii-injected runtime fqn on the class (although we would have to think to account for interfaces as well). Otherwise, we can check for the existence of functions on the value we see, or perhaps even check the name of the constructor.
  • Structs are typed structurally, so we'd have to check for the presence of members. Toposort the structs by required fields, use the presence of some other fields to scratch off possibilities. Recursing into values of fields is possible, but may become very expensive.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug This issue is a bug. module/kernel Issues affecting the `jsii-kernel` module p2
Projects
None yet
Development

No branches or pull requests

2 participants