You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ja...@apache.org on 2020/09/16 07:17:35 UTC

[camel-quarkus] branch master updated: gRPC native support

This is an automated email from the ASF dual-hosted git repository.

jamesnetherton pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-quarkus.git


The following commit(s) were added to refs/heads/master by this push:
     new 776e28d  gRPC native support
776e28d is described below

commit 776e28d0736f981f7587f384cd550546dd13096e
Author: James Netherton <ja...@gmail.com>
AuthorDate: Tue Sep 15 19:19:45 2020 +0100

    gRPC native support
    
    Fixes #762
---
 .../ROOT/pages/reference/components/grpc.adoc      |   4 +-
 .../ROOT/pages/reference/extensions/grpc.adoc      |  16 +-
 docs/modules/ROOT/pages/reference/index.adoc       |   4 +-
 .../component/grpc/deployment/GrpcProcessor.java   |  46 ----
 extensions-jvm/pom.xml                             |   1 -
 .../grpc/deployment/pom.xml                        |   4 +
 .../component/grpc/deployment/GrpcProcessor.java   | 243 +++++++++++++++++++++
 {extensions-jvm => extensions}/grpc/pom.xml        |   1 -
 .../grpc/runtime/pom.xml                           |  14 ++
 .../grpc/runtime/src/main/doc/configuration.adoc   |   6 +
 .../quarkus/grpc/runtime/CamelGrpcRecorder.java    |  85 +++++++
 .../grpc/runtime/CamelQuarkusBindableService.java  |  27 +++
 .../runtime/QuarkusBindableServiceFactory.java     |  63 ++++++
 .../grpc/runtime/graal/GrpcSubstitutions.java      |  36 +++
 .../main/resources/META-INF/quarkus-extension.yaml |   3 +-
 extensions/pom.xml                                 |   1 +
 .../grpc}/pom.xml                                  |  75 +++++--
 .../quarkus/component/grpc/it/GrpcResource.java    |   0
 .../camel/quarkus/component/grpc/it/GrpcRoute.java |   2 +-
 .../quarkus/component/grpc/it/PingPongImpl.java    |   2 +-
 .../grpc}/src/main/proto/pingpong.proto            |   0
 .../camel/quarkus/component/grpc/it/GrpcIT.java    |  23 ++
 .../component/grpc/it/GrpcServerTestResource.java  |   4 +-
 .../camel/quarkus/component/grpc/it/GrpcTest.java  |   7 +-
 integration-tests/pom.xml                          |   1 +
 tooling/scripts/test-categories.yaml               |   1 +
 26 files changed, 587 insertions(+), 82 deletions(-)

diff --git a/docs/modules/ROOT/pages/reference/components/grpc.adoc b/docs/modules/ROOT/pages/reference/components/grpc.adoc
index 864d462..3848442 100644
--- a/docs/modules/ROOT/pages/reference/components/grpc.adoc
+++ b/docs/modules/ROOT/pages/reference/components/grpc.adoc
@@ -4,8 +4,8 @@
 = gRPC
 :cq-artifact-id: camel-quarkus-grpc
 :cq-artifact-id-base: grpc
-:cq-native-supported: false
-:cq-status: Preview
+:cq-native-supported: true
+:cq-status: Stable
 :cq-deprecated: false
 :cq-jvm-since: 1.0.0
 :cq-native-since: 1.0.0
diff --git a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
index d7308b8..3099af1 100644
--- a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
@@ -4,15 +4,15 @@
 = gRPC
 :page-aliases: extensions/grpc.adoc
 :cq-artifact-id: camel-quarkus-grpc
-:cq-native-supported: false
-:cq-status: Preview
+:cq-native-supported: true
+:cq-status: Stable
 :cq-description: Expose gRPC endpoints and access external gRPC endpoints.
 :cq-deprecated: false
 :cq-jvm-since: 1.0.0
 :cq-native-since: 1.0.0
 
 [.badges]
-[.badge-key]##JVM since##[.badge-supported]##1.0.0## [.badge-key]##Native##[.badge-unsupported]##unsupported##
+[.badge-key]##JVM since##[.badge-supported]##1.0.0## [.badge-key]##Native since##[.badge-supported]##1.0.0##
 
 Expose gRPC endpoints and access external gRPC endpoints.
 
@@ -33,3 +33,13 @@ Please refer to the above link for usage and configuration details.
 ----
 
 Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
+
+== Additional Camel Quarkus configuration
+
+This extension leverages https://quarkus.io/guides/grpc-service-implementation[Quarkus gRPC]. The configuration of the gRPC consumer is different than normal,
+since Quarkus manages the lifecycle of the gRPC server. This means that the consumer endpoint host and port is driven by the configuration properties `quarkus.grpc.server.host`
+and `quarkus.grpc.server.port` and thus the Camel gRPC endpoint configuration for the host & port is effectively ignored. But, it's still good practice to have the
+endpoint configuration host / port mirror the Quarkus gRPC host / port property values to avoid confusion and ambiguity.
+
+The full list of Quarkus gRPC configuration options can be found at the https://quarkus.io/guides/grpc-service-implementation#server-configuration[Quarkus gRPC guide].
+
diff --git a/docs/modules/ROOT/pages/reference/index.adoc b/docs/modules/ROOT/pages/reference/index.adoc
index 9fbb486..d80cd13 100644
--- a/docs/modules/ROOT/pages/reference/index.adoc
+++ b/docs/modules/ROOT/pages/reference/index.adoc
@@ -389,8 +389,8 @@ Stable | 1.0.0 | Unmarshal unstructured data to objects using Logstash based Gro
 |  xref:reference/extensions/groovy.adoc[Groovy]  | camel-quarkus-groovy | [.camel-element-JVM]##JVM## +
 Preview | 1.0.0 | Evaluate a Groovy script.
 
-|  xref:reference/extensions/grpc.adoc[gRPC]  | camel-quarkus-grpc | [.camel-element-JVM]##JVM## +
-Preview | 1.0.0 | Expose gRPC endpoints and access external gRPC endpoints.
+|  xref:reference/extensions/grpc.adoc[gRPC]  | camel-quarkus-grpc | [.camel-element-Native]##Native## +
+Stable | 1.0.0 | Expose gRPC endpoints and access external gRPC endpoints.
 
 |  xref:reference/extensions/guava-eventbus.adoc[Guava EventBus]  | camel-quarkus-guava-eventbus | [.camel-element-JVM]##JVM## +
 Preview | 1.1.0 | Send and receive messages to/from Guava EventBus.
diff --git a/extensions-jvm/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java b/extensions-jvm/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java
deleted file mode 100644
index 0e1b125..0000000
--- a/extensions-jvm/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.quarkus.component.grpc.deployment;
-
-import io.quarkus.deployment.annotations.BuildStep;
-import io.quarkus.deployment.annotations.ExecutionTime;
-import io.quarkus.deployment.annotations.Record;
-import io.quarkus.deployment.builditem.FeatureBuildItem;
-import io.quarkus.deployment.pkg.steps.NativeBuild;
-import org.apache.camel.quarkus.core.JvmOnlyRecorder;
-import org.jboss.logging.Logger;
-
-class GrpcProcessor {
-
-    private static final Logger LOG = Logger.getLogger(GrpcProcessor.class);
-    private static final String FEATURE = "camel-grpc";
-
-    @BuildStep
-    FeatureBuildItem feature() {
-        return new FeatureBuildItem(FEATURE);
-    }
-
-    /**
-     * Remove this once this extension starts supporting the native mode.
-     */
-    @BuildStep(onlyIf = NativeBuild.class)
-    @Record(value = ExecutionTime.RUNTIME_INIT)
-    void warnJvmInNative(JvmOnlyRecorder recorder) {
-        JvmOnlyRecorder.warnJvmInNative(LOG, FEATURE); // warn at build time
-        recorder.warnJvmInNative(FEATURE); // warn at runtime
-    }
-}
diff --git a/extensions-jvm/pom.xml b/extensions-jvm/pom.xml
index 9eb2fcc..f31e5a1 100644
--- a/extensions-jvm/pom.xml
+++ b/extensions-jvm/pom.xml
@@ -78,7 +78,6 @@
         <module>google-bigquery</module>
         <module>google-pubsub</module>
         <module>groovy</module>
-        <module>grpc</module>
         <module>guava-eventbus</module>
         <module>hazelcast</module>
         <module>hdfs</module>
diff --git a/extensions-jvm/grpc/deployment/pom.xml b/extensions/grpc/deployment/pom.xml
similarity index 94%
rename from extensions-jvm/grpc/deployment/pom.xml
rename to extensions/grpc/deployment/pom.xml
index 71010eb..8b16ee2 100644
--- a/extensions-jvm/grpc/deployment/pom.xml
+++ b/extensions/grpc/deployment/pom.xml
@@ -31,6 +31,10 @@
 
     <dependencies>
         <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-grpc-deployment</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core-deployment</artifactId>
         </dependency>
diff --git a/extensions/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java b/extensions/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java
new file mode 100644
index 0000000..9ea7dda
--- /dev/null
+++ b/extensions/grpc/deployment/src/main/java/org/apache/camel/quarkus/component/grpc/deployment/GrpcProcessor.java
@@ -0,0 +1,243 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.grpc.deployment;
+
+import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.inject.Singleton;
+
+import io.grpc.BindableService;
+import io.grpc.stub.AbstractAsyncStub;
+import io.grpc.stub.AbstractBlockingStub;
+import io.grpc.stub.AbstractFutureStub;
+import io.grpc.stub.StreamObserver;
+import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
+import io.quarkus.arc.deployment.GeneratedBeanBuildItem;
+import io.quarkus.arc.deployment.GeneratedBeanGizmoAdaptor;
+import io.quarkus.deployment.annotations.BuildProducer;
+import io.quarkus.deployment.annotations.BuildStep;
+import io.quarkus.deployment.annotations.ExecutionTime;
+import io.quarkus.deployment.annotations.Record;
+import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
+import io.quarkus.deployment.builditem.FeatureBuildItem;
+import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
+import io.quarkus.gizmo.ClassCreator;
+import io.quarkus.gizmo.FieldCreator;
+import io.quarkus.gizmo.MethodCreator;
+import io.quarkus.gizmo.MethodDescriptor;
+import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.grpc.deployment.BindableServiceBuildItem;
+import org.apache.camel.component.grpc.GrpcComponent;
+import org.apache.camel.component.grpc.server.GrpcMethodHandler;
+import org.apache.camel.quarkus.core.deployment.spi.CamelBeanBuildItem;
+import org.apache.camel.quarkus.grpc.runtime.CamelGrpcRecorder;
+import org.apache.camel.quarkus.grpc.runtime.CamelQuarkusBindableService;
+import org.apache.camel.quarkus.grpc.runtime.QuarkusBindableServiceFactory;
+import org.jboss.jandex.ClassInfo;
+import org.jboss.jandex.DotName;
+import org.jboss.jandex.IndexView;
+import org.jboss.jandex.MethodInfo;
+import org.jboss.jandex.Type;
+
+class GrpcProcessor {
+
+    private static final DotName BINDABLE_SERVICE_DOT_NAME = DotName.createSimple(BindableService.class.getName());
+    private static final DotName[] STUB_CLASS_DOT_NAMES = new DotName[] {
+            DotName.createSimple(AbstractAsyncStub.class.getName()),
+            DotName.createSimple(AbstractBlockingStub.class.getName()),
+            DotName.createSimple(AbstractFutureStub.class.getName())
+    };
+    private static final String FEATURE = "camel-grpc";
+
+    @BuildStep
+    FeatureBuildItem feature() {
+        return new FeatureBuildItem(FEATURE);
+    }
+
+    @BuildStep
+    void registerForReflection(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            CombinedIndexBuildItem combinedIndexBuildItem) {
+
+        IndexView index = combinedIndexBuildItem.getIndex();
+        for (DotName dotName : STUB_CLASS_DOT_NAMES) {
+            index.getAllKnownSubclasses(dotName)
+                    .stream()
+                    .map(classInfo -> new ReflectiveClassBuildItem(true, false, classInfo.name().toString()))
+                    .forEach(reflectiveClass::produce);
+        }
+    }
+
+    @BuildStep
+    void createBindableServiceBeans(
+            BuildProducer<GeneratedBeanBuildItem> generatedBean,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
+            BuildProducer<BindableServiceBuildItem> bindableService,
+            CombinedIndexBuildItem combinedIndexBuildItem) {
+
+        Set<String> services = generateBindableServiceBeans(generatedBean, reflectiveClass, combinedIndexBuildItem.getIndex());
+        services.stream()
+                .map(DotName::createSimple)
+                .map(BindableServiceBuildItem::new)
+                .forEach(bindableService::produce);
+    }
+
+    @BuildStep
+    void quarkusBindableServiceFactoryBean(BuildProducer<AdditionalBeanBuildItem> additionalBeans) {
+        additionalBeans.produce(AdditionalBeanBuildItem.unremovableOf(QuarkusBindableServiceFactory.class));
+    }
+
+    @BuildStep
+    @Record(ExecutionTime.STATIC_INIT)
+    CamelBeanBuildItem createGrpcComponent(CamelGrpcRecorder recorder) {
+        return new CamelBeanBuildItem(
+                "grpc",
+                GrpcComponent.class.getName(),
+                recorder.createGrpcComponent());
+    }
+
+    private Set<String> generateBindableServiceBeans(BuildProducer<GeneratedBeanBuildItem> generatedBean,
+            BuildProducer<ReflectiveClassBuildItem> reflectiveClass, IndexView index) {
+        Set<String> generatedBindableServiceClassNames = new HashSet<>();
+        Collection<ClassInfo> bindableServiceImpls = index.getAllKnownImplementors(BINDABLE_SERVICE_DOT_NAME);
+
+        // Generate implementation classes from any abstract gRPC BindableService implementations included in the application archive
+        // Override the various sync and async methods so that requests can be intercepted and delegated to Camel routing
+        // This mimics similar logic in DefaultBindableServiceFactory that uses Javassist ProxyFactory & MethodHandler
+        for (ClassInfo service : bindableServiceImpls) {
+            if (!Modifier.isAbstract(service.flags())) {
+                continue;
+            }
+
+            String superClassName = service.name().toString();
+            String generatedClassName = superClassName + "QuarkusMethodHandler";
+            generatedBindableServiceClassNames.add(generatedClassName);
+
+            // Register the service classes for reflection
+            reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, service.name().toString()));
+            reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, service.enclosingClass().toString()));
+            reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, generatedClassName));
+
+            try (ClassCreator classCreator = ClassCreator.builder()
+                    .classOutput(new GeneratedBeanGizmoAdaptor(generatedBean))
+                    .className(generatedClassName)
+                    .superClass(superClassName)
+                    .interfaces(CamelQuarkusBindableService.class)
+                    .build()) {
+
+                classCreator.addAnnotation(Singleton.class);
+
+                FieldCreator serverMethodHandler = classCreator
+                        .getFieldCreator("methodHandler", GrpcMethodHandler.class.getName())
+                        .setModifiers(Modifier.PRIVATE);
+
+                // Create constructor
+                try (MethodCreator initMethod = classCreator.getMethodCreator("<init>", void.class)) {
+                    initMethod.setModifiers(Modifier.PUBLIC);
+                    initMethod.invokeSpecialMethod(MethodDescriptor.ofMethod(superClassName, "<init>", void.class),
+                            initMethod.getThis());
+                    initMethod.returnValue(null);
+                }
+
+                // Create setMethodHandler override
+                try (MethodCreator setMethodHandlerMethod = classCreator.getMethodCreator("setMethodHandler", void.class,
+                        GrpcMethodHandler.class)) {
+                    setMethodHandlerMethod.setModifiers(Modifier.PUBLIC);
+
+                    ResultHandle self = setMethodHandlerMethod.getThis();
+                    ResultHandle methodHandlerInstance = setMethodHandlerMethod.getMethodParam(0);
+
+                    setMethodHandlerMethod.writeInstanceField(serverMethodHandler.getFieldDescriptor(), self,
+                            methodHandlerInstance);
+                    setMethodHandlerMethod.returnValue(null);
+                }
+
+                // Override service methods that the gRPC component is interested in
+                // E.g methods with one or two parameters where one is of type StreamObserver
+                List<MethodInfo> methods = service.methods();
+                for (MethodInfo method : methods) {
+                    if (isCandidateServiceMethod(method)) {
+                        String[] params = method.parameters()
+                                .stream()
+                                .map(type -> type.name().toString())
+                                .toArray(String[]::new);
+
+                        ClassInfo classInfo = index
+                                .getClassByName(DotName.createSimple(GrpcMethodHandler.class.getName()));
+
+                        String returnType = method.returnType().name().toString();
+                        try (MethodCreator methodCreator = classCreator.getMethodCreator(method.name(), returnType, params)) {
+                            method.exceptions()
+                                    .stream()
+                                    .map(type -> type.name().toString())
+                                    .forEach(methodCreator::addException);
+
+                            if (method.parameters().size() == 1) {
+                                ResultHandle returnValue = generateGrpcDelegateMethod(classInfo, serverMethodHandler,
+                                        methodCreator,
+                                        method, "handleForConsumerStrategy");
+                                methodCreator.returnValue(returnValue);
+                            } else if (method.parameters().size() == 2) {
+                                generateGrpcDelegateMethod(classInfo, serverMethodHandler, methodCreator, method,
+                                        "handle");
+                                methodCreator.returnValue(null);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return generatedBindableServiceClassNames;
+    }
+
+    private boolean isCandidateServiceMethod(MethodInfo method) {
+        List<Type> parameters = method.parameters();
+        if (parameters.size() == 1) {
+            return parameters.get(0).name().toString().equals(StreamObserver.class.getName());
+        } else if (parameters.size() == 2) {
+            return parameters.get(1).name().toString().equals(StreamObserver.class.getName());
+        }
+        return false;
+    }
+
+    private ResultHandle generateGrpcDelegateMethod(ClassInfo classInfo, FieldCreator fieldCreator, MethodCreator methodCreator,
+            MethodInfo sourceMethod, String targetMethod) {
+
+        MethodInfo method = classInfo.methods()
+                .stream()
+                .filter(methodInfo -> methodInfo.name().equals(targetMethod))
+                .findFirst()
+                .orElseThrow(() -> new RuntimeException(
+                        "Unable to find target method " + targetMethod + " on GrpcServerMethodHandler"));
+
+        ResultHandle methodNameParam = methodCreator.load(sourceMethod.name());
+        ResultHandle[] methodParams;
+        if (sourceMethod.parameters().size() == 1) {
+            methodParams = new ResultHandle[] { methodCreator.getMethodParam(0), methodNameParam };
+        } else {
+            methodParams = new ResultHandle[] { methodCreator.getMethodParam(0), methodCreator.getMethodParam(1),
+                    methodNameParam };
+        }
+
+        ResultHandle resultHandle = methodCreator.readInstanceField(fieldCreator.getFieldDescriptor(), methodCreator.getThis());
+        return methodCreator.invokeVirtualMethod(method, resultHandle, methodParams);
+    }
+}
diff --git a/extensions-jvm/grpc/pom.xml b/extensions/grpc/pom.xml
similarity index 97%
rename from extensions-jvm/grpc/pom.xml
rename to extensions/grpc/pom.xml
index c220608..e49d35a 100644
--- a/extensions-jvm/grpc/pom.xml
+++ b/extensions/grpc/pom.xml
@@ -33,6 +33,5 @@
     <modules>
         <module>deployment</module>
         <module>runtime</module>
-        <module>integration-test</module>
     </modules>
 </project>
diff --git a/extensions-jvm/grpc/runtime/pom.xml b/extensions/grpc/runtime/pom.xml
similarity index 87%
rename from extensions-jvm/grpc/runtime/pom.xml
rename to extensions/grpc/runtime/pom.xml
index 4c7f6cd..454767a 100644
--- a/extensions-jvm/grpc/runtime/pom.xml
+++ b/extensions/grpc/runtime/pom.xml
@@ -48,12 +48,26 @@
 
     <dependencies>
         <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-grpc</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core</artifactId>
         </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-grpc</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.netty</groupId>
+                    <artifactId>netty-tcnative-boringssl-static</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.graalvm.nativeimage</groupId>
+            <artifactId>svm</artifactId>
         </dependency>
     </dependencies>
 
diff --git a/extensions/grpc/runtime/src/main/doc/configuration.adoc b/extensions/grpc/runtime/src/main/doc/configuration.adoc
new file mode 100644
index 0000000..f903be5
--- /dev/null
+++ b/extensions/grpc/runtime/src/main/doc/configuration.adoc
@@ -0,0 +1,6 @@
+This extension leverages https://quarkus.io/guides/grpc-service-implementation[Quarkus gRPC]. The configuration of the gRPC consumer is different than normal,
+since Quarkus manages the lifecycle of the gRPC server. This means that the consumer endpoint host and port is driven by the configuration properties `quarkus.grpc.server.host`
+and `quarkus.grpc.server.port` and thus the Camel gRPC endpoint configuration for the host & port is effectively ignored. But, it's still good practice to have the
+endpoint configuration host / port mirror the Quarkus gRPC host / port property values to avoid confusion and ambiguity.
+
+The full list of Quarkus gRPC configuration options can be found at the https://quarkus.io/guides/grpc-service-implementation#server-configuration[Quarkus gRPC guide].
diff --git a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelGrpcRecorder.java b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelGrpcRecorder.java
new file mode 100644
index 0000000..ba13200
--- /dev/null
+++ b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelGrpcRecorder.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.grpc.runtime;
+
+import java.util.Map;
+
+import io.quarkus.runtime.RuntimeValue;
+import io.quarkus.runtime.annotations.Recorder;
+import org.apache.camel.Consumer;
+import org.apache.camel.Endpoint;
+import org.apache.camel.Processor;
+import org.apache.camel.component.grpc.GrpcComponent;
+import org.apache.camel.component.grpc.GrpcConfiguration;
+import org.apache.camel.component.grpc.GrpcConsumer;
+import org.apache.camel.component.grpc.GrpcEndpoint;
+import org.apache.camel.component.grpc.server.BindableServiceFactory;
+import org.apache.camel.spi.annotations.Component;
+import org.apache.camel.support.CamelContextHelper;
+import org.apache.camel.support.service.ServiceHelper;
+
+import static org.apache.camel.component.grpc.GrpcConstants.GRPC_BINDABLE_SERVICE_FACTORY_NAME;
+
+@Recorder
+public class CamelGrpcRecorder {
+
+    public RuntimeValue<GrpcComponent> createGrpcComponent() {
+        return new RuntimeValue<>(new QuarkusGrpcComponent());
+    }
+
+    @Component("grpc")
+    static final class QuarkusGrpcComponent extends GrpcComponent {
+
+        @Override
+        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
+            GrpcConfiguration config = new GrpcConfiguration();
+            config = parseConfiguration(config, uri);
+
+            Endpoint endpoint = new QuarkusGrpcEndpoint(uri, this, config);
+            setProperties(endpoint, parameters);
+            return endpoint;
+        }
+    }
+
+    static final class QuarkusGrpcEndpoint extends GrpcEndpoint {
+
+        public QuarkusGrpcEndpoint(String uri, GrpcComponent component, GrpcConfiguration config) throws Exception {
+            super(uri, component, config);
+        }
+
+        @Override
+        public Consumer createConsumer(Processor processor) throws Exception {
+            return new QuarkusGrpcConsumer(this, processor, configuration);
+        }
+    }
+
+    static final class QuarkusGrpcConsumer extends GrpcConsumer {
+
+        public QuarkusGrpcConsumer(GrpcEndpoint endpoint, Processor processor, GrpcConfiguration configuration) {
+            super(endpoint, processor, configuration);
+        }
+
+        @Override
+        protected void doStart() throws Exception {
+            // Quarkus gRPC extension handles server startup so we only need to configure the BindableService for this consumer endpoint
+            ServiceHelper.startService(getProcessor());
+            BindableServiceFactory bindableServiceFactory = CamelContextHelper.lookup(endpoint.getCamelContext(),
+                    GRPC_BINDABLE_SERVICE_FACTORY_NAME, BindableServiceFactory.class);
+            bindableServiceFactory.createBindableService(this);
+        }
+    }
+}
diff --git a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelQuarkusBindableService.java b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelQuarkusBindableService.java
new file mode 100644
index 0000000..4a4426b
--- /dev/null
+++ b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/CamelQuarkusBindableService.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.grpc.runtime;
+
+import io.grpc.BindableService;
+import org.apache.camel.component.grpc.server.GrpcMethodHandler;
+
+/**
+ * A Camel Quarkus specific BindableService that enables a GrpcMethodHandler to be configured
+ */
+public interface CamelQuarkusBindableService extends BindableService {
+    void setMethodHandler(GrpcMethodHandler methodHandler);
+}
diff --git a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/QuarkusBindableServiceFactory.java b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/QuarkusBindableServiceFactory.java
new file mode 100644
index 0000000..7ffd3fd
--- /dev/null
+++ b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/QuarkusBindableServiceFactory.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.grpc.runtime;
+
+import javax.enterprise.inject.Instance;
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import io.grpc.BindableService;
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.grpc.GrpcConsumer;
+import org.apache.camel.component.grpc.GrpcEndpoint;
+import org.apache.camel.component.grpc.GrpcUtils;
+import org.apache.camel.component.grpc.server.BindableServiceFactory;
+import org.apache.camel.component.grpc.server.GrpcMethodHandler;
+
+import static org.apache.camel.component.grpc.GrpcConstants.GRPC_BINDABLE_SERVICE_FACTORY_NAME;
+
+/**
+ * A custom BindableServiceFactory which finds, configures and returns the appropriate BindableService
+ * that was dynamically generated at build time
+ */
+@Singleton
+@Named(GRPC_BINDABLE_SERVICE_FACTORY_NAME)
+public class QuarkusBindableServiceFactory implements BindableServiceFactory {
+
+    @Inject
+    Instance<CamelQuarkusBindableService> bindableServices;
+
+    @Override
+    public BindableService createBindableService(GrpcConsumer consumer) {
+        GrpcEndpoint endpoint = (GrpcEndpoint) consumer.getEndpoint();
+        CamelContext camelContext = endpoint.getCamelContext();
+
+        Class<?> baseClass = GrpcUtils.constructGrpcImplBaseClass(endpoint.getServicePackage(), endpoint.getServiceName(),
+                camelContext);
+
+        // Find the BindableService implementation that was generated in GrpcProcessor and configure the GrpcMethodHandler
+        CamelQuarkusBindableService bindableService = bindableServices.stream()
+                .filter(service -> baseClass.isAssignableFrom(service.getClass()))
+                .findFirst()
+                .orElseThrow(() -> new IllegalStateException(
+                        "Unable to find generated class for service " + endpoint.getServiceName()));
+
+        bindableService.setMethodHandler(new GrpcMethodHandler(consumer));
+        return bindableService;
+    }
+}
diff --git a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/graal/GrpcSubstitutions.java b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/graal/GrpcSubstitutions.java
new file mode 100644
index 0000000..9ca3e9f
--- /dev/null
+++ b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/graal/GrpcSubstitutions.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.grpc.runtime.graal;
+
+import com.oracle.svm.core.annotate.Substitute;
+import com.oracle.svm.core.annotate.TargetClass;
+import org.apache.camel.component.grpc.GrpcConsumer;
+import org.apache.camel.component.grpc.server.BindableServiceFactory;
+
+final class GrpcSubstitutions {
+}
+
+@TargetClass(GrpcConsumer.class)
+final class SubstituteGrpcConsumer {
+
+    @Substitute
+    private BindableServiceFactory getBindableServiceFactory() {
+        // Remove unwanted references to javassist.
+        // This is effectively replaced by the BindableServiceFactory lookup in QuarkusGrpcConsumer.doStart()
+        return null;
+    }
+}
diff --git a/extensions-jvm/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml
similarity index 97%
rename from extensions-jvm/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml
rename to extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml
index 4a016fd..3e14a06 100644
--- a/extensions-jvm/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml
+++ b/extensions/grpc/runtime/src/main/resources/META-INF/quarkus-extension.yaml
@@ -24,9 +24,8 @@
 name: "Camel gRPC"
 description: "Expose gRPC endpoints and access external gRPC endpoints"
 metadata:
-  unlisted: true
   guide: "https://camel.apache.org/camel-quarkus/latest/reference/extensions/grpc.html"
   categories:
   - "integration"
   status:
-  - "preview"
+  - "stable"
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 129356f..2540be7 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -109,6 +109,7 @@
         <module>google-sheets</module>
         <module>graphql</module>
         <module>grok</module>
+        <module>grpc</module>
         <module>gson</module>
         <module>http</module>
         <module>hystrix</module>
diff --git a/extensions-jvm/grpc/integration-test/pom.xml b/integration-tests/grpc/pom.xml
similarity index 73%
rename from extensions-jvm/grpc/integration-test/pom.xml
rename to integration-tests/grpc/pom.xml
index d1711ee..43e931c 100644
--- a/extensions-jvm/grpc/integration-test/pom.xml
+++ b/integration-tests/grpc/pom.xml
@@ -21,25 +21,14 @@
     <modelVersion>4.0.0</modelVersion>
     <parent>
         <groupId>org.apache.camel.quarkus</groupId>
-        <artifactId>camel-quarkus-build-parent-it</artifactId>
+        <artifactId>camel-quarkus-integration-tests</artifactId>
         <version>1.2.0-SNAPSHOT</version>
-        <relativePath>../../../poms/build-parent-it/pom.xml</relativePath>
     </parent>
 
-    <artifactId>camel-quarkus-grpc-integration-test</artifactId>
-    <name>Camel Quarkus :: gRPC :: Integration Test</name>
+    <artifactId>camel-quarkus-integration-test-grpc</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: gRPC</name>
     <description>Integration tests for Camel Quarkus gRPC extension</description>
 
-    <properties>
-        <!-- mvnd, a.k.a. Maven Daemon: https://github.com/mvndaemon/mvnd -->
-        <!-- The following rule tells mvnd to build the listed deployment modules before this module. -->
-        <!-- This is important because mvnd builds modules in parallel by default. The deployment modules are not -->
-        <!-- explicit dependencies of this module in the Maven sense, although they are required by the Quarkus Maven plugin. -->
-        <!-- Please update the rule whenever you change the dependencies of this module by running -->
-        <!--     mvn process-resources -Pformat    from the root directory -->
-        <mvnd.builder.rule>camel-quarkus-grpc-deployment</mvnd.builder.rule>
-    </properties>
-
     <dependencies>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
@@ -70,6 +59,34 @@
             <artifactId>camel-quarkus-integration-test-support</artifactId>
             <scope>test</scope>
         </dependency>
+
+        <!-- The following dependencies guarantee that this module is built after them. You can update them by running `mvn process-resources -Pformat -N` from the source tree root directory -->
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-direct-deployment</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-grpc-deployment</artifactId>
+            <version>${project.version}</version>
+            <type>pom</type>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>*</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
     </dependencies>
 
     <build>
@@ -155,4 +172,34 @@
             </plugin>
         </plugins>
     </build>
+
+    <profiles>
+        <profile>
+            <id>native</id>
+            <activation>
+                <property>
+                    <name>native</name>
+                </property>
+            </activation>
+            <properties>
+                <quarkus.package.type>native</quarkus.package.type>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
 </project>
diff --git a/extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcResource.java b/integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcResource.java
similarity index 100%
rename from extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcResource.java
rename to integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcResource.java
diff --git a/extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java b/integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java
similarity index 92%
rename from extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java
rename to integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java
index fab0cb3..4adfd56 100644
--- a/extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java
+++ b/integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/GrpcRoute.java
@@ -25,7 +25,7 @@ public class GrpcRoute extends RouteBuilder {
 
     @Override
     public void configure() throws Exception {
-        from("grpc://localhost:{{camel.grpc.consumer.port}}/org.apache.camel.quarkus.component.grpc.it.model.PingPong?synchronous=true")
+        from("grpc://localhost:9000/org.apache.camel.quarkus.component.grpc.it.model.PingPong?synchronous=true")
                 .process(exchange -> {
                     final Message message = exchange.getMessage();
                     final PingRequest request = message.getBody(PingRequest.class);
diff --git a/extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java b/integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java
similarity index 100%
rename from extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java
rename to integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java
index db153ca..6f7b74d 100644
--- a/extensions-jvm/grpc/integration-test/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java
+++ b/integration-tests/grpc/src/main/java/org/apache/camel/quarkus/component/grpc/it/PingPongImpl.java
@@ -31,8 +31,8 @@ public class PingPongImpl extends org.apache.camel.quarkus.component.grpc.it.mod
                 request.getPingName());
         PongResponse response = PongResponse.newBuilder().setPongName(request.getPingName() + GRPC_TEST_PONG_VALUE)
                 .setPongId(request.getPingId()).build();
+
         responseObserver.onNext(response);
         responseObserver.onCompleted();
     }
-
 }
diff --git a/extensions-jvm/grpc/integration-test/src/main/proto/pingpong.proto b/integration-tests/grpc/src/main/proto/pingpong.proto
similarity index 100%
rename from extensions-jvm/grpc/integration-test/src/main/proto/pingpong.proto
rename to integration-tests/grpc/src/main/proto/pingpong.proto
diff --git a/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcIT.java b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcIT.java
new file mode 100644
index 0000000..c06814c
--- /dev/null
+++ b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcIT.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.quarkus.component.grpc.it;
+
+import io.quarkus.test.junit.NativeImageTest;
+
+@NativeImageTest
+class GrpcIT extends GrpcTest {
+}
diff --git a/extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java
similarity index 90%
rename from extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java
rename to integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java
index c647fd2..b355d54 100644
--- a/extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java
+++ b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcServerTestResource.java
@@ -36,9 +36,7 @@ public class GrpcServerTestResource implements QuarkusTestResourceLifecycleManag
         try {
             final int port = AvailablePortFinder.getNextAvailable();
             grpcServer = ServerBuilder.forPort(port).addService(new PingPongImpl()).build().start();
-            return CollectionHelper.mapOf(
-                    "camel.grpc.test.server.port", String.valueOf(port),
-                    "camel.grpc.consumer.port", String.valueOf(AvailablePortFinder.getNextAvailable()));
+            return CollectionHelper.mapOf("camel.grpc.test.server.port", String.valueOf(port));
         } catch (Exception e) {
             throw new RuntimeException("Could not start gRPC server", e);
         }
diff --git a/extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java
similarity index 93%
rename from extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java
rename to integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java
index ab5b708..4625a0c 100644
--- a/extensions-jvm/grpc/integration-test/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java
+++ b/integration-tests/grpc/src/test/java/org/apache/camel/quarkus/component/grpc/it/GrpcTest.java
@@ -25,7 +25,6 @@ import org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc;
 import org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc.PingPongBlockingStub;
 import org.apache.camel.quarkus.component.grpc.it.model.PingRequest;
 import org.apache.camel.quarkus.component.grpc.it.model.PongResponse;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
@@ -35,14 +34,11 @@ import static org.hamcrest.Matchers.equalTo;
 @QuarkusTestResource(GrpcServerTestResource.class)
 class GrpcTest {
 
-    @ConfigProperty(name = "camel.grpc.consumer.port")
-    int consumerPort;
-
     @Test
     public void consumer() {
         ManagedChannel syncRequestChannel = null;
         try {
-            syncRequestChannel = ManagedChannelBuilder.forAddress("localhost", consumerPort).usePlaintext().build();
+            syncRequestChannel = ManagedChannelBuilder.forAddress("localhost", 9000).usePlaintext().build();
             final PingPongBlockingStub blockingStub = PingPongGrpc.newBlockingStub(syncRequestChannel);
 
             final PingRequest pingRequest = PingRequest.newBuilder()
@@ -73,5 +69,4 @@ class GrpcTest {
                 .body(equalTo("PINGPONG"));
 
     }
-
 }
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 7d7d48c..722472e 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -95,6 +95,7 @@
         <module>google</module>
         <module>graphql</module>
         <module>grok</module>
+        <module>grpc</module>
         <module>http</module>
         <module>hystrix</module>
         <module>infinispan</module>
diff --git a/tooling/scripts/test-categories.yaml b/tooling/scripts/test-categories.yaml
index 986f35a..cbcef00 100644
--- a/tooling/scripts/test-categories.yaml
+++ b/tooling/scripts/test-categories.yaml
@@ -25,6 +25,7 @@ cloud:
   - azure
   - consul
   - elasticsearch-rest
+  - grpc
   - smallrye-reactive-messaging
 core-main-validation:
   - core