-
Notifications
You must be signed in to change notification settings - Fork 89
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
Support for readers and filters to access the Jandex index #1475
Conversation
@Raptoer, this PR is for a concept that would allow you to use the Jandex index from an instance of an @Spindl, this is also meant to assist with your issue #1370. Using an For both issues, I would say implementing an |
4a5078e
to
cb92d1a
Compare
SonarCloud Quality Gate failed. |
Hi @MikeEdgar, thank you for considering helping us with our problem. I understand that the Scanners are considered internal API, and would also prefer not to hook into the scanning process like that 😅 |
Being able to filter the active scanners would allow us to get rid of another ugly workaround though, which we need for now since we can't influence the order in which the scanners run. 😬 |
@Spindl, having the index would allow that. Suppose you have an endpoint method: package com.example;
@Path("/widgets")
public class WidgetsResource {
@GET
@Path("{widgetId}")
@Operation(operationId = "getWidget")
@com.example.MyAnnotation(value = "Something Important")
public Response getWidgets(String widgetId) {
...
}
} You could do something like in the filter: public class MyFilter implements OASFilter {
private IndexView index;
public MyFilter(IndexView index) {
this.index = index;
}
@Override
public Operation filterOperation(Opertion operation) {
if ("getWidget".equals(operation.getOperationId()) {
MethodInfo getWidgets = index
.getClassByName("com.example.WidgetsResource")
.method("getWidget", Type.create(
DotName.createSimple("java.lang.String"),
Type.Kind.CLASS));
AnnotationInstance myAnnotation = getWidgets.annotation("com.example.MyAnnotation");
// Do something with `myAnnotation` and the `operation`
}
}
} |
@MikeEdgar, I fear that would not work for us. To do that, we would have to know the association between the operation ID and the fully qualified name of the class that contains it. I guess we could maybe try to "put the cart before the horse" and guess the class the method belongs to from the operation ID (which is And I just checked, and we would have the same problem with the Schema as well, since we also adapt some things there (e.g. we have custom |
@Spindl , there are other options to access the index.getAnnotations(org.eclipse.microprofile.openapi.annotations.Operation.class)
.stream()
.filter(annotation -> operation.getOperationId().equals(annotation.value("operationId").asString()))
.map(AnnotationInstance::target)
.map(AnnotationTarget::asMethod)
.findFirst()
.ifPresent(methodInfo -> {
// Do something with the methodInfo
}); Something similar may work for schemas if there is a way to navigate back from the annotations you are interested in. |
Hi @MikeEdgar I assume we could do something like that for the operations, even though we still couldn't get rid of our custom scanner since we don't annotate our endpoints with the @operation annotation, but rather also calculate the operation_id in the scanner. And for the Schema I see no way this could work. |
I have same problems like @Spindl : I want to add BeanValiation-Infos annotated at classes/methods/fields to OpenApi. so i need the relation between an OpenApi-Schema and the class/method/field. |
any progress on this? Only the low test-coverage prevents the merge 🤔 |
If this is useful to you as-is, I'm happy to fix up this PR and merge it. However, adding in some relation between the OpenAPI model pieces and the source that generated them will require something more involved. |
I hope it will suffice for me, to get access to the jandex. Nevertheless: my goal is to document custom BeanValidations in OpenApi. |
Signed-off-by: Michael Edgar <[email protected]>
Signed-off-by: Michael Edgar <[email protected]>
Kudos, SonarCloud Quality Gate passed! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @MikeEdgar
@MikeEdgar |
The Jandex index is not available at runtime, the openapi schema document created from the index in build time is available. |
Right - that is obviously specific to Quarkus, so if you need to do something at run time that you could not have done at build time, your reader/filter will need to fall back to some other mechanism. I suppose you could also build your own Jandex index at build time with your app classes and load it yourself in a filter. |
My problem is that my openApiFilter is triggered twice: once during build time and once during runtime. My hope was to find a configuration so that quarkus creates and filters OpenApi during build-time and stores the result in the jar. So during runtime this openApi could be used without any further filtering/processing. |
That doesn't seem correct. I would expect the runtime input (loaded in |
I created a small test quarkus-project (v.3.4.1) with an openApiFilter using Jandex: In the filter i add a tag to the openApi with a timestamp and info if the Jandex was available: public class OpenApiFilter implements OASFilter {
IndexView index;
public OpenApiFilter(IndexView aIndex) {
index = aIndex;
}
@Override
public void filterOpenAPI(OpenAPI aOpenAPI) {
boolean jandexAvailable = index != null && !index.getKnownClasses().isEmpty();
System.out.println("org.acme.OpenApiFilter.filterOpenAPI() Jandex available " + jandexAvailable);
if (aOpenAPI.getTags() == null) {
System.out.println("org.acme.OpenApiFilter.filterOpenAPI() tags are null");
} else {
System.out.println("org.acme.OpenApiFilter.filterOpenAPI() existing tags:");
aOpenAPI.getTags().stream().map(Tag::getName).forEach(System.out::println);
}
Tag myTag = OASFactory.createTag().name("MyTag " + LocalTime.now() + " Jandex available " + jandexAvailable);
System.out.println("org.acme.OpenApiFilter.filterOpenAPI() adding tag " + myTag.getName());
aOpenAPI.addTag(myTag);
}
} I see that the filter is triggered during build and during runtime. In both cases I tried several configurations, like |
The output of the build should be placed in |
The openApi unter |
Ok, I see. We only execute the app's filter on the version written to the |
@ChMThiel , another option may be to use an |
The document that is stored and the one we pass to runtime might not be the same. Except if you have a reason for storing it, there should be no need to do so. That feature was a request from users that store and version control the stored schema, so that they can compare between releases. The reason we run the filter at build time in that case is that it usually only runs during build, and not at runtime. For the normal flow of events the user's filters are run at runtime. We have two options here I think. 1) Allow users to define the stage a user defined filter should run, with the default being runtime as it is now. 2) Add built-in support for what you are trying to do (BeanValidationScanner). Maybe we should do both ? |
I do not only filter/adjust the OpenApi in my OASFilter, i want to add infos. To get these infos (that are not present in given OpenApi) i had to use some tricks/hacks: During runtime i had access to CDI and was able to request classes implementing certain marker-interface. Now that the jandex is available, i can replace the CDI-hack with the an elegant Jandex-request (For my audit-example For the special case of adding BeanValidation-infos imho the optimal solution would be do make the BeanValidatioScanner more flexible/generic. But with something like jandex.getKnownClasses().stream()
.filter(ClassInfo::isAnnotation)
.filter(i -> i.hasAnnotation(Constraint.class)) I can get all BeanValidation-annotations in the OASFilter, connect those to the matchinng OpenApi-Schema and add the info by myself. I would really appreciate if you support both options because both options have it's use cases, but to define the run-stage of the filter is what i need most. |
Cool, I can look at making the change to allow running user filters during build. That is a Quarkus change I think. /cc @MikeEdgar |
Allows implementations of
OASModelReader
andOASFilter
to optionally provide a single-argument constructor accepting a JandexIndexView
to be used internally.Relates to #1255 and #1370