Skip to content

Dynamic validation - #1991

Open
msosnicki wants to merge 8 commits into
disneystreaming:series/0.19from
msosnicki:dynamic-validation
Open

Dynamic validation#1991
msosnicki wants to merge 8 commits into
disneystreaming:series/0.19from
msosnicki:dynamic-validation

Conversation

@msosnicki

Copy link
Copy Markdown
Contributor

PR Checklist (not all items are relevant to all PRs)

  • Added unit-tests (for runtime code)
  • Added bootstrapped code + smoke tests (when the rendering logic is modified)
  • Added build-plugins integration tests (when reflection loading is required at codegen-time)
  • Added alloy compliance tests (when simpleRestJson protocol behaviour is expanded/updated)
  • Updated dynamic module to match generated-code behaviour
  • Added documentation
  • Updated changelog

Comment on lines +137 to +138
enumSchema(e.asInstanceOf[EnumerationSchema[Enum[?]]])
.asInstanceOf[Schema[A]]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Casts are pretty risky in Dynamic land. Any way we can make this work without them?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need to limit ourselves to JVM here, this could work on all platforms.

* behaviour), mirroring the fact that codegen-produced schemas enforce these
* constraints but dynamically-loaded do not).
*/
def loadModel(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also have a platform-agnostic variant that works on our own model of Model - let's add performValidation to it too

/**
* Loads a dynamic schema index model from a smithy model.
*
* @param performValidation when true, constraint traits (`@length`, `@range`,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My first thought seeing this name was that we'd be doing model validations rather than schema validations...

maybe addSchemaValidators or applySchemaRefinements would fit better?

def reifyConstraints(index: DynamicSchemaIndex): DynamicSchemaIndex =
new DynamicSchemaIndex {
def allServices: Iterable[DynamicSchemaIndex.ServiceWrapper] =
index.allServices

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I believe this isn't right: operation inputs/outputs/errors won't have their traits reified. UNLESS the default DSI implementation calls getSchema(shapeId) - in which case they would be reified - but we can't assume that about the index instance here, as it's an implementation detail and not something enforced by a contract.

To be safe, we could convert those services to builders and map each endpoint's input/output/errors, reifying the constraints right there. I think a simpler alternative to this would be embedding the reification process directly in the DynamicCompiler rather than in a "middleware" (here)


private object ReifyConstraints extends (Schema ~> Schema) {

private def void[C, A](

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think at this point we should move this to RefinementProvider. It was always a bit of a hack, having it as a more first-class thing would feel better

private def collection[C[_], B](
schema: Schema.CollectionSchema[C, B]
): Schema[C[B]] =
schema.tag match {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AFAIK that's not an exhaustive match (CollectionTag is open in 0.19). We should have another case for arbitrary tags.

case t @ PrimitiveSchema(_, _, tag) =>
tag match {
case PString =>
t.reifyHint(RefinementProvider.stringLengthConstraint)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also: @idRef

m.reifyHint(
RefinementProvider.lengthConstraint[c[k, v]](m.tag.iterator(_).size)
)
case other => other

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd handle the remainder explicitly, like in smithy-playground

Comment thread CHANGELOG.md Outdated
# 0.19.11

- codegen: Fix an `IllegalAccessError` (e.g. `class ...IncludeClosures cannot access its abstract superclass ...BackwardCompatHelper`) that could occur during `smithy4sCodegen` when a project dependency pulled a different version of a Smithy library (`smithy-build`, `smithy-model`, etc.) than the one bundled with the codegen plugin. The model-loading `URLClassLoader` used the plugin classloader as its parent, so a duplicate copy of a plugin-provided module on the child loader could split a package across two classloaders and break package-private access. The codegen now drops any dependency already provided by the parent classloader (tracked via the new `BuildInfo.codegenDependencies`) from the child classloader, so Smithy versions no longer need to be aligned between the plugin and the project's dependencies.
- dynamic: Add `DynamicSchemaIndex.loadModel(model, performValidation: Boolean)` overload. When `performValidation = true`, constraint traits (`@length`, `@range`, `@pattern`, ...) are reified into schema refinements instead of being kept just as hints, matching the behaviour of codegen-produced schemas.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.11 is already out, we need a new section :)

@msosnicki
msosnicki force-pushed the dynamic-validation branch from aa4cea6 to 3439438 Compare August 3, 2026 11:02
@msosnicki
msosnicki marked this pull request as ready for review August 3, 2026 13:57
@msosnicki

msosnicki commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

@kubukoz thanks for review, I think all your comments are now addressed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants