Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Also search interfaces recursively
  • Loading branch information
lostiniceland committed Feb 7, 2023
1 parent a129312 commit 16b44aa
Showing 1 changed file with 68 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
package io.quarkus.resteasy.deployment;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.jboss.jandex.*;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.AnnotationsTransformerBuildItem;
Expand Down Expand Up @@ -90,8 +101,8 @@ public void transform(TransformationContext ctx) {
if (annotation != null) {
stringBuilder = new StringBuilder(slashify(annotation.value().asString()));
} else {
// Look for @Path on interface-method with same name
stringBuilder = searchPathAnnotationOnInterfaces(index, classInfo, methodInfo)
// Fallback: look for @Path on interface-method with same name
stringBuilder = searchPathAnnotationOnInterfaces(index, methodInfo)
.map(annotationInstance -> new StringBuilder(slashify(annotationInstance.value().asString())))
.orElse(new StringBuilder());
}
Expand All @@ -101,11 +112,12 @@ public void transform(TransformationContext ctx) {
if (annotation != null) {
stringBuilder.insert(0, slashify(annotation.value().asString()));
} else {
// Look for @Path on interfaces
classInfo.interfaceTypes().stream()
.filter(type -> type.hasAnnotation(REST_PATH)).findFirst()
.ifPresent(
type -> stringBuilder.insert(0, slashify(type.annotation(REST_PATH).value().asString())));
// Fallback: look for @Path on interfaces
getAllClassInterfaces(index, List.of(classInfo), new ArrayList<>()).stream()
.filter(interfaceClassInfo -> interfaceClassInfo.hasAnnotation(REST_PATH))
.findFirst()
.map(interfaceClassInfo -> interfaceClassInfo.annotation(REST_PATH).value())
.ifPresent(annotationValue -> stringBuilder.insert(0, slashify(annotationValue.asString())));
}

if (restPathPrefix != null) {
Expand Down Expand Up @@ -140,25 +152,53 @@ String slashify(String path) {
return '/' + path;
}

static Optional<AnnotationInstance> searchPathAnnotationOnInterfaces(CombinedIndexBuildItem index, ClassInfo classInfo,
MethodInfo methodInfo) {
@SuppressWarnings("unchecked")
Optional<MethodInfo> resolvedMethodInfo = (Optional<MethodInfo>) classInfo.interfaceNames()
.stream()
// find same method on interface
.map(dotName -> {
ClassInfo interfaceClassInfo = index.getIndex().getClassByName(dotName);
if (interfaceClassInfo == null) {
return Optional.empty();
} else {
return Optional.ofNullable(interfaceClassInfo.method(methodInfo.name(),
methodInfo.parameterTypes().toArray(new Type[] {})));
}
})
.flatMap(Optional::stream)
.findFirst();
// TODO split necessary due to type-inference with Optional.empty
return resolvedMethodInfo.flatMap(interfaceMethodInfo -> Optional.ofNullable(interfaceMethodInfo.annotation(REST_PATH)));
/**
* Searches for the same method as passed in methodInfo parameter in all implemented interfaces and yields an
* Optional containing the JAX-RS Path annotation.
*
* @param index Jandex-Index for additional lookup
* @param methodInfo the method to find
* @return Optional with the annotation if found. Never null.
*/
static Optional<AnnotationInstance> searchPathAnnotationOnInterfaces(CombinedIndexBuildItem index, MethodInfo methodInfo) {

Collection<ClassInfo> allClassInterfaces = getAllClassInterfaces(index, List.of(methodInfo.declaringClass()),
new ArrayList<>());

return allClassInterfaces.stream()
.map(interfaceClassInfo -> interfaceClassInfo.method(
methodInfo.name(),
methodInfo.parameterTypes().toArray(new Type[] {})))
.filter(Objects::nonNull)
.findFirst()
.map(resolvedMethodInfo -> resolvedMethodInfo.annotation(REST_PATH));
}

/**
* Recursively get all interfaces given as classInfo collection.
*
* @param index Jandex-Index for additional lookup
* @param classInfos the class(es) to search. Ends the recursion when empty.
* @param resultAcc accumulator for tail-recursion
* @return Collection of all interfaces und their parents. Never null.
*/
private static Collection<ClassInfo> getAllClassInterfaces(
CombinedIndexBuildItem index,
Collection<ClassInfo> classInfos,
List<ClassInfo> resultAcc) {
Objects.requireNonNull(index);
Objects.requireNonNull(classInfos);
Objects.requireNonNull(resultAcc);
if (classInfos.isEmpty()) {
return resultAcc;
}
List<ClassInfo> interfaces = classInfos.stream()
.flatMap(classInfo -> classInfo.interfaceNames().stream())
.map(dotName -> index.getIndex().getClassByName(dotName))
.filter(Objects::nonNull)
.collect(Collectors.toUnmodifiableList());
resultAcc.addAll(interfaces);
return getAllClassInterfaces(index, interfaces, resultAcc);
}

static boolean isRestEndpointMethod(CombinedIndexBuildItem index, MethodInfo methodInfo) {
Expand All @@ -171,7 +211,7 @@ static boolean isRestEndpointMethod(CombinedIndexBuildItem index, MethodInfo met
}
}
// Search for interface
return searchPathAnnotationOnInterfaces(index, methodInfo.declaringClass(), methodInfo).isPresent();
return searchPathAnnotationOnInterfaces(index, methodInfo).isPresent();
}
return true;
}
Expand Down

0 comments on commit 16b44aa

Please sign in to comment.