From 29169fa1c168addacb3da20433270057773bfbc4 Mon Sep 17 00:00:00 2001 From: Ales Justin Date: Thu, 14 Nov 2024 14:49:55 +0100 Subject: [PATCH] Check for duplicate services - mutiny and plain; from #44326 --- .../grpc/deployment/GrpcServerProcessor.java | 39 +++++++++++++++++++ .../grpc/server/DuplicateServiceTest.java | 35 +++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java index 677c243adb9e0b..c962c5496c3024 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java @@ -227,6 +227,8 @@ void discoverBindableServices(BuildProducer bindables, IndexView index = combinedIndexBuildItem.getIndex(); Collection bindableServices = index.getAllKnownImplementors(GrpcDotNames.BINDABLE_SERVICE); + Map> implBase = new HashMap<>(); + for (ClassInfo service : bindableServices) { if (service.interfaceNames().contains(GrpcDotNames.MUTINY_BEAN)) { // Ignore the generated beans @@ -235,6 +237,9 @@ void discoverBindableServices(BuildProducer bindables, if (Modifier.isAbstract(service.flags())) { continue; } + + fillBaseImpls(index, implBase, service); + BindableServiceBuildItem item = new BindableServiceBuildItem(service.name()); Set blockingMethods = gatherBlockingOrVirtualMethodNames(service, index, false); Set virtualMethods = gatherBlockingOrVirtualMethodNames(service, index, true); @@ -248,6 +253,40 @@ void discoverBindableServices(BuildProducer bindables, } } + private static void fillBaseImpls(IndexView index, Map> implBase, ClassInfo serviceClass) { + AnnotationInstance grpcAnnotation = serviceClass.annotation(GrpcDotNames.GRPC_SERVICE); + if (grpcAnnotation == null) { + return; + } + + // mutiny vs plain + // org.acme.example.MutinyGreeterGrpc$GreeterImplBase + // org.acme.example.GreeterGrpc$GreeterImplBase + + DotName biClass = findImplBase(serviceClass, index); + String[] split = biClass.toString().split("\\$"); // find inner class + String serviceNameIB = split[1].replace("ImplBase", ""); + String prefix = split[0].startsWith("Mutiny") ? "" : "."; // do we have some package + String serviceNameGrpc = split[0].replace(prefix + "Mutiny" + serviceNameIB + "Grpc", prefix + serviceNameIB + "Grpc"); + + Set existing = implBase.compute(serviceNameIB, (k, v) -> v == null ? new HashSet<>() : v); + if (!existing.add(serviceNameGrpc)) { + throw new IllegalArgumentException("Duplicate service impl: " + existing); + } + } + + private static DotName findImplBase(ClassInfo classInfo, IndexView index) { + if (classInfo == null) { + throw new IllegalArgumentException("No ImplBase found"); + } + DotName name = classInfo.name(); + if (name.toString().endsWith("ImplBase")) { + return name; + } + Type superClazz = index.getClassByName(name).superClassType(); + return findImplBase(superClazz != null ? index.getClassByName(superClazz.name()) : null, index); + } + /** * Generate list of {@link ClassInfo} with {@code service} as the first element and the class implementing * {@code io.grpc.BindableService} (for example via the protobuf generated {@code *ImplBase}) as the last one. diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java new file mode 100644 index 00000000000000..e0dd9400bbadf2 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java @@ -0,0 +1,35 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +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 com.google.protobuf.EmptyProto; + +import io.grpc.testing.integration.Messages; +import io.quarkus.grpc.server.services.BlockingMutinyTestService; +import io.quarkus.grpc.server.services.BlockingTestService; +import io.quarkus.test.QuarkusUnitTest; + +public class DuplicateServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addPackage(EmptyProto.class.getPackage()) + .addPackage(Messages.SimpleRequest.class.getPackage()) + .addClasses(BlockingTestService.class, + BlockingMutinyTestService.class)) + .assertException(t -> { + System.out.println("t = " + t); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +}