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

Add validation events decorators #1774

Merged
merged 8 commits into from
May 24, 2023

Conversation

sugmanue
Copy link
Contributor

Description of changes:

Adds a new interface ValidationEventDecorator that libraries can implement and plug into Smithy by making those discoverable using the java builtin ServiceLoader. All of the ValidationEventDecorator instances are loaded and each ValidationEvent is passed to each of the decorators. The decorators can make use of the ValidationEvent#eventId() method to quickly filter out the events that it knows how to decorate form the events it does not care about, and the ValidationEvent#toBuilder() to create a builder that can be used to mutate the instance.

The current use case is to add hints to a know set of events to point the user into the right solution for it (e.g., you need to pull X or Y dependency for this unresolved shape). Since often these solutions might require specific details about the environment in which Smithy is being used, those decorators cannot be part of Smithy itself but now can be implemented by libraries and loaded automatically by Smithy in a similar way in which validators are currently loaded.

For instance, a decorator that suggest the user to use or remove unused structures might look like this

    @Override
    public ValidationEvent decorate(ValidationEvent ev) {
        if (ev.containsId("UnreferencedShape")) {
            if (ev.getMessage().contains("The structure ")) {
                return ev.toBuilder()
                    .hint("Consider using this structure in your service or remove it from the model")
                    .build();
            }
        }
        return ev;
    }

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Adds a new interface `ValidationEventDecorator` that libraries can
implement and plug into Smithy by making those discoverable using the
java builtin
[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html). All
of the `ValidationEventDecorator` instances are loaded and each
`ValidationEvent` is passed to each of the decorators. The decorators
can make use of the `ValidationEvent#eventId()` method to quickly
filter out the events that it knows how to decorate form the events it
does not care about, and the `ValidationEvent#toBuilder()` to create a
builder that can be used to mutate the instance.

The current use case is to add hints to a know set of events to point
the user into the right solution for it (e.g., you need to pull X or Y
dependency for this unresolved shape). Since often these solutions
might require specific details about the environment in which Smithy
is being used, those decorators cannot be part of Smithy itself but
now can be implemented by libraries and loaded automatically by Smithy
in a similar way in which validators are currently loaded.

For instance, a decorator that suggest the user to use or remove
unused structures might look like this

```java
    @OverRide
    public ValidationEvent decorate(ValidationEvent ev) {
        if (ev.containsId("UnreferencedShape")) {
            if (ev.getMessage().contains("The structure ")) {
                return ev.toBuilder()
                    .hint("Consider using this structure in your service or remove it from the model")
                    .build();
            }
        }
        return ev;
    }
```
@sugmanue sugmanue requested a review from a team as a code owner May 17, 2023 00:46
In order to be able to decorate events that are returned before
running the validation logic we need to pull the decoration logic up
to the ModelAssambler itself. For this, a new factory was created to
load the decorators instead of coupling this logic with the
ValidatorFactory one and the assembler will take care of loading them
and passing them down to the validation logic.
…tion/ValidationEventDecorator.java

Co-authored-by: Michael Dowling <[email protected]>
sugmanue and others added 2 commits May 22, 2023 13:34
* Move back the responsibility of loading the decorators to the
  ValidatorFactory and pass it down to the ModelValidator from the
  ModelAssembler

* Overwrite the events in place in the list instead of crating a new
  list and copying + decorating.

* Create a new method to decorate a single event and use it as part of
  the stream that returns core error events.

* Remove the posibility of manually adding decorators in the validator
  and assembler and just use the ones loaded by the
  `ValidatorFacotry`. We don't need this now and we can add it back if
  and when needed.
* Do not catch exceptions thrown by loaded decorators. We will ship
  like this for now and add later if the need arises.

* Add a new method to create the validation factory instead of using
  the existing one to avoid braking backwards compatibility.
Remove the 'builtin' qualifier that doesn't make sense in this context
@sugmanue
Copy link
Contributor Author

Approved offline after the last requested change to change loadBuiltinDecorators to loadDecorators.

@sugmanue sugmanue merged commit ead65d6 into smithy-lang:main May 24, 2023
syall pushed a commit to Xtansia/smithy that referenced this pull request Aug 11, 2023
* Add validation events decorators

Adds a new interface `ValidationEventDecorator` that libraries can
implement and plug into Smithy by making those discoverable using the
java builtin
[`ServiceLoader`](https://docs.oracle.com/javase/8/docs/api/java/util/ServiceLoader.html). All
of the `ValidationEventDecorator` instances are loaded and each
`ValidationEvent` is passed to each of the decorators. The decorators
can make use of the `ValidationEvent#eventId()` method to quickly
filter out the events that it knows how to decorate form the events it
does not care about, and the `ValidationEvent#toBuilder()` to create a
builder that can be used to mutate the instance.

The current use case is to add hints to a know set of events to point
the user into the right solution for it (e.g., you need to pull X or Y
dependency for this unresolved shape). Since often these solutions
might require specific details about the environment in which Smithy
is being used, those decorators cannot be part of Smithy itself but
now can be implemented by libraries and loaded automatically by Smithy
in a similar way in which validators are currently loaded.

For instance, a decorator that suggest the user to use or remove
unused structures might look like this

```java
    @OverRide
    public ValidationEvent decorate(ValidationEvent ev) {
        if (ev.containsId("UnreferencedShape")) {
            if (ev.getMessage().contains("The structure ")) {
                return ev.toBuilder()
                    .hint("Consider using this structure in your service or remove it from the model")
                    .build();
            }
        }
        return ev;
    }
```

* Load the decorators using its own factory

In order to be able to decorate events that are returned before
running the validation logic we need to pull the decoration logic up
to the ModelAssambler itself. For this, a new factory was created to
load the decorators instead of coupling this logic with the
ValidatorFactory one and the assembler will take care of loading them
and passing them down to the validation logic.

* Fix an event duplication bug

* Update smithy-model/src/main/java/software/amazon/smithy/model/validation/ValidationEventDecorator.java

Co-authored-by: Michael Dowling <[email protected]>

* Update smithy-model/src/main/java/software/amazon/smithy/model/loader/ModelValidator.java

Co-authored-by: Michael Dowling <[email protected]>

* Address pull request comments

* Move back the responsibility of loading the decorators to the
  ValidatorFactory and pass it down to the ModelValidator from the
  ModelAssembler

* Overwrite the events in place in the list instead of crating a new
  list and copying + decorating.

* Create a new method to decorate a single event and use it as part of
  the stream that returns core error events.

* Remove the posibility of manually adding decorators in the validator
  and assembler and just use the ones loaded by the
  `ValidatorFacotry`. We don't need this now and we can add it back if
  and when needed.

* Address pull request comments

* Do not catch exceptions thrown by loaded decorators. We will ship
  like this for now and add later if the need arises.

* Add a new method to create the validation factory instead of using
  the existing one to avoid braking backwards compatibility.

* Address pull request comments

Remove the 'builtin' qualifier that doesn't make sense in this context

---------

Co-authored-by: Michael Dowling <[email protected]>
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.

3 participants