132132import io .quarkus .arc .deployment .BeanDiscoveryFinishedBuildItem ;
133133import io .quarkus .arc .deployment .GeneratedBeanBuildItem ;
134134import io .quarkus .arc .deployment .UnremovableBeanBuildItem ;
135+ import io .quarkus .arc .processor .KotlinUtils ;
135136import io .quarkus .arc .runtime .BeanContainer ;
136137import io .quarkus .deployment .Capabilities ;
137138import io .quarkus .deployment .Capability ;
@@ -739,9 +740,13 @@ public Supplier<Boolean> apply(ClassInfo classInfo) {
739740
740741 checkForDuplicateEndpoint (config , allServerMethods );
741742
742- Function <Type , DotName > typeToReturnName = new Function <Type , DotName >() {
743+ Function <MethodInfo , DotName > methodToReturnName = new Function <MethodInfo , DotName >() {
743744 @ Override
744- public DotName apply (Type type ) {
745+ public DotName apply (MethodInfo method ) {
746+ var type = method .returnType ();
747+ if (type .name ().equals (DotName .OBJECT_NAME ) && KotlinUtils .isKotlinSuspendMethod (method )) {
748+ type = KotlinUtils .getKotlinSuspendMethodResult (method );
749+ }
745750 DotName typeName = type .name ();
746751 if (type .kind () == Type .Kind .CLASS ) {
747752 return typeName ;
@@ -757,6 +762,19 @@ public DotName apply(Type type) {
757762 }
758763 };
759764
765+ // Provides a predicate for filtering classes/methods that have annotations from one of the client
766+ // packages. This only reduces the false positives as a "base" interface could be derived and
767+ // client-related annotation applies. Although it seems unlikely that an endpoint without any
768+ // client annotations violates the specification for server resources methods; this type of false
769+ // positive would only mean needless processing as there would be no exception thrown.
770+ Predicate <AnnotationInstance > knownClientAnnotation = new Predicate <AnnotationInstance >() {
771+ public boolean test (AnnotationInstance ann ) {
772+ return ann .name ().packagePrefix ().startsWith ("io.quarkus.rest.client" ) ||
773+ ann .name ().packagePrefix ().startsWith ("org.eclipse.microprofile.rest.client" ) ||
774+ ann .name ().packagePrefix ().startsWith ("org.jboss.resteasy.reactive.client" );
775+ }
776+ };
777+
760778 Map <DotName , Set <DotName >> returnsBySubResources = new HashMap <>();
761779 //now index possible sub resources. These are all classes that have method annotations
762780 //that are not annotated @Path
@@ -765,8 +783,16 @@ public DotName apply(Type type) {
765783 MethodInfo method = instance .target ().asMethod ();
766784 ClassInfo classInfo = method .declaringClass ();
767785
786+ // Reject known client interfaces (See predicate above)
787+ if (classInfo .annotations ().stream ().anyMatch (knownClientAnnotation )
788+ || method .annotations ().stream ().anyMatch (knownClientAnnotation )
789+ || method .parameters ().stream ().flatMap (p -> p .annotations ().stream ())
790+ .anyMatch (knownClientAnnotation )) {
791+ continue ;
792+ }
793+
768794 returnsBySubResources .computeIfAbsent (classInfo .name (), ignored -> new HashSet <>())
769- .add (typeToReturnName .apply (method . returnType () ));
795+ .add (methodToReturnName .apply (method ));
770796 }
771797 }
772798 //sub resources can also have just a path annotation
@@ -776,8 +802,16 @@ public DotName apply(Type type) {
776802 MethodInfo method = instance .target ().asMethod ();
777803 ClassInfo classInfo = method .declaringClass ();
778804
805+ // Reject known client interfaces (See predicate above)
806+ if (classInfo .annotations ().stream ().anyMatch (knownClientAnnotation )
807+ || method .annotations ().stream ().anyMatch (knownClientAnnotation )
808+ || method .parameters ().stream ().flatMap (p -> p .annotations ().stream ())
809+ .anyMatch (knownClientAnnotation )) {
810+ continue ;
811+ }
812+
779813 returnsBySubResources .computeIfAbsent (classInfo .name (), ignored -> new HashSet <>())
780- .add (typeToReturnName .apply (method . returnType () ));
814+ .add (methodToReturnName .apply (method ));
781815 }
782816 }
783817
0 commit comments