Skip to content

Commit

Permalink
Update OpenAPI auto-tag processing to account for SR 2.2.0 changes
Browse files Browse the repository at this point in the history
Save method hashes based on resource implementation classes and both the
concrete and (potentially) abstract methods.
  • Loading branch information
MikeEdgar committed Aug 11, 2022
1 parent 057eb78 commit f5f4783
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 44 deletions.
Expand Up @@ -535,46 +535,50 @@ private List<String> getAuthenticatedMethodReferences(
}

private Map<String, String> getClassNamesMethodReferences(OpenApiFilteredIndexViewBuildItem apiFilteredIndexViewBuildItem) {
FilteredIndexView filteredIndex = apiFilteredIndexViewBuildItem.getIndex();
List<AnnotationInstance> openapiAnnotations = new ArrayList<>();
Set<DotName> allOpenAPIEndpoints = getAllOpenAPIEndpoints();
for (DotName dotName : allOpenAPIEndpoints) {
openapiAnnotations.addAll(apiFilteredIndexViewBuildItem.getIndex().getAnnotations(dotName));
openapiAnnotations.addAll(filteredIndex.getAnnotations(dotName));
}

Map<String, String> classNames = new HashMap<>();

for (AnnotationInstance ai : openapiAnnotations) {
if (ai.target().kind().equals(AnnotationTarget.Kind.METHOD)) {
MethodInfo method = ai.target().asMethod();
if (Modifier.isInterface(method.declaringClass().flags())) {
Collection<ClassInfo> allKnownImplementors = apiFilteredIndexViewBuildItem.getIndex()
.getAllKnownImplementors(method.declaringClass().name());
for (ClassInfo impl : allKnownImplementors) {
MethodInfo implMethod = impl.method(method.name(), method.parameterTypes().toArray(new Type[] {}));
if (implMethod != null) {
String implRef = JandexUtil.createUniqueMethodReference(impl, method);
classNames.put(implRef, impl.simpleName());
}
}
} else if (Modifier.isAbstract(method.declaringClass().flags())) {
Collection<ClassInfo> allKnownSubclasses = apiFilteredIndexViewBuildItem.getIndex()
.getAllKnownSubclasses(method.declaringClass().name());
for (ClassInfo impl : allKnownSubclasses) {
MethodInfo implMethod = impl.method(method.name(), method.parameterTypes().toArray(new Type[] {}));
if (implMethod != null) {
String implRef = JandexUtil.createUniqueMethodReference(impl, method);
classNames.put(implRef, impl.simpleName());
}
}
ClassInfo declaringClass = method.declaringClass();
Type[] params = method.parameterTypes().toArray(new Type[] {});

if (Modifier.isInterface(declaringClass.flags())) {
addMethodImplementationClassNames(method, params, filteredIndex
.getAllKnownImplementors(declaringClass.name()), classNames);
} else if (Modifier.isAbstract(declaringClass.flags())) {
addMethodImplementationClassNames(method, params, filteredIndex
.getAllKnownSubclasses(declaringClass.name()), classNames);
} else {
String ref = JandexUtil.createUniqueMethodReference(method.declaringClass(), method);
classNames.put(ref, method.declaringClass().simpleName());
String ref = JandexUtil.createUniqueMethodReference(declaringClass, method);
classNames.put(ref, declaringClass.simpleName());
}
}
}
return classNames;
}

void addMethodImplementationClassNames(MethodInfo method, Type[] params, Collection<ClassInfo> classes,
Map<String, String> classNames) {
for (ClassInfo impl : classes) {
String simpleClassName = impl.simpleName();
MethodInfo implMethod = impl.method(method.name(), params);

if (implMethod != null) {
classNames.put(JandexUtil.createUniqueMethodReference(impl, implMethod), simpleClassName);
}

classNames.put(JandexUtil.createUniqueMethodReference(impl, method), simpleClassName);
}
}

private boolean isValidOpenAPIMethodForAutoAdd(MethodInfo method, DotName securityRequirement) {
return isOpenAPIEndpoint(method) && !method.hasAnnotation(securityRequirement)
&& method.declaringClass().classAnnotation(securityRequirement) == null;
Expand Down
@@ -0,0 +1,16 @@
package io.quarkus.smallrye.openapi.test.jaxrs;

import java.util.List;

import javax.ws.rs.GET;

public abstract class AutoTagFetchableResource<T> implements AbstractAutoTagResource<T> {

@GET
abstract List<T> getAll();

@Override
public T getById(long id) {
return null;
}
}
@@ -1,11 +1,20 @@
package io.quarkus.smallrye.openapi.test.jaxrs;

import java.util.List;

import javax.ws.rs.Path;

@Path("/address")
public class AutoTagResource implements AbstractAutoTagResource<String> {
@Path("/tagged")
public class AutoTagResource extends AutoTagFetchableResource<String> {

@Override
public String getById(long id) {
return "Disney Land, Gate " + id;
}
}

@Override
public List<String> getAll() {
return null;
}

}
Expand Up @@ -7,34 +7,27 @@
import io.quarkus.test.QuarkusUnitTest;
import io.restassured.RestAssured;

public class AutoTagTestCase {
class AutoTagTestCase {
@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClasses(OpenApiResourceWithNoTag.class, AutoTagResource.class, AbstractAutoTagResource.class));
.addClasses(OpenApiResourceWithNoTag.class, AutoTagResource.class, AutoTagFetchableResource.class,
AbstractAutoTagResource.class));

@Test
public void testAutoSecurityRequirement() {
void testTagInOpenApi() {
RestAssured.given().header("Accept", "application/json")
.when().get("/q/openapi")
.when()
.get("/q/openapi")
.then()
.log().body()
.and()
.log().ifValidationFails()
.assertThat()
.statusCode(200)
.body("paths.'/tagged'.get.tags", Matchers.hasItem("Auto Tag Resource"))
.body("paths.'/tagged/{id}'.get.tags", Matchers.hasItem("Auto Tag Resource"))
.body("paths.'/resource/annotated'.get.tags", Matchers.hasItem("From Annotation"))
.and()
.body("paths.'/resource/auto'.get.tags", Matchers.hasItem("Open Api Resource With No Tag"))
.and()
.body("paths.'/resource/auto'.post.tags", Matchers.hasItem("Open Api Resource With No Tag"));

}

@Test
public void testTagInOpenApi() {
RestAssured.given().header("Accept", "application/json")
.when().get("/q/openapi")
.then()
.statusCode(200)
.body(Matchers.containsString("Auto Tag Resource"));
}

}

0 comments on commit f5f4783

Please sign in to comment.