Hi there,
Sorry for bothering you with asking an advice on very specific subjects, but you're much more experienced with this than I am with you 🙂
I have a custom codegen integration that overrides serde for "discriminated" unions.
The way it is currently implemented is that for the deserialization I create a custom deserializer that first deserializes the content into document, checks the value of "discriminator" and calls document.deserializeInto(inputBuilder) based on the value.
For the serialization, I override serializeMembers of each discriminated union member so that instead of calling serializer.writeStruct($SCHEMA, first) it calls
serializer.writeString(CUSTOM_CREATED_SCHEMA_FOR_DISCRIMINATOR_FIELD, "<discriminator value>");
value.serializeMembers(serializer);
this kinda flattens the structure and adds "discriminator" into the result object.
So far it was working well and solved the problem, at least at the serde level.
But now I'm trying to integrate Validator into the pipeline and this is where it gets tricky 😂 If I just run the validator on an object with discriminated union in it, one of the errors I get back is Union member conflicts with from ValidatorOfUnion, which makes sense and generally is fine as I can filter it out before returning back. But another side-effect of this is that this error prevents from validating any other fields in this object (which again makes perfect sense from the validator point of view due to lack of knowledge about extra "features").
So I was thinking that with #1171 landed (I know its not yet released) to smithy-java it should be possible to "replicate" ValidatorOfUnion that would support such discrimiated unions - I could ignore error from original ValidatorOfUnion but run my own CustomConstraint that would handle it properly. But the problem I'm facing right now is that the way ValidatorOfUnion is implemented - it re-uses Validator.ShapeValidator (it takes it in as an ctor parameter) to run validation on downstream objects, and this class is not exposed to public (and I think I understand why).
In theory, in a custom constraint I can create another instance of Validator and run it against the discriminated unions only, but this can cause a couple of issues:
- parameters of Validator (such as maxDepth or maxAllowedErrors) won't be synced
- more importantly,
currentPath, currentDepth and other validator run's "state" won't be shared, meaning that some of them will need to be re-constructed (e.g. path), but some couldn't (depth or current errors to prevent further validation if it reached maxAllowedErrors)
I was also thinking to play around with Schemas (e.g. create "merged" schemas for each member of a discriminated union so it contains union target + discriminator and then use it overridden schema method), but this approach feels like less extendable and controlled from the codegen perspective (e.g. there is no an easy way to add custom shapes to the model so that the codegen would generate schemas for them because it removes unused shapes from the model before running the codegen - otherwise I would need to replicate and maintain some code from smithy-java which I would rather to avoid doing; also there is no an easy way to override schema method either).
So I'm running out of ideas and I would appreciate any advice that you might have. Currently I'd prefer not to have discriminated union as a feature for many reasons, but this is something that is being used in existing APIs that we want to migrate over to Smithy before we can think about migrating them to a better state.
Thanks!
Hi there,
Sorry for bothering you with asking an advice on very specific subjects, but you're much more experienced with this than I am with you 🙂
I have a custom codegen integration that overrides serde for "discriminated" unions.
The way it is currently implemented is that for the deserialization I create a custom deserializer that first deserializes the content into document, checks the value of "discriminator" and calls
document.deserializeInto(inputBuilder)based on the value.For the serialization, I override
serializeMembersof each discriminated union member so that instead of callingserializer.writeStruct($SCHEMA, first)it callsthis kinda flattens the structure and adds "discriminator" into the result object.
So far it was working well and solved the problem, at least at the serde level.
But now I'm trying to integrate Validator into the pipeline and this is where it gets tricky 😂 If I just run the validator on an object with discriminated union in it, one of the errors I get back is
Union member conflicts withfromValidatorOfUnion, which makes sense and generally is fine as I can filter it out before returning back. But another side-effect of this is that this error prevents from validating any other fields in this object (which again makes perfect sense from the validator point of view due to lack of knowledge about extra "features").So I was thinking that with #1171 landed (I know its not yet released) to smithy-java it should be possible to "replicate"
ValidatorOfUnionthat would support such discrimiated unions - I could ignore error from originalValidatorOfUnionbut run my ownCustomConstraintthat would handle it properly. But the problem I'm facing right now is that the wayValidatorOfUnionis implemented - it re-usesValidator.ShapeValidator(it takes it in as an ctor parameter) to run validation on downstream objects, and this class is not exposed to public (and I think I understand why).In theory, in a custom constraint I can create another instance of Validator and run it against the discriminated unions only, but this can cause a couple of issues:
currentPath,currentDepthand other validator run's "state" won't be shared, meaning that some of them will need to be re-constructed (e.g. path), but some couldn't (depth or current errors to prevent further validation if it reached maxAllowedErrors)I was also thinking to play around with Schemas (e.g. create "merged" schemas for each member of a discriminated union so it contains union target + discriminator and then use it overridden
schemamethod), but this approach feels like less extendable and controlled from the codegen perspective (e.g. there is no an easy way to add custom shapes to the model so that the codegen would generate schemas for them because it removes unused shapes from the model before running the codegen - otherwise I would need to replicate and maintain some code from smithy-java which I would rather to avoid doing; also there is no an easy way to overrideschemamethod either).So I'm running out of ideas and I would appreciate any advice that you might have. Currently I'd prefer not to have discriminated union as a feature for many reasons, but this is something that is being used in existing APIs that we want to migrate over to Smithy before we can think about migrating them to a better state.
Thanks!