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

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


The following commit(s) were added to refs/heads/main by this push:
     new 6e96ceb6a9 Introduce custom  CodeGenProvider for gRPC extension
6e96ceb6a9 is described below

commit 6e96ceb6a9dec6d46e7c3fb6ff9743edc3033149
Author: James Netherton <jamesnether...@gmail.com>
AuthorDate: Tue Aug 15 08:44:10 2023 +0100

    Introduce custom  CodeGenProvider for gRPC extension
    
    Co-authored-by: Peter Palaga <ppal...@redhat.com>
---
 docs/antora.yml                                    |   2 -
 .../ROOT/pages/reference/extensions/grpc.adoc      | 141 ++++---
 extensions/grpc/codegen/pom.xml                    | 150 +++++++
 .../codegen/CamelQuarkusGrpcCodegenProvider.java   | 434 +++++++++++++++++++++
 .../codegen/CamelQuarkusGrpcPostProcessor.java     |  90 +++++
 .../services/io.quarkus.deployment.CodeGenProvider |   1 +
 extensions/grpc/deployment/pom.xml                 |   4 +
 extensions/grpc/pom.xml                            |   1 +
 extensions/grpc/runtime/src/main/doc/usage.adoc    |  86 ++--
 .../quarkus/grpc/runtime/GrpcBuildTimeConfig.java  |  86 ++++
 integration-tests-support/grpc/pom.xml             |  31 ++
 .../main/resources/org/acme/proto/a/proto-a.proto  |  35 ++
 .../main/resources/org/acme/proto/b/proto-b.proto  |  35 ++
 .../resources/org/acme/proto/c/proto-c-1.proto     |  35 ++
 .../org/acme/proto/c/sub/package/proto-c-3.proto   |  35 ++
 .../resources/org/acme/proto/c/sub/proto-c-2.proto |  35 ++
 .../resources/org/acme/proto/d/proto-d-1.proto     |  35 ++
 .../org/acme/proto/d/sub/package/proto-d-3.proto   |  35 ++
 .../resources/org/acme/proto/d/sub/proto-d-2.proto |  35 ++
 .../main/resources/org/acme/proto/e/common.proto   |  35 ++
 .../main/resources/org/acme/proto/e/proto-e.proto  |  19 +
 integration-tests-support/pom.xml                  |   1 +
 integration-tests/grpc/pom.xml                     | 119 +-----
 .../grpc/src/main/proto/pingpong.proto             |   3 +
 .../grpc/src/main/resources/application.properties |   8 +
 .../camel/quarkus/component/grpc/it/GrpcTest.java  |  36 ++
 pom.xml                                            |   2 -
 poms/bom-test/pom.xml                              |   5 +
 poms/bom/pom.xml                                   |   5 +
 poms/bom/src/main/generated/flattened-full-pom.xml |   5 +
 .../src/main/generated/flattened-reduced-pom.xml   |   5 +
 .../generated/flattened-reduced-verbose-pom.xml    |   5 +
 poms/build-parent/pom.xml                          |  10 -
 33 files changed, 1355 insertions(+), 209 deletions(-)

diff --git a/docs/antora.yml b/docs/antora.yml
index 365263e3d5..a7659e3b01 100644
--- a/docs/antora.yml
+++ b/docs/antora.yml
@@ -36,8 +36,6 @@ asciidoc:
     mapstruct-version: 1.5.5.Final # replace ${mapstruct.version}
     min-maven-version: 3.8.2 # replace ${min-maven-version}
     target-maven-version: 3.9.3 # replace ${target-maven-version}
-    protobuf-maven-plugin-version: 0.6.1 # replace 
${protobuf-maven-plugin-version}
-    os-maven-plugin-version: 1.7.1 # replace ${os-maven-plugin-version}
 
     # Attributes used in xrefs to other Antora components
     cq-camel-components: components
diff --git a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc 
b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
index 623c185294..f9f45ba2a3 100644
--- a/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
+++ b/docs/modules/ROOT/pages/reference/extensions/grpc.adoc
@@ -50,47 +50,24 @@ endif::[]
 [id="extensions-grpc-usage-protobuf-generated-code"]
 === Protobuf generated code
 
-You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC 
service stubs with protobuf.
-
-[id="extensions-grpc-usage-protobuf-maven-plugin"]
-==== protobuf-maven-plugin
-
-The `protobuf-maven-plugin` can generate service stubs for `.proto` files. 
Below is an example configuration for Maven.
+Camel Quarkus gRPC can generate gRPC service stubs for `.proto` files. When 
using Maven, ensure that you have
+enabled the `generate-code` goals of the `quarkus-maven-plugin` in your 
project build.
 
 [source,xml]
 ----
 <build>
-    <extensions>
-        <extension>
-            <groupId>kr.motd.maven</groupId>
-            <artifactId>os-maven-plugin</artifactId>
-            <version>{os-maven-plugin-version}</version>
-        </extension>
-    </extensions>
-
     <plugins>
         <plugin>
-            <groupId>org.xolstice.maven.plugins</groupId>
-            <artifactId>protobuf-maven-plugin</artifactId>
-            <version>{protobuf-maven-plugin-version}</version>
-            <configuration>
-                
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
-                <pluginId>grpc-java</pluginId>
-                
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
-            </configuration>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-maven-plugin</artifactId>
+            <version>${quarkus.platform.version}</version>
+            <extensions>true</extensions>
             <executions>
                 <execution>
-                    <id>compile</id>
-                    <goals>
-                        <goal>compile</goal>
-                        <goal>compile-custom</goal>
-                    </goals>
-                </execution>
-                <execution>
-                    <id>test-compile</id>
                     <goals>
-                        <goal>test-compile</goal>
-                        <goal>test-compile-custom</goal>
+                        <goal>build</goal>
+                        <goal>generate-code</goal>
+                        <goal>generate-code-tests</goal>
                     </goals>
                 </execution>
             </executions>
@@ -99,24 +76,49 @@ The `protobuf-maven-plugin` can generate service stubs for 
`.proto` files. Below
 </build>
 ----
 
-[id="extensions-grpc-usage-generated-code-limitations"]
-==== Generated code limitations
+With this configuration, you can put your service and message definitions into 
the `src/main/proto` directory and
+the `quarkus-maven-plugin` will generate code from your `.proto` files.
 
-A limitation of the generated code is that it is annotated with the non 
Jakarta EE 10 friendly `@javax.annotation.Generated`.
+[id="extensions-grpc-usage-scanning-proto-files-with-imports"]
+==== Scanning `proto` files with imports
 
-To avoid compilation issues, the `grpc-java` project recommendation is to add 
a `provided` scoped dependency like this:
+The Protocol Buffers specification provides a way to import proto files. You 
can control the scope of dependencies to
+scan by adding configuration property 
`quarkus.camel.grpc.codegen.scan-for-imports` property to 
`application.properties`.
+The available options are outlined below.
 
-[source,xml]
+* `all` - Scan all dependencies
+* `none` - Disable dependency scanning. Use only the proto definitions defined 
in `src/main/proto` or `src/test/proto`
+* `groupId1:artifactId1,groupId2:artifactId2` - Scan only the dependencies 
matching the `groupId` and `artifactId` list
+
+The default value is `com.google.protobuf:protobuf-java`.
+
+[id="extensions-grpc-usage-scanning-proto-files-from-dependencies"]
+==== Scanning `proto` files from dependencies
+
+If you have proto files shared across multiple dependencies, you can generate 
gRPC service stubs for them by adding
+configuration property `quarkus.camel.grpc.codegen.scan-for-proto` to 
`application.properties`.
+
+First add a dependency for the artifact(s) containing proto files to your 
project. Next, enable proto file
+dependency scanning.
+
+[source,properties]
 ----
-<dependency>
-    <groupId>org.apache.tomcat</groupId>
-    <artifactId>annotations-api</artifactId>
-    <version>6.0.53</version>
-    <scope>provided</scope>
-</dependency>
+quarkus.camel.grpc.codegen.scan-for-proto=org.my.groupId1:my-artifact-id-1,org.my.groupId2:my-artifact-id-2
 ----
 
-Alternatively, you can use Maven or Gradle plugins to iterate over the 
generated code (found at `target/generated-sources` for Maven) and replace all 
instances of `@javax.annotation.Generated` with `@jakarta.annotation.Generated`.
+It is possible to include / exclude specific proto files from dependency 
scanning via configuration properties.
+
+The configuration property name suffix is the Maven `groupId` / `artifactId` 
for the dependency to configure includes / excludes on.
+Paths are relative to the classpath location of the proto files within the 
dependency. Paths can be an explicit path to a proto file,
+or as glob patterns to include / exclude multiple files.
+
+[source,properties]
+----
+quarkus.camel.grpc.codegen.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,baz/a-proto.proto
+quarkus.camel.grpc.codegen.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,baz/another-proto.proto
+----
+
+NOTE: The `:` character within property keys must be escaped with `\`.
 
 [id="extensions-grpc-usage-accessing-classpath-resources-in-native-mode"]
 === Accessing classpath resources in native mode
@@ -149,3 +151,54 @@ More information about selecting resources for inclusion 
in the native executabl
 
 At present there is no support for integrating Camel Quarkus gRPC with Quarkus 
gRPC. If you have both the `camel-quarkus-grpc` and `quarkus-grpc` extension 
dependency on the classpath, you are likely to encounter problems at build time 
when compiling your application.
 
+
+[id="extensions-grpc-additional-camel-quarkus-configuration"]
+== Additional Camel Quarkus configuration
+
+[width="100%",cols="80,5,15",options="header"]
+|===
+| Configuration property | Type | Default
+
+
+|icon:lock[title=Fixed at build time] 
[[quarkus.camel.grpc.codegen.enabled]]`link:#quarkus.camel.grpc.codegen.enabled[quarkus.camel.grpc.codegen.enabled]`
+
+If `true`, Camel Quarkus gRPC code generation is run for .proto files 
discovered from the `proto` directory, or from dependencies specified in the 
`scan-for-proto` or `scan-for-imports` options. When `false`, code generation 
for .proto files is disabled.
+| `boolean`
+| `true`
+
+|icon:lock[title=Fixed at build time] 
[[quarkus.camel.grpc.codegen.scan-for-proto]]`link:#quarkus.camel.grpc.codegen.scan-for-proto[quarkus.camel.grpc.codegen.scan-for-proto]`
+
+Camel Quarkus gRPC code generation can scan application dependencies for 
.proto files to generate Java stubs from them. This property sets the scope of 
the dependencies to scan. Applicable values:
+
+ - _none_ - default - don't scan dependencies
+ - a comma separated list of _groupId:artifactId_ coordinates to scan
+ - _all_ - scan all dependencies
+| `string`
+| `none`
+
+|icon:lock[title=Fixed at build time] 
[[quarkus.camel.grpc.codegen.scan-for-imports]]`link:#quarkus.camel.grpc.codegen.scan-for-imports[quarkus.camel.grpc.codegen.scan-for-imports]`
+
+Camel Quarkus gRPC code generation can scan dependencies for .proto files that 
can be imported by protos in this applications. Applicable values:
+
+ - _none_ - default - don't scan dependencies
+ - a comma separated list of _groupId:artifactId_ coordinates to scan
+ - _all_ - scan all dependencies  The default is 
_com.google.protobuf:protobuf-java_.
+| `string`
+| `com.google.protobuf:protobuf-java`
+
+|icon:lock[title=Fixed at build time] 
[[quarkus.camel.grpc.codegen.scan-for-proto-includes]]`link:#quarkus.camel.grpc.codegen.scan-for-proto-includes[quarkus.camel.grpc.codegen.scan-for-proto-includes]`
+
+Package path or file glob pattern includes per dependency containing .proto 
files to be considered for inclusion.
+| ``Map<String,List<String>>``
+| 
+
+|icon:lock[title=Fixed at build time] 
[[quarkus.camel.grpc.codegen.scan-for-proto-excludes]]`link:#quarkus.camel.grpc.codegen.scan-for-proto-excludes[quarkus.camel.grpc.codegen.scan-for-proto-excludes]`
+
+Package path or file glob pattern includes per dependency containing .proto 
files to be considered for exclusion.
+| ``Map<String,List<String>>``
+| 
+|===
+
+[.configuration-legend]
+{doc-link-icon-lock}[title=Fixed at build time] Configuration property fixed 
at build time. All other configuration properties are overridable at runtime.
+
diff --git a/extensions/grpc/codegen/pom.xml b/extensions/grpc/codegen/pom.xml
new file mode 100644
index 0000000000..759840ed37
--- /dev/null
+++ b/extensions/grpc/codegen/pom.xml
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-grpc-parent</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>camel-quarkus-grpc-codegen</artifactId>
+    <name>Camel Quarkus :: gRPC :: Codegen</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-core-deployment</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-devtools-utilities</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.google.code.findbugs</groupId>
+                    <artifactId>jsr305</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.github.javaparser</groupId>
+            <artifactId>javaparser-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>linux-aarch_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>linux-x86_32</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>linux-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>osx-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>osx-aarch_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>windows-x86_32</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protoc</artifactId>
+            <classifier>windows-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>linux-aarch_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>linux-x86_32</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>linux-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>osx-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>osx-aarch_64</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>windows-x86_32</classifier>
+            <type>exe</type>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>protoc-gen-grpc-java</artifactId>
+            <classifier>windows-x86_64</classifier>
+            <type>exe</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git 
a/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java
 
b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java
new file mode 100644
index 0000000000..4b8f437182
--- /dev/null
+++ 
b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcCodegenProvider.java
@@ -0,0 +1,434 @@
+/*
+ * 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.codegen;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.stream.Stream;
+
+import io.quarkus.bootstrap.model.ApplicationModel;
+import io.quarkus.bootstrap.prebuild.CodeGenException;
+import io.quarkus.deployment.CodeGenContext;
+import io.quarkus.deployment.CodeGenProvider;
+import io.quarkus.deployment.util.ProcessUtil;
+import io.quarkus.maven.dependency.ResolvedDependency;
+import io.quarkus.paths.PathFilter;
+import io.quarkus.runtime.util.HashUtil;
+import io.quarkus.utilities.OS;
+import org.eclipse.microprofile.config.Config;
+import org.jboss.logging.Logger;
+
+import static java.util.Arrays.asList;
+
+/**
+ * Custom {@link CodeGenProvider} for Camel Quarkus gRPC. Based on the 
original Quarkus gRPC implementation:
+ * <p>
+ * <a href=
+ * 
"https://github.com/quarkusio/quarkus/tree/main/extensions/grpc/codegen";>https://github.com/quarkusio/quarkus/tree/main/extensions/grpc/codegen</a>
+ * <p>
+ * The implementation does not include additional logic for features not 
supported in Camel gRPC, such as integration
+ * with Mutiny and CDI.
+ */
+public class CamelQuarkusGrpcCodegenProvider implements CodeGenProvider {
+    private static final Logger LOG = 
Logger.getLogger(CamelQuarkusGrpcCodegenProvider.class);
+    private static final String EXE = "exe";
+    private static final String PROTO = ".proto";
+    private static final String PROTOC = "protoc";
+    private static final String PROTOC_GROUP_ID = "com.google.protobuf";
+    private static final String SCAN_DEPENDENCIES_FOR_PROTO = 
"quarkus.camel.grpc.codegen.scan-for-proto";
+    private static final String SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN = 
"quarkus.camel.grpc.codegen.scan-for-proto-includes.\"%s\"";
+    private static final String SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN = 
"quarkus.camel.grpc.codegen.scan-for-proto-excludes.\"%s\"";
+    private static final String SCAN_FOR_IMPORTS = 
"quarkus.camel.grpc.codegen.scan-for-imports";
+
+    private Executables executables;
+
+    @Override
+    public String providerId() {
+        return "camel-quarkus-grpc";
+    }
+
+    @Override
+    public String inputExtension() {
+        return "proto";
+    }
+
+    @Override
+    public String inputDirectory() {
+        return "proto";
+    }
+
+    @Override
+    public boolean trigger(CodeGenContext context) throws CodeGenException {
+        final Config config = context.config();
+        if (!config.getValue("quarkus.camel.grpc.codegen.enabled", 
Boolean.class)) {
+            LOG.info("Skipping " + this.getClass() + " invocation on user's 
request");
+            return false;
+        }
+
+        Path outDir = context.outDir();
+        Path workDir = context.workDir();
+        Set<String> protoDirs = new HashSet<>();
+
+        try {
+            List<String> protoFiles = new ArrayList<>();
+            if (Files.isDirectory(context.inputDir())) {
+                try (Stream<Path> protoFilesPaths = 
Files.walk(context.inputDir())) {
+                    protoFilesPaths
+                            .filter(Files::isRegularFile)
+                            .filter(s -> s.toString().endsWith(PROTO))
+                            .map(Path::normalize)
+                            .map(Path::toAbsolutePath)
+                            .map(Path::toString)
+                            .forEach(protoFiles::add);
+                    
protoDirs.add(context.inputDir().normalize().toAbsolutePath().toString());
+                }
+            }
+            Path dirWithProtosFromDependencies = 
workDir.resolve("protoc-protos-from-dependencies");
+            Collection<Path> protoFilesFromDependencies = 
gatherProtosFromDependencies(dirWithProtosFromDependencies, protoDirs,
+                    context);
+            if (!protoFilesFromDependencies.isEmpty()) {
+                protoFilesFromDependencies.stream()
+                        .map(Path::normalize)
+                        .map(Path::toAbsolutePath)
+                        .map(Path::toString)
+                        .forEach(protoFiles::add);
+            }
+
+            if (!protoFiles.isEmpty()) {
+                initExecutables(workDir, context.applicationModel());
+
+                Path protocDependenciesDir = 
workDir.resolve("protoc-dependencies");
+                Collection<String> protosToImport = 
gatherDirectoriesWithImports(protocDependenciesDir, context);
+
+                if (!protoFilesFromDependencies.isEmpty() && 
!protosToImport.isEmpty()) {
+                    // Clean up potential duplicates that can exist when 
scan-for-imports artifacts clash with scan-for-proto configs
+                    protoFiles.forEach(file -> {
+                        if (!file.contains(context.inputDir().toString())) {
+                            String relativeFileName = 
file.replace(dirWithProtosFromDependencies.toString(), "");
+                            Path path = 
Paths.get(protocDependenciesDir.toAbsolutePath().toString(), relativeFileName);
+                            if (Files.exists(path)) {
+                                LOG.debugf("Cleaning up duplicate proto file 
%s", path);
+                                try {
+                                    Files.delete(path);
+                                } catch (IOException e) {
+                                    LOG.errorf("Failed cleaning up duplicate 
proto file %s", e);
+                                }
+                            }
+                        }
+                    });
+                }
+
+                List<String> command = new ArrayList<>();
+                command.add(executables.protoc.toString());
+                for (String protoImportDir : protosToImport) {
+                    command.add(String.format("-I=%s", 
escapeWhitespace(protoImportDir)));
+                }
+                for (String protoDir : protoDirs) {
+                    command.add(String.format("-I=%s", 
escapeWhitespace(protoDir)));
+                }
+
+                command.addAll(asList("--plugin=protoc-gen-grpc=" + 
executables.grpc,
+                        "--grpc_out=" + outDir,
+                        "--java_out=" + outDir));
+                command.addAll(protoFiles);
+
+                ProcessBuilder processBuilder = new ProcessBuilder(command);
+
+                final Process process = 
ProcessUtil.launchProcess(processBuilder, context.shouldRedirectIO());
+                int resultCode = process.waitFor();
+                if (resultCode != 0) {
+                    throw new CodeGenException("Failed to generate Java 
classes from proto files: " + protoFiles +
+                            " to " + outDir.toAbsolutePath() + " with command 
" + String.join(" ", command));
+                }
+                new CamelQuarkusGrpcPostProcessor(outDir).process();
+                LOG.info("Successfully finished generating and post-processing 
sources from proto files");
+                return true;
+            }
+        } catch (IOException | InterruptedException e) {
+            throw new CodeGenException(
+                    "Failed to generate java files from proto file in " + 
context.inputDir().toAbsolutePath(), e);
+        }
+
+        return false;
+    }
+
+    private static void copySanitizedProtoFile(ResolvedDependency artifact, 
Path protoPath, Path outProtoPath)
+            throws IOException {
+        boolean genericServicesFound = false;
+
+        try (var reader = Files.newBufferedReader(protoPath);
+                var writer = Files.newBufferedWriter(outProtoPath)) {
+
+            String line = reader.readLine();
+            while (line != null) {
+                // filter java_generic_services to avoid "Tried to write the 
same file twice"
+                // when set to true. Generic services are deprecated and 
replaced by classes generated by
+                // this plugin
+                if (!line.contains("java_generic_services")) {
+                    writer.write(line);
+                    writer.newLine();
+                } else {
+                    genericServicesFound = true;
+                }
+
+                line = reader.readLine();
+            }
+        }
+
+        if (genericServicesFound) {
+            LOG.infof("Ignoring option java_generic_services in %s:%s%s.", 
artifact.getGroupId(), artifact.getArtifactId(),
+                    protoPath);
+        }
+    }
+
+    private Collection<Path> gatherProtosFromDependencies(Path workDir, 
Set<String> protoDirectories,
+            CodeGenContext context) throws CodeGenException {
+        if (context.test()) {
+            return Collections.emptyList();
+        }
+        Config properties = context.config();
+        String scanDependencies = 
properties.getValue(SCAN_DEPENDENCIES_FOR_PROTO, String.class);
+
+        if ("none".equalsIgnoreCase(scanDependencies)) {
+            return Collections.emptyList();
+        }
+        boolean scanAll = "all".equalsIgnoreCase(scanDependencies);
+
+        List<String> dependenciesToScan = asList(scanDependencies.split(","));
+
+        ApplicationModel appModel = context.applicationModel();
+        List<Path> protoFilesFromDependencies = new ArrayList<>();
+        for (ResolvedDependency artifact : appModel.getRuntimeDependencies()) {
+            String packageId = String.format("%s:%s", artifact.getGroupId(), 
artifact.getArtifactId());
+            Collection<String> includes = properties
+                    
.getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_INCLUDE_PATTERN, 
packageId), String.class)
+                    .orElse(List.of());
+
+            Collection<String> excludes = properties
+                    
.getOptionalValues(String.format(SCAN_DEPENDENCIES_FOR_PROTO_EXCLUDE_PATTERN, 
packageId), String.class)
+                    .orElse(List.of());
+
+            if (scanAll
+                    || dependenciesToScan.contains(packageId)) {
+                extractProtosFromArtifact(workDir, protoFilesFromDependencies, 
protoDirectories, artifact, includes, excludes,
+                        true);
+            }
+        }
+        return protoFilesFromDependencies;
+    }
+
+    @Override
+    public boolean shouldRun(Path sourceDir, Config config) {
+        return CodeGenProvider.super.shouldRun(sourceDir, config)
+                || isGeneratingFromAppDependenciesEnabled(config);
+    }
+
+    private boolean isGeneratingFromAppDependenciesEnabled(Config config) {
+        return config.getOptionalValue(SCAN_DEPENDENCIES_FOR_PROTO, 
String.class)
+                .filter(value -> !"none".equals(value)).isPresent();
+    }
+
+    private Collection<String> gatherDirectoriesWithImports(Path workDir, 
CodeGenContext context) throws CodeGenException {
+        Config properties = context.config();
+
+        String scanForImports = properties.getOptionalValue(SCAN_FOR_IMPORTS, 
String.class)
+                .orElse("com.google.protobuf:protobuf-java");
+
+        if ("none".equals(scanForImports.toLowerCase(Locale.getDefault()))) {
+            return Collections.emptyList();
+        }
+
+        boolean scanAll = 
"all".equals(scanForImports.toLowerCase(Locale.getDefault()));
+        List<String> dependenciesToScan = 
Arrays.asList(scanForImports.split(","));
+
+        Set<String> importDirectories = new HashSet<>();
+        ApplicationModel appModel = context.applicationModel();
+        for (ResolvedDependency artifact : appModel.getRuntimeDependencies()) {
+            if (scanAll
+                    || dependenciesToScan.contains(
+                            String.format("%s:%s", artifact.getGroupId(), 
artifact.getArtifactId()))) {
+                extractProtosFromArtifact(workDir, new ArrayList<>(), 
importDirectories, artifact, List.of(),
+                        List.of(), false);
+            }
+        }
+        return importDirectories;
+    }
+
+    private void extractProtosFromArtifact(Path workDir, Collection<Path> 
protoFiles,
+            Set<String> protoDirectories, ResolvedDependency artifact, 
Collection<String> filesToInclude,
+            Collection<String> filesToExclude, boolean isDependency) throws 
CodeGenException {
+
+        try {
+            artifact.getContentTree(new PathFilter(filesToInclude, 
filesToExclude)).walk(
+                    pathVisit -> {
+                        Path path = pathVisit.getPath();
+                        if (Files.isRegularFile(path) && 
path.getFileName().toString().endsWith(PROTO)) {
+                            Path root = pathVisit.getRoot();
+                            if (Files.isDirectory(root)) {
+                                protoFiles.add(path);
+                                
protoDirectories.add(path.getParent().normalize().toAbsolutePath().toString());
+                            } else { // archive
+                                Path relativePath = 
path.getRoot().relativize(path);
+                                Path protoUnzipDir = workDir
+                                        
.resolve(HashUtil.sha1(root.normalize().toAbsolutePath().toString()))
+                                        .normalize().toAbsolutePath();
+                                try {
+                                    Files.createDirectories(protoUnzipDir);
+                                    
protoDirectories.add(protoUnzipDir.toString());
+                                } catch (IOException e) {
+                                    throw new GrpcCodeGenException("Failed to 
create directory: " + protoUnzipDir, e);
+                                }
+                                Path outPath = protoUnzipDir;
+                                for (Path part : relativePath) {
+                                    outPath = outPath.resolve(part.toString());
+                                }
+                                try {
+                                    
Files.createDirectories(outPath.getParent());
+                                    if (isDependency) {
+                                        copySanitizedProtoFile(artifact, path, 
outPath);
+                                    } else {
+                                        Files.copy(path, outPath, 
StandardCopyOption.REPLACE_EXISTING);
+                                    }
+                                    protoFiles.add(outPath);
+                                } catch (IOException e) {
+                                    throw new GrpcCodeGenException("Failed to 
extract proto file" + path + " to target: "
+                                            + outPath, e);
+                                }
+                            }
+                        }
+                    });
+        } catch (GrpcCodeGenException e) {
+            throw new CodeGenException(e.getMessage(), e);
+        }
+    }
+
+    private String escapeWhitespace(String path) {
+        if (OS.determineOS() == OS.LINUX) {
+            return path.replace(" ", "\\ ");
+        } else {
+            return path;
+        }
+    }
+
+    private void initExecutables(Path workDir, ApplicationModel model) throws 
CodeGenException {
+        if (executables == null) {
+            Path protocPath;
+            String protocPathProperty = 
System.getProperty("quarkus.grpc.protoc-path");
+            String classifier = 
System.getProperty("quarkus.grpc.protoc-os-classifier", osClassifier());
+            if (protocPathProperty == null) {
+                protocPath = findArtifactPath(model, PROTOC_GROUP_ID, PROTOC, 
classifier, EXE);
+            } else {
+                protocPath = Paths.get(protocPathProperty);
+            }
+            Path protocExe = makeExecutableFromPath(workDir, PROTOC_GROUP_ID, 
PROTOC, classifier, "exe", protocPath);
+
+            Path protocGrpcPluginExe = prepareExecutable(workDir, model,
+                    "io.grpc", "protoc-gen-grpc-java", classifier, "exe");
+
+            executables = new Executables(protocExe, protocGrpcPluginExe);
+        }
+    }
+
+    private Path prepareExecutable(Path buildDir, ApplicationModel model,
+            String groupId, String artifactId, String classifier, String 
packaging) throws CodeGenException {
+        Path artifactPath = findArtifactPath(model, groupId, artifactId, 
classifier, packaging);
+
+        return makeExecutableFromPath(buildDir, groupId, artifactId, 
classifier, packaging, artifactPath);
+    }
+
+    private Path makeExecutableFromPath(Path buildDir, String groupId, String 
artifactId, String classifier, String packaging,
+            Path artifactPath) throws CodeGenException {
+        Path exe = buildDir.resolve(String.format("%s-%s-%s-%s", groupId, 
artifactId, classifier, packaging));
+
+        if (Files.exists(exe)) {
+            return exe;
+        }
+
+        if (artifactPath == null) {
+            String location = String.format("%s:%s:%s:%s", groupId, 
artifactId, classifier, packaging);
+            throw new CodeGenException("Failed to find " + location + " among 
dependencies");
+        }
+
+        try {
+            Files.copy(artifactPath, exe, StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new CodeGenException("Failed to copy file: " + artifactPath 
+ " to " + exe, e);
+        }
+        if (!exe.toFile().setExecutable(true)) {
+            throw new CodeGenException("Failed to make the file executable: " 
+ exe);
+        }
+        return exe;
+    }
+
+    private static Path findArtifactPath(ApplicationModel model, String 
groupId, String artifactId, String classifier,
+            String packaging) {
+        Path artifactPath = null;
+
+        for (ResolvedDependency artifact : model.getDependencies()) {
+            if (groupId.equals(artifact.getGroupId())
+                    && artifactId.equals(artifact.getArtifactId())
+                    && classifier.equals(artifact.getClassifier())
+                    && packaging.equals(artifact.getType())) {
+                artifactPath = artifact.getResolvedPaths().getSinglePath();
+            }
+        }
+        return artifactPath;
+    }
+
+    private String osClassifier() throws CodeGenException {
+        String architecture = OS.getArchitecture();
+        switch (OS.determineOS()) {
+        case LINUX:
+            return "linux-" + architecture;
+        case WINDOWS:
+            return "windows-" + architecture;
+        case MAC:
+            return "osx-" + architecture;
+        default:
+            throw new CodeGenException(
+                    "Unsupported OS, please use maven plugin instead to 
generate Java classes from proto files");
+        }
+    }
+
+    private static class Executables {
+        final Path protoc;
+        final Path grpc;
+
+        Executables(Path protoc, Path grpc) {
+            this.protoc = protoc;
+            this.grpc = grpc;
+        }
+    }
+
+    private static class GrpcCodeGenException extends RuntimeException {
+        private GrpcCodeGenException(String message, Exception cause) {
+            super(message, cause);
+        }
+    }
+
+}
diff --git 
a/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java
 
b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java
new file mode 100644
index 0000000000..efd44afebd
--- /dev/null
+++ 
b/extensions/grpc/codegen/src/main/java/org/apache/camel/quarkus/grpc/codegen/CamelQuarkusGrpcPostProcessor.java
@@ -0,0 +1,90 @@
+/*
+ * 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.codegen;
+
+import java.io.File;
+import java.nio.file.Path;
+
+import com.github.javaparser.ast.CompilationUnit;
+import com.github.javaparser.ast.body.TypeDeclaration;
+import com.github.javaparser.ast.expr.NormalAnnotationExpr;
+import com.github.javaparser.ast.visitor.ModifierVisitor;
+import com.github.javaparser.ast.visitor.Visitable;
+import com.github.javaparser.utils.SourceRoot;
+import org.jboss.logging.Logger;
+
+/**
+ * Post processor for generated proto classes.
+ */
+public class CamelQuarkusGrpcPostProcessor {
+    private static final Logger LOG = 
Logger.getLogger(CamelQuarkusGrpcPostProcessor.class);
+    private static final String JAVAX_GENERATED = "javax" + 
".annotation.Generated";
+    private static final String JAKARTA_GENERATED = 
"jakarta.annotation.Generated";
+    private final Path root;
+
+    public CamelQuarkusGrpcPostProcessor(Path root) {
+        this.root = root;
+    }
+
+    public static void main(String[] args) {
+        for (String arg : args) {
+            Path path = new File(arg).toPath();
+            CamelQuarkusGrpcPostProcessor postProcessor = new 
CamelQuarkusGrpcPostProcessor(path);
+            postProcessor.process();
+        }
+    }
+
+    public void process() {
+        SourceRoot sr = new SourceRoot(root);
+        try {
+            sr.parse("", (localPath, absolutePath, result) -> {
+                if (result.isSuccessful()) {
+                    CompilationUnit unit = result.getResult().orElseThrow();
+                    if (unit.getPrimaryType().isPresent()) {
+                        TypeDeclaration<?> type = unit.getPrimaryType().get();
+                        process(unit, type);
+                        return SourceRoot.Callback.Result.SAVE;
+                    }
+                } else {
+                    LOG.errorf(
+                            "Unable to parse a protoc generated class, 
skipping post-processing for this " +
+                                    "file. Reported problems are %s",
+                            result.toString());
+                }
+
+                return SourceRoot.Callback.Result.DONT_SAVE;
+            });
+        } catch (Exception e) {
+            LOG.error("Unable to parse protoc generated classes - skipping 
gRPC post processing", e);
+        }
+    }
+
+    private void process(CompilationUnit unit, TypeDeclaration<?> primary) {
+        LOG.debugf("Post-processing %s", 
primary.getFullyQualifiedName().orElse(primary.getNameAsString()));
+        unit.accept(new ModifierVisitor<Void>() {
+            @Override
+            public Visitable visit(NormalAnnotationExpr n, Void arg) {
+                // Replace javax.annotation.Generated with the jakarta 
equivalent
+                // https://github.com/grpc/grpc-java/issues/9179
+                if (n.getNameAsString().equals(JAVAX_GENERATED)) {
+                    n.setName(JAKARTA_GENERATED);
+                }
+                return super.visit(n, arg);
+            }
+        }, null);
+    }
+}
diff --git 
a/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider
 
b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider
new file mode 100644
index 0000000000..16ab0e7338
--- /dev/null
+++ 
b/extensions/grpc/codegen/src/main/resources/META-INF/services/io.quarkus.deployment.CodeGenProvider
@@ -0,0 +1 @@
+org.apache.camel.quarkus.grpc.codegen.CamelQuarkusGrpcCodegenProvider
\ No newline at end of file
diff --git a/extensions/grpc/deployment/pom.xml 
b/extensions/grpc/deployment/pom.xml
index bd471510df..f7a8ef6381 100644
--- a/extensions/grpc/deployment/pom.xml
+++ b/extensions/grpc/deployment/pom.xml
@@ -38,6 +38,10 @@
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-core-deployment</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            <artifactId>camel-quarkus-grpc-codegen</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel.quarkus</groupId>
             <artifactId>camel-quarkus-grpc</artifactId>
diff --git a/extensions/grpc/pom.xml b/extensions/grpc/pom.xml
index b9958962b6..c8a039cdf0 100644
--- a/extensions/grpc/pom.xml
+++ b/extensions/grpc/pom.xml
@@ -31,6 +31,7 @@
     <packaging>pom</packaging>
 
     <modules>
+        <module>codegen</module>
         <module>deployment</module>
         <module>runtime</module>
     </modules>
diff --git a/extensions/grpc/runtime/src/main/doc/usage.adoc 
b/extensions/grpc/runtime/src/main/doc/usage.adoc
index 1bfc0a2eee..a6f686659c 100644
--- a/extensions/grpc/runtime/src/main/doc/usage.adoc
+++ b/extensions/grpc/runtime/src/main/doc/usage.adoc
@@ -1,45 +1,23 @@
 === Protobuf generated code
 
-You can https://github.com/grpc/grpc-java#generated-code[generate] gRPC 
service stubs with protobuf.
-
-==== protobuf-maven-plugin
-
-The `protobuf-maven-plugin` can generate service stubs for `.proto` files. 
Below is an example configuration for Maven.
+Camel Quarkus gRPC can generate gRPC service stubs for `.proto` files. When 
using Maven, ensure that you have
+enabled the `generate-code` goals of the `quarkus-maven-plugin` in your 
project build.
 
 [source,xml]
 ----
 <build>
-    <extensions>
-        <extension>
-            <groupId>kr.motd.maven</groupId>
-            <artifactId>os-maven-plugin</artifactId>
-            <version>{os-maven-plugin-version}</version>
-        </extension>
-    </extensions>
-
     <plugins>
         <plugin>
-            <groupId>org.xolstice.maven.plugins</groupId>
-            <artifactId>protobuf-maven-plugin</artifactId>
-            <version>{protobuf-maven-plugin-version}</version>
-            <configuration>
-                
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact>
-                <pluginId>grpc-java</pluginId>
-                
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
-            </configuration>
+            <groupId>io.quarkus</groupId>
+            <artifactId>quarkus-maven-plugin</artifactId>
+            <version>${quarkus.platform.version}</version>
+            <extensions>true</extensions>
             <executions>
                 <execution>
-                    <id>compile</id>
-                    <goals>
-                        <goal>compile</goal>
-                        <goal>compile-custom</goal>
-                    </goals>
-                </execution>
-                <execution>
-                    <id>test-compile</id>
                     <goals>
-                        <goal>test-compile</goal>
-                        <goal>test-compile-custom</goal>
+                        <goal>build</goal>
+                        <goal>generate-code</goal>
+                        <goal>generate-code-tests</goal>
                     </goals>
                 </execution>
             </executions>
@@ -48,23 +26,47 @@ The `protobuf-maven-plugin` can generate service stubs for 
`.proto` files. Below
 </build>
 ----
 
-==== Generated code limitations
+With this configuration, you can put your service and message definitions into 
the `src/main/proto` directory and
+the `quarkus-maven-plugin` will generate code from your `.proto` files.
 
-A limitation of the generated code is that it is annotated with the non 
Jakarta EE 10 friendly `@javax.annotation.Generated`.
+==== Scanning `proto` files with imports
 
-To avoid compilation issues, the `grpc-java` project recommendation is to add 
a `provided` scoped dependency like this:
+The Protocol Buffers specification provides a way to import proto files. You 
can control the scope of dependencies to
+scan by adding configuration property 
`quarkus.camel.grpc.codegen.scan-for-imports` property to 
`application.properties`.
+The available options are outlined below.
 
-[source,xml]
+* `all` - Scan all dependencies
+* `none` - Disable dependency scanning. Use only the proto definitions defined 
in `src/main/proto` or `src/test/proto`
+* `groupId1:artifactId1,groupId2:artifactId2` - Scan only the dependencies 
matching the `groupId` and `artifactId` list
+
+The default value is `com.google.protobuf:protobuf-java`.
+
+==== Scanning `proto` files from dependencies
+
+If you have proto files shared across multiple dependencies, you can generate 
gRPC service stubs for them by adding
+configuration property `quarkus.camel.grpc.codegen.scan-for-proto` to 
`application.properties`.
+
+First add a dependency for the artifact(s) containing proto files to your 
project. Next, enable proto file
+dependency scanning.
+
+[source,properties]
+----
+quarkus.camel.grpc.codegen.scan-for-proto=org.my.groupId1:my-artifact-id-1,org.my.groupId2:my-artifact-id-2
+----
+
+It is possible to include / exclude specific proto files from dependency 
scanning via configuration properties.
+
+The configuration property name suffix is the Maven `groupId` / `artifactId` 
for the dependency to configure includes / excludes on.
+Paths are relative to the classpath location of the proto files within the 
dependency. Paths can be an explicit path to a proto file,
+or as glob patterns to include / exclude multiple files.
+
+[source,properties]
 ----
-<dependency>
-    <groupId>org.apache.tomcat</groupId>
-    <artifactId>annotations-api</artifactId>
-    <version>6.0.53</version>
-    <scope>provided</scope>
-</dependency>
+quarkus.camel.grpc.codegen.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,baz/a-proto.proto
+quarkus.camel.grpc.codegen.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,baz/another-proto.proto
 ----
 
-Alternatively, you can use Maven or Gradle plugins to iterate over the 
generated code (found at `target/generated-sources` for Maven) and replace all 
instances of `@javax.annotation.Generated` with `@jakarta.annotation.Generated`.
+NOTE: The `:` character within property keys must be escaped with `\`.
 
 === Accessing classpath resources in native mode
 
diff --git 
a/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java
 
b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java
new file mode 100644
index 0000000000..0f7a3eda56
--- /dev/null
+++ 
b/extensions/grpc/runtime/src/main/java/org/apache/camel/quarkus/grpc/runtime/GrpcBuildTimeConfig.java
@@ -0,0 +1,86 @@
+/*
+ * 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.List;
+import java.util.Map;
+
+import io.quarkus.runtime.annotations.ConfigGroup;
+import io.quarkus.runtime.annotations.ConfigItem;
+import io.quarkus.runtime.annotations.ConfigPhase;
+import io.quarkus.runtime.annotations.ConfigRoot;
+
+@ConfigRoot(name = "camel.grpc", phase = ConfigPhase.BUILD_TIME)
+public class GrpcBuildTimeConfig {
+    /**
+     * Build time configuration options for Camel Quarkus gRPC code generator.
+     */
+    @ConfigItem
+    public CodeGenConfig codegen;
+
+    @ConfigGroup
+    public static class CodeGenConfig {
+        /**
+         * If {@code true}, Camel Quarkus gRPC code generation is run for 
.proto files discovered from the {@code proto}
+         * directory, or from dependencies specified in the {@code 
scan-for-proto} or {@code scan-for-imports} options. When
+         * {@code false}, code generation for .proto files is disabled.
+         */
+        @ConfigItem(defaultValue = "true")
+        public boolean enabled;
+
+        /**
+         * Camel Quarkus gRPC code generation can scan application 
dependencies for .proto files to generate Java stubs
+         * from them.
+         * This property sets the scope of the dependencies to scan.
+         * Applicable values:
+         * <ul>
+         * <li><i>none</i> - default - don't scan dependencies</li>
+         * <li>a comma separated list of <i>groupId:artifactId</i> coordinates 
to scan</li>
+         * <li><i>all</i> - scan all dependencies</li>
+         * </ul>
+         */
+        @ConfigItem(defaultValue = "none")
+        public String scanForProto;
+
+        /**
+         * Camel Quarkus gRPC code generation can scan dependencies for .proto 
files that can be imported by protos in this
+         * applications.
+         * Applicable values:
+         * <ul>
+         * <li><i>none</i> - default - don't scan dependencies</li>
+         * <li>a comma separated list of <i>groupId:artifactId</i> coordinates 
to scan</li>
+         * <li><i>all</i> - scan all dependencies</li>
+         * </ul>
+         *
+         * The default is <i>com.google.protobuf:protobuf-java</i>.
+         */
+        @ConfigItem(defaultValue = "com.google.protobuf:protobuf-java")
+        public String scanForImports;
+
+        /**
+         * Package path or file glob pattern includes per dependency 
containing .proto files to be considered for inclusion.
+         */
+        @ConfigItem
+        public Map<String, List<String>> scanForProtoIncludes;
+
+        /**
+         * Package path or file glob pattern includes per dependency 
containing .proto files to be considered for exclusion.
+         */
+        @ConfigItem
+        public Map<String, List<String>> scanForProtoExcludes;
+    }
+}
diff --git a/integration-tests-support/grpc/pom.xml 
b/integration-tests-support/grpc/pom.xml
new file mode 100644
index 0000000000..ed38040e5c
--- /dev/null
+++ b/integration-tests-support/grpc/pom.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-integration-tests-support</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>camel-quarkus-integration-tests-support-grpc</artifactId>
+    <name>Camel Quarkus :: Integration Tests :: gRPC :: Support</name>
+</project>
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto
new file mode 100644
index 0000000000..f9fc661b41
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/a/proto-a.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.a";
+option java_outer_classname = "PingPongProtoA";
+
+package org.acme.proto.a;
+
+service TestA {
+  rpc PingSyncSync (PingRequestA) returns (PongResponseA) {}
+}
+
+message PingRequestA {
+  string ping_name = 1;
+}
+
+message PongResponseA {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto
new file mode 100644
index 0000000000..4aae4b2a34
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/b/proto-b.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.b";
+option java_outer_classname = "PingPongProtoB";
+
+package org.acme.proto.b;
+
+service TestB {
+  rpc PingSyncSync (PingRequestB) returns (PongResponseB) {}
+}
+
+message PingRequestB {
+  string ping_name = 1;
+}
+
+message PongResponseB {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto
new file mode 100644
index 0000000000..6d0c48f7da
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/proto-c-1.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.c";
+option java_outer_classname = "PingPongProtoC";
+
+package org.acme.proto.c;
+
+service TestC {
+  rpc PingSyncSync (PingRequestC) returns (PongResponseC) {}
+}
+
+message PingRequestC {
+  string ping_name = 1;
+}
+
+message PongResponseC {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto
new file mode 100644
index 0000000000..7a023479cc
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/package/proto-c-3.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.c.sub.dir";
+option java_outer_classname = "PingPongProtoC";
+
+package org.acme.proto.c.sub.dir;
+
+service TestC {
+  rpc PingSyncSync (PingRequestC) returns (PongResponseC) {}
+}
+
+message PingRequestC {
+  string ping_name = 1;
+}
+
+message PongResponseC {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto
new file mode 100644
index 0000000000..533c40ca33
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/c/sub/proto-c-2.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.c.sub";
+option java_outer_classname = "PingPongProtoC";
+
+package org.acme.proto.c.sub;
+
+service TestC {
+  rpc PingSyncSync (PingRequestC) returns (PongResponseC) {}
+}
+
+message PingRequestC {
+  string ping_name = 1;
+}
+
+message PongResponseC {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto
new file mode 100644
index 0000000000..49b2d57cc3
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/proto-d-1.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.d";
+option java_outer_classname = "PingPongProtoD";
+
+package org.acme.proto.d;
+
+service TestD {
+  rpc PingSyncSync (PingRequestD) returns (PongResponseD) {}
+}
+
+message PingRequestD {
+  string ping_name = 1;
+}
+
+message PongResponseD {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto
new file mode 100644
index 0000000000..234b487c24
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/package/proto-d-3.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.d.sub.dir";
+option java_outer_classname = "PingPongProtoD";
+
+package org.acme.proto.sub.dir.d;
+
+service TestD {
+  rpc PingSyncSync (PingRequestD) returns (PongResponseD) {}
+}
+
+message PingRequestD {
+  string ping_name = 1;
+}
+
+message PongResponseD {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto
new file mode 100644
index 0000000000..2cf0e8715b
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/d/sub/proto-d-2.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.c.sub";
+option java_outer_classname = "PingPongProtoD";
+
+package org.acme.proto.d.sub;
+
+service TestD {
+  rpc PingSyncSync (PingRequestD) returns (PongResponseD) {}
+}
+
+message PingRequestD {
+  string ping_name = 1;
+}
+
+message PongResponseD {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto
new file mode 100644
index 0000000000..9daa38a04b
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/common.proto
@@ -0,0 +1,35 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "org.acme.proto.e";
+option java_outer_classname = "PingPongProtoE";
+
+package org.acme.proto.e;
+
+service TestE {
+  rpc PingSyncSync (PingRequestE) returns (PongResponseE) {}
+}
+
+message PingRequestE {
+  string ping_name = 1;
+}
+
+message PongResponseE {
+  string pong_name = 1;
+}
\ No newline at end of file
diff --git 
a/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto
 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto
new file mode 100644
index 0000000000..4be113a27d
--- /dev/null
+++ 
b/integration-tests-support/grpc/src/main/resources/org/acme/proto/e/proto-e.proto
@@ -0,0 +1,19 @@
+/**
+ * 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.
+ */
+syntax = "proto3";
+import "org/acme/proto/e/common.proto";
+import "google/protobuf/timestamp.proto";
diff --git a/integration-tests-support/pom.xml 
b/integration-tests-support/pom.xml
index 84ebb6b244..bd9292e7c7 100644
--- a/integration-tests-support/pom.xml
+++ b/integration-tests-support/pom.xml
@@ -45,6 +45,7 @@
         <module>custom-type-converter</module>
         <module>custom-main-listener</module>
         <module>google</module>
+        <module>grpc</module>
         <module>jdbc</module>
         <module>kafka</module>
         <module>mongodb</module>
diff --git a/integration-tests/grpc/pom.xml b/integration-tests/grpc/pom.xml
index c2e4dfee39..843227c5dd 100644
--- a/integration-tests/grpc/pom.xml
+++ b/integration-tests/grpc/pom.xml
@@ -30,10 +30,6 @@
     <name>Camel Quarkus :: Integration Tests :: gRPC</name>
     <description>Integration tests for Camel Quarkus gRPC 
extension</description>
 
-    <properties>
-        <cq.skip.protobuf>false</cq.skip.protobuf><!-- set to true via groovy 
below on unsupported platforms or if -Dquickly is available -->
-    </properties>
-
     <dependencies>
         <dependency>
             <groupId>org.apache.camel</groupId>
@@ -59,6 +55,10 @@
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-resteasy-jsonb</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel.quarkus</groupId>
+            
<artifactId>camel-quarkus-integration-tests-support-grpc</artifactId>
+        </dependency>
 
         <!-- test dependencies -->
         <dependency>
@@ -79,6 +79,7 @@
         <dependency>
             <groupId>org.awaitility</groupId>
             <artifactId>awaitility</artifactId>
+            <scope>test</scope>
         </dependency>
     </dependencies>
 
@@ -128,116 +129,16 @@
                 </executions>
             </plugin>
             <plugin>
-                <groupId>kr.motd.maven</groupId>
-                <artifactId>os-maven-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>detect-os</id>
-                        <phase>initialize</phase>
-                        <goals>
-                            <goal>detect</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.codehaus.gmavenplus</groupId>
-                <artifactId>gmavenplus-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <!-- Skip code generation & tests on unsupported 
platforms -->
-                        <id>skip-plugins-on-unsupported-platform</id>
-                        <phase>generate-sources</phase>
-                        <goals>
-                            <goal>execute</goal>
-                        </goals>
-                        <configuration>
-                            <scripts>
-                                <script>
-                                    String platformUnsupported = 
project.properties['os.detected.classifier'].matches('^.*?(linux|windows|osx)-x86.*$')
 ? 'false' : 'true'
-                                    project.properties['skipTests'] = 
platformUnsupported
-                                    project.properties['cq.skip.protobuf'] = 
platformUnsupported || project.properties.containsKey('quickly')
-                                </script>
-                            </scripts>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <!--
-                            Hack around grpc-java protobuf generator tagging 
generated classes with javax.annotation.Generated.
-
-                            This avoids implementing the recommendation to add 
a dependency on org.apache.tomcat:annotations-api:
-
-                            https://github.com/grpc/grpc-java#download
-
-                            Hopefully this will eventually get fixed for the 
Jakarta 10+ world:
-
-                            https://github.com/grpc/grpc-java/issues/9179
-                        -->
-                        <id>strip-javax-generated-annotation</id>
-                        <phase>process-sources</phase>
-                        <goals>
-                            <goal>execute</goal>
-                        </goals>
-                        <configuration>
-                            <scripts>
-                                <script>
-                                    def buildDir = project.build.directory
-                                    new 
File("${buildDir}/generated-sources").eachFileRecurse { file -&gt;
-                                        if (file.name.endsWith('.java') 
&amp;&amp; file.text.contains('javax.annotation.Generated')) {
-                                            def modifiedContent = 
file.text.replace('javax', 'jakarta')
-                                            file.write(modifiedContent)
-                                        }
-                                    }
-                                </script>
-                            </scripts>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.xolstice.maven.plugins</groupId>
-                <artifactId>protobuf-maven-plugin</artifactId>
+                <groupId>io.quarkus</groupId>
+                <artifactId>quarkus-maven-plugin</artifactId>
                 <extensions>true</extensions>
                 <executions>
                     <execution>
                         <goals>
-                            <goal>compile</goal>
-                            <goal>compile-custom</goal>
-                        </goals>
-                        <phase>generate-sources</phase>
-                        <configuration>
-                            
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
-                            <pluginId>grpc-java</pluginId>
-                            
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
-                            <checkStaleness>true</checkStaleness>
-                            <skip>${cq.skip.protobuf}</skip>
-                        </configuration>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>default-compile</id>
-                        <phase>compile</phase>
-                        <goals>
-                            <goal>compile</goal>
+                            <goal>build</goal>
+                            <goal>generate-code</goal>
+                            <goal>generate-code-tests</goal>
                         </goals>
-                        <configuration>
-                            <skipMain>${cq.skip.protobuf}</skipMain>
-                        </configuration>
-                    </execution>
-                    <execution>
-                        <id>default-testCompile</id>
-                        <phase>test-compile</phase>
-                        <goals>
-                            <goal>testCompile</goal>
-                        </goals>
-                        <configuration>
-                            <skip>${cq.skip.protobuf}</skip>
-                        </configuration>
                     </execution>
                 </executions>
             </plugin>
diff --git a/integration-tests/grpc/src/main/proto/pingpong.proto 
b/integration-tests/grpc/src/main/proto/pingpong.proto
index 459a3b33af..2e09f3bc1a 100644
--- a/integration-tests/grpc/src/main/proto/pingpong.proto
+++ b/integration-tests/grpc/src/main/proto/pingpong.proto
@@ -16,6 +16,9 @@
  */
 syntax = "proto3";
 
+// Tests that arbitrary imports can work
+import "google/protobuf/timestamp.proto";
+
 option java_multiple_files = true;
 option java_package = "org.apache.camel.quarkus.component.grpc.it.model";
 option java_outer_classname = "PingPongProto";
diff --git a/integration-tests/grpc/src/main/resources/application.properties 
b/integration-tests/grpc/src/main/resources/application.properties
index 7fb36b14c9..63661b9b4a 100644
--- a/integration-tests/grpc/src/main/resources/application.properties
+++ b/integration-tests/grpc/src/main/resources/application.properties
@@ -16,3 +16,11 @@
 ## ---------------------------------------------------------------------------
 
 quarkus.native.resources.includes=certs/*.key,certs/*.pem,keys/*.json
+
+# Test codegen protobuf imports
+quarkus.camel.grpc.codegen.scan-for-imports=com.google.protobuf:protobuf-java,org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc
+
+# Test codegen scanning for proto files in other dependencies
+quarkus.camel.grpc.codegen.scan-for-proto=org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc
+quarkus.camel.grpc.codegen.scan-for-proto-includes."org.apache.camel.quarkus\:camel-quarkus-integration-tests-support-grpc"=org/acme/proto/a/*,org/acme/proto/b/proto-b.proto,org/acme/proto/c/**,org/acme/proto/d/**,org/acme/proto/e/**
+quarkus.camel.grpc.codegen.scan-for-proto-excludes."org.apache.camel.quarkus\:camel-quarkus-integration-tests-support-grpc"=org/acme/proto/d/*,org/acme/proto/d/sub/proto-d-2.proto,org/acme/proto/d/sub/package**
diff --git 
a/integration-tests/grpc/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
index 2a891f32b6..fdae550b34 100644
--- 
a/integration-tests/grpc/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
@@ -17,6 +17,7 @@
 package org.apache.camel.quarkus.component.grpc.it;
 
 import java.util.Iterator;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Stream;
@@ -39,6 +40,7 @@ import 
org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc.PingPongBlo
 import 
org.apache.camel.quarkus.component.grpc.it.model.PingPongGrpc.PingPongStub;
 import org.apache.camel.quarkus.component.grpc.it.model.PingRequest;
 import org.apache.camel.quarkus.component.grpc.it.model.PongResponse;
+import org.apache.camel.util.StringHelper;
 import org.awaitility.Awaitility;
 import org.eclipse.microprofile.config.Config;
 import org.eclipse.microprofile.config.ConfigProvider;
@@ -62,6 +64,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
 
 @QuarkusTest
 @QuarkusTestResource(GrpcServerTestResource.class)
@@ -574,6 +577,25 @@ class GrpcTest {
         }
     }
 
+    @ParameterizedTest
+    @MethodSource("generatedProtoClassNames")
+    public void codeGenDependencyScan(String generatedClassPackage) {
+        // Additional proto files scanned from 
org.apache.camel.quarkus:camel-quarkus-integration-tests-support-grpc
+        ClassLoader classLoader = 
Thread.currentThread().getContextClassLoader();
+        String packageChar = StringHelper.after(generatedClassPackage, 
"org.acme.proto.").replaceAll(".sub|.dir", "");
+        String generatedClassName = generatedClassPackage + ".PingPongProto" + 
packageChar.toUpperCase();
+        try {
+            classLoader.loadClass(generatedClassName);
+            if (packageChar.equals("d")) {
+                fail("Expected to not be able to load generated class: " + 
generatedClassName);
+            }
+        } catch (ClassNotFoundException e) {
+            if (!packageChar.equals("d")) {
+                fail("Expected to be able to load generated class: " + 
generatedClassName);
+            }
+        }
+    }
+
     static Stream<Arguments> producerMethodPorts() {
         return Stream.of(
                 Arguments.of("pingSyncSync", 
"{{camel.grpc.test.async.server.port}}"),
@@ -584,6 +606,20 @@ class GrpcTest {
                 Arguments.of("pingAsyncAsync", 
"{{camel.grpc.test.sync.server.port}}"));
     }
 
+    static List<String> generatedProtoClassNames() {
+        String packagePrefix = "org.acme.proto.";
+        return List.of(
+                packagePrefix + "a",
+                packagePrefix + "b",
+                packagePrefix + "c",
+                packagePrefix + "c.sub",
+                packagePrefix + "c.sub.dir",
+                packagePrefix + "d",
+                packagePrefix + "d.sub",
+                packagePrefix + "d.sub.dir",
+                packagePrefix + "e");
+    }
+
     static final class PongResponseStreamObserver implements 
StreamObserver<PongResponse> {
         private final CountDownLatch latch;
         private final boolean simulateError;
diff --git a/pom.xml b/pom.xml
index 31f015663d..146fa3282c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -200,8 +200,6 @@
         <maven-scm-plugin.version>2.0.0</maven-scm-plugin.version>
         <maven-shade-plugin.version>3.5.0</maven-shade-plugin.version>
         <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
-        <os-maven-plugin.version>1.7.1</os-maven-plugin.version>
-        
<protobuf-maven-plugin.version>${protobuf-maven-plugin-version}</protobuf-maven-plugin.version>
         <rpkgtests-maven-plugin.version>1.0.0</rpkgtests-maven-plugin.version>
 
         <!-- Test container image properties -->
diff --git a/poms/bom-test/pom.xml b/poms/bom-test/pom.xml
index 077be210a4..df923ebe13 100644
--- a/poms/bom-test/pom.xml
+++ b/poms/bom-test/pom.xml
@@ -175,6 +175,11 @@
                 
<artifactId>camel-quarkus-integration-tests-support-google</artifactId>
                 <version>${camel-quarkus.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel.quarkus</groupId>
+                
<artifactId>camel-quarkus-integration-tests-support-grpc</artifactId>
+                <version>${camel-quarkus.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel.quarkus</groupId>
                 <artifactId>camel-quarkus-integration-test-support</artifactId>
diff --git a/poms/bom/pom.xml b/poms/bom/pom.xml
index 4bab975644..58665b94e6 100644
--- a/poms/bom/pom.xml
+++ b/poms/bom/pom.xml
@@ -3837,6 +3837,11 @@
                 <artifactId>camel-quarkus-grpc-deployment</artifactId>
                 <version>${camel-quarkus.version}</version>
             </dependency>
+            <dependency>
+                <groupId>org.apache.camel.quarkus</groupId>
+                <artifactId>camel-quarkus-grpc-codegen</artifactId>
+                <version>${camel-quarkus.version}</version>
+            </dependency>
             <dependency>
                 <groupId>org.apache.camel.quarkus</groupId>
                 <artifactId>camel-quarkus-gson</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-full-pom.xml 
b/poms/bom/src/main/generated/flattened-full-pom.xml
index fdece605a3..498a885125 100644
--- a/poms/bom/src/main/generated/flattened-full-pom.xml
+++ b/poms/bom/src/main/generated/flattened-full-pom.xml
@@ -3763,6 +3763,11 @@
         <artifactId>camel-quarkus-grpc-deployment</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
         <version>3.0.0-SNAPSHOT</version><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+        <artifactId>camel-quarkus-grpc-codegen</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+        <version>3.0.0-SNAPSHOT</version><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
         <artifactId>camel-quarkus-gson</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
diff --git a/poms/bom/src/main/generated/flattened-reduced-pom.xml 
b/poms/bom/src/main/generated/flattened-reduced-pom.xml
index 726a1de96e..69509ddae3 100644
--- a/poms/bom/src/main/generated/flattened-reduced-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-pom.xml
@@ -3763,6 +3763,11 @@
         <artifactId>camel-quarkus-grpc-deployment</artifactId>
         <version>3.0.0-SNAPSHOT</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId>
+        <artifactId>camel-quarkus-grpc-codegen</artifactId>
+        <version>3.0.0-SNAPSHOT</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId>
         <artifactId>camel-quarkus-gson</artifactId>
diff --git a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml 
b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
index fc09ab6bda..de31528b04 100644
--- a/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
+++ b/poms/bom/src/main/generated/flattened-reduced-verbose-pom.xml
@@ -3763,6 +3763,11 @@
         <artifactId>camel-quarkus-grpc-deployment</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
         <version>3.0.0-SNAPSHOT</version><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
       </dependency>
+      <dependency>
+        <groupId>org.apache.camel.quarkus</groupId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+        <artifactId>camel-quarkus-grpc-codegen</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+        <version>3.0.0-SNAPSHOT</version><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
+      </dependency>
       <dependency>
         <groupId>org.apache.camel.quarkus</groupId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
         <artifactId>camel-quarkus-gson</artifactId><!-- 
org.apache.camel.quarkus:camel-quarkus-bom:${project.version} -->
diff --git a/poms/build-parent/pom.xml b/poms/build-parent/pom.xml
index ca0f8efd25..64ad613061 100644
--- a/poms/build-parent/pom.xml
+++ b/poms/build-parent/pom.xml
@@ -71,11 +71,6 @@
                         </execution>
                     </executions>
                 </plugin>
-                <plugin>
-                    <groupId>kr.motd.maven</groupId>
-                    <artifactId>os-maven-plugin</artifactId>
-                    <version>${os-maven-plugin.version}</version>
-                </plugin>
                 <plugin>
                     <groupId>org.apache.camel.quarkus</groupId>
                     <artifactId>camel-quarkus-maven-plugin</artifactId>
@@ -100,11 +95,6 @@
                     <artifactId>jandex-maven-plugin</artifactId>
                     <version>${jandex-maven-plugin.version}</version>
                 </plugin>
-                <plugin>
-                    <groupId>org.xolstice.maven.plugins</groupId>
-                    <artifactId>protobuf-maven-plugin</artifactId>
-                    <version>${protobuf-maven-plugin.version}</version>
-                </plugin>
                 <plugin>
                     <groupId>net.revelc.code.formatter</groupId>
                     <artifactId>formatter-maven-plugin</artifactId>


Reply via email to