diff --git a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java index d9fe9f478b498..67adec4015f7f 100644 --- a/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java +++ b/extensions/resteasy-reactive/rest/deployment/src/main/java/io/quarkus/resteasy/reactive/server/deployment/ResteasyReactiveProcessor.java @@ -245,6 +245,8 @@ public class ResteasyReactiveProcessor { private static final int SECURITY_EXCEPTION_MAPPERS_PRIORITY = Priorities.USER + 1; private static final String[] EMPTY_STRING_ARRAY = new String[0]; + private static final DotName QUARKUS_TEST_MOCK = DotName.createSimple("io.quarkus.test.Mock"); + @BuildStep public FeatureBuildItem buildSetup() { return new FeatureBuildItem(Feature.REST); @@ -697,21 +699,23 @@ public Supplier apply(ClassInfo classInfo) { generatedClassBuildItemBuildProducer, applicationClassPredicate, reflectiveClassBuildItemBuildProducer)); serverEndpointIndexer = serverEndpointIndexerBuilder.build(); - Map> allMethods = new HashMap<>(); - for (ClassInfo i : scannedResources.values()) { - Optional endpoints = serverEndpointIndexer.createEndpoints(i, true); + Map> allServerMethods = new HashMap<>(); + for (ClassInfo ci : scannedResources.values()) { + Optional endpoints = serverEndpointIndexer.createEndpoints(ci, true); if (endpoints.isPresent()) { - if (singletonClasses.contains(i.name().toString())) { - endpoints.get().setFactory(new SingletonBeanFactory<>(i.name().toString())); + if (singletonClasses.contains(ci.name().toString())) { + endpoints.get().setFactory(new SingletonBeanFactory<>(ci.name().toString())); } resourceClasses.add(endpoints.get()); - for (ResourceMethod rm : endpoints.get().getMethods()) { - addResourceMethodByPath(allMethods, endpoints.get().getPath(), i, rm); + if (!ignoreResourceForDuplicateDetection(ci)) { + for (ResourceMethod rm : endpoints.get().getMethods()) { + addResourceMethodByPath(allServerMethods, endpoints.get().getPath(), ci, rm); + } } } } - checkForDuplicateEndpoint(config, allMethods); + checkForDuplicateEndpoint(config, allServerMethods); //now index possible sub resources. These are all classes that have method annotations //that are not annotated @Path @@ -782,6 +786,14 @@ public Supplier apply(ClassInfo classInfo) { handleDateFormatReflection(reflectiveClassBuildItemBuildProducer, index); } + // TODO: this is really just a hackish way of allowing the use of @Mock so we might need something better + private boolean ignoreResourceForDuplicateDetection(ClassInfo ci) { + if (ci.hasAnnotation(QUARKUS_TEST_MOCK)) { + return true; + } + return false; + } + private boolean filtersAccessResourceMethod(ResourceInterceptors resourceInterceptors) { AtomicBoolean ab = new AtomicBoolean(false); ResourceInterceptors.FiltersVisitor visitor = new ResourceInterceptors.FiltersVisitor() { diff --git a/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/duplicate/DuplicateResourceAndClientTest.java b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/duplicate/DuplicateResourceAndClientTest.java new file mode 100644 index 0000000000000..69fdd14033620 --- /dev/null +++ b/extensions/resteasy-reactive/rest/deployment/src/test/java/io/quarkus/resteasy/reactive/server/test/duplicate/DuplicateResourceAndClientTest.java @@ -0,0 +1,59 @@ +package io.quarkus.resteasy.reactive.server.test.duplicate; + +import static io.restassured.RestAssured.when; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.quarkus.test.Mock; +import io.quarkus.test.QuarkusUnitTest; + +public class DuplicateResourceAndClientTest { + + @RegisterExtension + static QuarkusUnitTest runner = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(Client.class, Resource.class)); + + @Test + public void dummy() { + when() + .get("/hello") + .then() + .statusCode(200); + } + + @Path("/hello") + public interface Client { + + @GET + @Produces(MediaType.TEXT_PLAIN) + String hello(); + } + + @Mock + public static class ClientMock implements Client { + + @Override + public String hello() { + return ""; + } + } + + @Path("/hello") + public static class Resource { + + @GET + @Produces(MediaType.TEXT_PLAIN) + public String hello() { + return "hello"; + } + } +}