Repository: spring-projects-experimental/spring-grpc
Pull request #120: Add AOT/Native sample w/ integration test
Author: login: therepanic
Created: 2025-02-28T21:54:52Z | Merged: 2025-03-10T17:26:34Z

Since I don't have much expertise in this area, I spent some time, but I still managed to combine Spring AOT + native image. I did this by adding the `org.springframework.boot.aot` plugin for AOT, and to make it all native, I added `BP_NATIVE_IMAGE=true` to the environment.

And everything is as described in the issue, we can't get the project to build. When trying to build, we will see the following log:
```
    [creator]     Error: Classes that should be initialized at run time got initialized during image building:
    [creator]      ch.qos.logback.classic.Logger was unintentionally initialized at build time. To see why ch.qos.logback.classic.Logger got initialized use --trace-class-initialization=ch.qos.logback.classic.Logger
    [creator]     ch.qos.logback.core.util.StatusPrinter was unintentionally initialized at build time. To see why ch.qos.logback.core.util.StatusPrinter got initialized use --trace-class-initialization=ch.qos.logback.core.util.StatusPrinter
    [creator]     ch.qos.logback.core.util.StatusPrinter2 was unintentionally initialized at build time. To see why ch.qos.logback.core.util.StatusPrinter2 got initialized use --trace-class-initialization=ch.qos.logback.core.util.StatusPrinter2
    [creator]     org.slf4j.helpers.Reporter was unintentionally initialized at build time. To see why org.slf4j.helpers.Reporter got initialized use --trace-class-initialization=org.slf4j.helpers.Reporter
    [creator]     ch.qos.logback.core.status.InfoStatus was unintentionally initialized at build time. To see why ch.qos.logback.core.status.InfoStatus got initialized use --trace-class-initialization=ch.qos.logback.core.status.InfoStatus
    [creator]     ch.qos.logback.core.util.Loader was unintentionally initialized at build time. To see why ch.qos.logback.core.util.Loader got initialized use --trace-class-initialization=ch.qos.logback.core.util.Loader
    [creator]     ch.qos.logback.core.status.StatusBase was unintentionally initialized at build time. To see why ch.qos.logback.core.status.StatusBase got initialized use --trace-class-initialization=ch.qos.logback.core.status.StatusBase
    [creator]     org.slf4j.LoggerFactory was unintentionally initialized at build time. To see why org.slf4j.LoggerFactory got initialized use --trace-class-initialization=org.slf4j.LoggerFactory
    [creator]     ch.qos.logback.classic.Level was unintentionally initialized at build time. To see why ch.qos.logback.classic.Level got initialized use --trace-class-initialization=ch.qos.logback.classic.Level
    [creator]     To see how the classes got initialized, use --trace-class-initialization=ch.qos.logback.classic.Logger,ch.qos.logback.core.util.StatusPrinter,ch.qos.logback.core.util.StatusPrinter2,org.slf4j.helpers.Reporter,ch.qos.logback.core.status.InfoStatus,ch.qos.logback.core.util.Loader,ch.qos.logback.core.status.StatusBase,org.slf4j.LoggerFactory,ch.qos.logback.classic.Level
    [creator]     Error: Use -H:+ReportExceptionStackTraces to print stacktrace of underlying exception
    [creator]     --------------------------------------------------------------------------------
    [creator]         7.1s (14.6% of total time) in 87 GCs | Peak RSS: 1.96GB | CPU load: 3.65
    [creator]     ================================================================================
    [creator]     Finished generating 'org.springframework.grpc.sample.GrpcServerApplication' in 48.0s.
    [creator]     unable to invoke layer creator
    [creator]     unable to contribute native-image layer
    [creator]     error running build
    [creator]     exit status 1
    [creator]     ERROR: failed to build: exit status 1

> Task :bootBuildImage FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':bootBuildImage'.
> Builder lifecycle 'creator' failed with status code 51

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
> Get more help at https://help.gradle.org.

BUILD FAILED in 1m 26s
13 actionable tasks: 13 executed
```
Is it just me, or is it just that problem related to missing hints?

fix: #116 


Diff:
diff --git a/samples/grpc-server/HELP-gradle.md b/samples/grpc-server/HELP-gradle.md
new file mode 100644
index 00000000..224f1eb3
--- /dev/null
+++ b/samples/grpc-server/HELP-gradle.md
@@ -0,0 +1,71 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Gradle documentation](https://docs.gradle.org)
+* [Spring Boot Gradle Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.3/gradle-plugin)
+* [Create an OCI image](https://docs.spring.io/spring-boot/3.4.3/gradle-plugin/packaging-oci-image.html)
+* [GraalVM Native Image Support](https://docs.spring.io/spring-boot/3.4.3/reference/packaging/native-image/introducing-graalvm-native-images.html)
+* [Spring gRPC [Experimental]](https://docs.spring.io/spring-grpc/reference/index.html)
+
+### Additional Links
+These additional references should also help you:
+
+* [Gradle Build Scans – insights for your project's build](https://scans.gradle.com#gradle)
+* [Configure AOT settings in Build Plugin](https://docs.spring.io/spring-boot/3.4.3/how-to/aot.html)
+* [Various sample apps using Spring gRPC](https://github.com/spring-projects-experimental/spring-grpc/tree/main/samples)
+
+## GraalVM Native Support
+
+This project has been configured to let you generate either a lightweight container or a native executable.
+It is also possible to run your tests in a native image.
+
+### Lightweight Container with Cloud Native Buildpacks
+If you're already familiar with Spring Boot container images support, this is the easiest way to get started.
+Docker should be installed and configured on your machine prior to creating the image.
+
+To create the image, run the following goal:
+
+```
+$ ./gradlew bootBuildImage
+```
+
+Then, you can run the app like any other container:
+
+```
+$ docker run --rm grpc-server:0.5.0-SNAPSHOT
+```
+
+### Executable with Native Build Tools
+Use this option if you want to explore more options such as running your tests in a native image.
+The GraalVM `native-image` compiler should be installed and configured on your machine.
+
+NOTE: GraalVM 22.3+ is required.
+
+To create the executable, run the following goal:
+
+```
+$ ./gradlew nativeCompile
+```
+
+Then, you can run the app as follows:
+```
+$ build/native/nativeCompile/grpc-server
+```
+
+You can also run your existing tests suite in a native image.
+This is an efficient way to validate the compatibility of your application.
+
+To run your existing tests in a native image, run the following goal:
+
+```
+$ ./gradlew nativeTest
+```
+
+### Gradle Toolchain support
+
+There are some limitations regarding Native Build Tools and Gradle toolchains.
+Native Build Tools disable toolchain support by default.
+Effectively, native image compilation is done with the JDK used to execute Gradle.
+You can read more about [toolchain support in the Native Build Tools here](https://graalvm.github.io/native-build-tools/latest/gradle-plugin.html#configuration-toolchains).
diff --git a/samples/grpc-server/HELP-maven.md b/samples/grpc-server/HELP-maven.md
new file mode 100644
index 00000000..6bee4517
--- /dev/null
+++ b/samples/grpc-server/HELP-maven.md
@@ -0,0 +1,71 @@
+# Getting Started
+
+### Reference Documentation
+For further reference, please consider the following sections:
+
+* [Official Apache Maven documentation](https://maven.apache.org/guides/index.html)
+* [Spring Boot Maven Plugin Reference Guide](https://docs.spring.io/spring-boot/3.4.3/maven-plugin)
+* [Create an OCI image](https://docs.spring.io/spring-boot/3.4.3/maven-plugin/build-image.html)
+* [GraalVM Native Image Support](https://docs.spring.io/spring-boot/3.4.3/reference/packaging/native-image/introducing-graalvm-native-images.html)
+* [Spring gRPC [Experimental]](https://docs.spring.io/spring-grpc/reference/index.html)
+
+### Additional Links
+These additional references should also help you:
+
+* [Configure AOT settings in Build Plugin](https://docs.spring.io/spring-boot/3.4.3/how-to/aot.html)
+* [Various sample apps using Spring gRPC](https://github.com/spring-projects-experimental/spring-grpc/tree/main/samples)
+
+## GraalVM Native Support
+
+This project has been configured to let you generate either a lightweight container or a native executable.
+It is also possible to run your tests in a native image.
+
+### Lightweight Container with Cloud Native Buildpacks
+If you're already familiar with Spring Boot container images support, this is the easiest way to get started.
+Docker should be installed and configured on your machine prior to creating the image.
+
+To create the image, run the following goal:
+
+```
+$ ./mvnw spring-boot:build-image -Pnative
+```
+
+Then, you can run the app like any other container:
+
+```
+$ docker run --rm grpc-server-sample:0.5.0-SNAPSHOT
+```
+
+### Executable with Native Build Tools
+Use this option if you want to explore more options such as running your tests in a native image.
+The GraalVM `native-image` compiler should be installed and configured on your machine.
+
+NOTE: GraalVM 22.3+ is required.
+
+To create the executable, run the following goal:
+
+```
+$ ./mvnw native:compile -Pnative
+```
+
+Then, you can run the app as follows:
+```
+$ target/grpc-server-sample
+```
+
+You can also run your existing tests suite in a native image.
+This is an efficient way to validate the compatibility of your application.
+
+To run your existing tests in a native image, run the following goal:
+
+```
+$ ./mvnw test -PnativeTest
+```
+
+
+### Maven Parent overrides
+
+Due to Maven's design, elements are inherited from the parent POM to the project POM.
+While most of the inheritance is fine, it also inherits unwanted elements like `<license>` and `<developers>` from the parent.
+To prevent this, the project POM contains empty overrides for these elements.
+If you manually switch to a different parent and actually want the inheritance, you need to remove those overrides.
diff --git a/samples/grpc-server/README.md b/samples/grpc-server/README.md
index 975f0634..78548e78 100644
--- a/samples/grpc-server/README.md
+++ b/samples/grpc-server/README.md
@@ -12,7 +12,6 @@ $ ./mvnw spring-boot:run
   '  |____| .__|_| |_|_| |_\__, | / / / /
  =========|_|==============|___/=/_/_/_/
  :: Spring Boot ::                (v3.0.0)
-
 2022-12-08T05:32:24.934-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 17.0.5 with PID 551632 (/home/dsyer/dev/scratch/demo/target/classes started by dsyer in /home/dsyer/dev/scratch/demo)
 2022-12-08T05:32:24.938-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
 2022-12-08T05:32:25.377-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcHealthServiceAutoConfiguration
@@ -36,26 +35,6 @@ $ grpcurl -d '{"name":"Hi"}' -plaintext localhost:9090 Simple.SayHello
 ```
 
 ## Native Image
+[Native Image with Gradle](./HELP-gradle.md)
 
-The app compiles to a native image if the JVM is GraalVM:
-
-```
-$ ./mvnw -Pnative native:compile
-$ ./target/demo
-  .   ____          _            __ _ _
- /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
-( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
-  '  |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot ::                (v3.0.0)
-
-2022-12-08T05:36:54.365-08:00  INFO 554359 --- [           main] com.example.demo.DemoApplication         : Starting AOT-processed DemoApplication using Java 17.0.5 with PID 554359 (/home/dsyer/dev/scratch/demo/target/demo started by dsyer in /home/dsyer/dev/scratch/demo)
-2022-12-08T05:36:54.366-08:00  INFO 554359 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
-2022-12-08T05:36:54.377-08:00  INFO 554359 --- [           main] g.s.a.GrpcServerFactoryAutoConfiguration : Detected grpc-netty: Creating NettyGrpcServerFactory
-2022-12-08T05:36:54.392-08:00  INFO 554359 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: Simple, bean: grpcServerService, class: com.example.demo.GrpcServerService
-2022-12-08T05:36:54.392-08:00  INFO 554359 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.health.v1.Health, bean: grpcHealthService, class: io.grpc.protobuf.services.HealthServiceImpl
-2022-12-08T05:36:54.392-08:00  INFO 554359 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.reflection.v1alpha.ServerReflection, bean: protoReflectionService, class: io.grpc.protobuf.services.ProtoReflectionService
-2022-12-08T05:36:54.396-08:00  INFO 554359 --- [           main] n.d.b.g.s.s.GrpcServerLifecycle          : gRPC Server started, listening on address: *, port: 9090
-2022-12-08T05:36:54.396-08:00  INFO 554359 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.046 seconds (process running for 0.052)
-```
+[Native Image with Maven](./HELP-maven.md)
\ No newline at end of file


Reviews:
user: login: onobc
body: Great first pass at this @panic08 !

A have left some specific comments inline. Other than that, here are some general thoughts:

So we can build native images using [Buildpacks](https://docs.spring.io/spring-boot/how-to/native-image/developing-your-first-application.html#howto.native-image.developing-your-first-application.buildpacks) or w/ [GraalVM native build tools](https://docs.spring.io/spring-boot/how-to/native-image/developing-your-first-application.html#howto.native-image.developing-your-first-application.native-build-tools).

I think we should support and talk about both.

## Buildpacks
With buildpacks we build w/ one of these:
```
mvn -Pnative spring-boot:build-image
```
OR
```
gradle bootBuildImage
```
Then run in Docker like:
```
docker run --rm -p 8080:8080 docker.io/library/myproject:0.0.1-SNAPSHOT
```

## Native Build Tools

Requirement here is that we have GraalVM installed on the machine. I use skdman locally and do something like:
```
$ sdk install java 22.3.r17-nik
$ sdk use java 22.3.r17-nik
```
I am not sure how we go about handling this in an automated fashion though. I believe we can leverage `org.junit.jupiter.api.condition.EnabledInNativeImage` to guard the tests in this case. 

> [!NOTE]
> Let's not worry about the scaffolding or executing it w/ native tools but let's make sure that the steps we end up w/ in the README/help are valid and we can do this locally.

After that the steps to build the native executable are..
```
mvn -Pnative native:compile
```
OR
```
gradle nativeCompile
```
And to run
```
target/grpc-server-aot
```
OR 
```
build/native/nativeCompile/grpc-server-aot
```

Wdyt?

state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T21:52:45Z
user: login: onobc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T21:57:21Z
user: login: onobc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T21:58:38Z
user: login: onobc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T21:59:10Z
user: login: onobc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-02T22:01:11Z
user: login: dsyer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-03T09:30:02Z
user: login: therepanic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T10:27:58Z
user: login: dsyer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-03T10:51:10Z
user: login: therepanic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T11:34:50Z
user: login: dsyer
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-03T11:39:22Z
user: login: therepanic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-03T11:45:46Z
user: login: onobc
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T22:02:10Z
user: login: onobc
body: Awesome job @panic08 ! 
I have a minor ask on the README, but other than that this looks great.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-06T22:02:29Z
user: login: therepanic
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-07T17:56:32Z
user: login: onobc
body: Looks good @panic08 ! Thanks for another great contribution.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-10T17:26:22Z

Review comments:
diff_hunk: @@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>3.4.3</version>
+		<relativePath /> <!-- lookup parent from repository -->
+	</parent>
+	<groupId>org.springframework.grpc</groupId>
+	<artifactId>grpc-server-aot-sample</artifactId>
+	<version>0.4.0-SNAPSHOT</version>
+	<name>Spring gRPC Server Sample</name>
+	<description>Demo project for Spring gRPC</description>
+	<url />
+	<licenses>
+		<license />
+	</licenses>
+	<developers>
+		<developer />
+	</developers>
+	<scm>
+		<connection />
+		<developerConnection />
+		<tag />
+		<url />
+	</scm>
+	<properties>
+		<java.version>17</java.version>
+		<spring-javaformat-maven-plugin.version>0.0.39</spring-javaformat-maven-plugin.version>
+		<protobuf-java.version>3.25.5</protobuf-java.version>
+		<grpc.version>1.69.0</grpc.version>
+	</properties>
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework.grpc</groupId>
+				<artifactId>spring-grpc-dependencies</artifactId>
+				<version>0.4.0-SNAPSHOT</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.grpc</groupId>
+			<artifactId>spring-grpc-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>io.grpc</groupId>
+			<artifactId>grpc-services</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-actuator</artifactId>
+		</dependency>
+
+		<dependency>
path: samples/grpc-server-aot/pom.xml
user: login: onobc
body: I don't think we need this in this sample.
created_at: 2025-03-02T21:26:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>3.4.3</version>
+		<relativePath /> <!-- lookup parent from repository -->
+	</parent>
+	<groupId>org.springframework.grpc</groupId>
+	<artifactId>grpc-server-aot-sample</artifactId>
+	<version>0.4.0-SNAPSHOT</version>
+	<name>Spring gRPC Server Sample</name>
+	<description>Demo project for Spring gRPC</description>
+	<url />
+	<licenses>
+		<license />
+	</licenses>
+	<developers>
+		<developer />
+	</developers>
+	<scm>
+		<connection />
+		<developerConnection />
+		<tag />
+		<url />
+	</scm>
+	<properties>
+		<java.version>17</java.version>
+		<spring-javaformat-maven-plugin.version>0.0.39</spring-javaformat-maven-plugin.version>
+		<protobuf-java.version>3.25.5</protobuf-java.version>
+		<grpc.version>1.69.0</grpc.version>
+	</properties>
+	<dependencyManagement>
+		<dependencies>
+			<dependency>
+				<groupId>org.springframework.grpc</groupId>
+				<artifactId>spring-grpc-dependencies</artifactId>
+				<version>0.4.0-SNAPSHOT</version>
+				<type>pom</type>
+				<scope>import</scope>
+			</dependency>
+		</dependencies>
+	</dependencyManagement>
+	<dependencies>
+		<dependency>
+			<groupId>org.springframework.grpc</groupId>
+			<artifactId>spring-grpc-spring-boot-starter</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>io.grpc</groupId>
+			<artifactId>grpc-services</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-actuator</artifactId>
+		</dependency>
+
+		<dependency>
+			<!-- for testing unix domain sockets -->
+			<groupId>io.netty</groupId>
+			<artifactId>netty-transport-native-epoll</artifactId>
+			<classifier>linux-x86_64</classifier>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.grpc</groupId>
+			<artifactId>spring-grpc-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
+
+	<build>
+		<extensions>
+			<extension>
+				<groupId>kr.motd.maven</groupId>
+				<artifactId>os-maven-plugin</artifactId>
+				<version>1.7.1</version>
+			</extension>
+		</extensions>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-deploy-plugin</artifactId>
+				<configuration>
+					<skip>true</skip>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>io.spring.javaformat</groupId>
+				<artifactId>spring-javaformat-maven-plugin</artifactId>
+				<version>${spring-javaformat-maven-plugin.version}</version>
+				<executions>
+					<execution>
+						<?m2e ignore?>
+						<phase>validate</phase>
+						<inherited>true</inherited>
+						<goals>
+							<goal>validate</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.xolstice.maven.plugins</groupId>
+				<artifactId>protobuf-maven-plugin</artifactId>
+				<version>0.6.1</version>
+				<configuration>
+					<protocArtifact>
+						com.google.protobuf:protoc:${protobuf-java.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>
+				<executions>
+					<execution>
+						<configuration>
+							<pluginParameter>
+								jakarta_omit,@generated=omit
+							</pluginParameter>
+						</configuration>
+						<goals>
+							<goal>compile</goal>
+							<goal>compile-custom</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+
+	<profiles>
path: samples/grpc-server-aot/pom.xml
user: login: onobc
body: 
Because we use the `spring-boot-starter-parent` it defines a `native` profile that prevents us from having to muck w/ the `process-aot` executions and simply use:

```xml
<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
    <groupId>org.graalvm.buildtools</groupId>
    <artifactId>native-maven-plugin</artifactId>
</plugin>
```
Details [here](https://docs.spring.io/spring-boot/how-to/native-image/developing-your-first-application.html).

The custom profile may be helpful in other apps that want to have some aot components and some not. I think we just keep it simple in the sample.

> [!TIP]
> Also, to see what the minimal things we need in a pom.xml or build.gradle start w/ a sample from start.spring.io and choose "maven | gradle" + "grpc" + "native".
created_at: 2025-03-02T21:30:33Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,175 @@
+/*
+ * Copyright 2024-2024 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.springframework.grpc.sample;
path: samples/grpc-server-aot/src/test/java/org/springframework/grpc/sample/GrpcServerHealthIntegrationTests.java
user: login: onobc
body: Let's drop this IT as this is verified in the other sample app.
created_at: 2025-03-02T21:31:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,347 @@
+/*
+ * Copyright 2024-2024 the original author or authors.
+ *
+ * Licensed 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
+ *
+ *      https://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.springframework.grpc.sample;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.context.TestConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.grpc.autoconfigure.server.GrpcServerProperties;
+import org.springframework.grpc.client.ChannelBuilderOptions;
+import org.springframework.grpc.client.GrpcChannelFactory;
+import org.springframework.grpc.sample.proto.HelloReply;
+import org.springframework.grpc.sample.proto.HelloRequest;
+import org.springframework.grpc.sample.proto.SimpleGrpc;
+import org.springframework.grpc.server.GlobalServerInterceptor;
+import org.springframework.grpc.server.GrpcServerFactory;
+import org.springframework.grpc.test.AutoConfigureInProcessTransport;
+import org.springframework.grpc.test.LocalGrpcPort;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.context.ActiveProfiles;
+
+import io.grpc.ForwardingServerCallListener;
+import io.grpc.ManagedChannel;
+import io.grpc.ServerCall.Listener;
+import io.grpc.ServerInterceptor;
+import io.grpc.Status.Code;
+import io.grpc.StatusRuntimeException;
+import io.grpc.netty.NettyChannelBuilder;
+
+/**
+ * More detailed integration tests for {@link GrpcServerFactory gRPC server factories} and
+ * various {@link GrpcServerProperties}.
+ */
+class GrpcServerIntegrationTests {
path: samples/grpc-server-aot/src/test/java/org/springframework/grpc/sample/GrpcServerIntegrationTests.java
user: login: onobc
body: Let's drop this IT as this is verified in the other sample app.
created_at: 2025-03-02T21:31:55Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,5 @@
+spring.grpc.server.ssl.bundle=ssltest
path: samples/grpc-server-aot/src/test/resources/application-ssl.properties
user: login: onobc
body: I don't think we need either of these ssl related files either if we drop the other redundant ITs
created_at: 2025-03-02T21:32:34Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1 @@
+spring.application.name=grpc-server
path: samples/grpc-server-aot/src/main/resources/application.properties
user: login: onobc
body: `s/grpc-server/grpc-server-aot`
created_at: 2025-03-02T21:33:01Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: onobc
body: @dsyer when I remove this file I am able to run w/ native successfully on Mac M. It breaks for me otherwise if this is left in place.
created_at: 2025-03-02T21:33:57Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,252 @@
+#!/bin/sh
path: samples/grpc-server-aot/gradlew
user: login: onobc
body: I would create a sample w/ "gradle" + "grpc" + "native" in start.spring.io and use whatever ".gradle + wrapper" pieces it generates (I believe ours is a bit outdated currently).


created_at: 2025-03-02T21:35:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,82 @@
+# Spring Boot gRPC Sample
path: samples/grpc-server-aot/README.md
user: login: onobc
body: This README will of course need to change, but before we worry about that I would suggest doing the following:

1. create a sample w/ "gradle" + "grpc" + "native" in start.spring.io and copy its generated HELP.md and paste it here w/ name `HELP-gradle.md`

2. create a sample w/ "gradle" + "grpc" + "native" in start.spring.io and copy its generated HELP.md and paste it here w/ name `HELP-maven.md`

Then we can synthesize them together and give excellent instructions how to run w/ either / or as they differ between run mechanics a bit.

created_at: 2025-03-02T21:38:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+plugins {
+    id 'java'
+    id 'org.springframework.boot' version '3.4.3'
+    id 'io.spring.dependency-management' version '1.1.6'
+    id 'org.springframework.boot.aot' version '3.4.3'
path: samples/grpc-server-aot/build.gradle
user: login: onobc
body: We should use the `id 'org.graalvm.buildtools.native' version '0.10.5'` plugin instead which covers both AOT and Native use.
created_at: 2025-03-02T21:57:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+plugins {
+    id 'java'
+    id 'org.springframework.boot' version '3.4.3'
+    id 'io.spring.dependency-management' version '1.1.6'
+    id 'org.springframework.boot.aot' version '3.4.3'
+    id 'com.google.protobuf' version '0.9.4'
+}
+
+group = 'com.example'
+version = '0.4.0-SNAPSHOT'
+
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+repositories {
+    mavenLocal()
path: samples/grpc-server-aot/build.gradle
user: login: onobc
body: I think this is holdover from the other sample apps but we should not need it.
created_at: 2025-03-02T21:58:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+plugins {
+    id 'java'
+    id 'org.springframework.boot' version '3.4.3'
+    id 'io.spring.dependency-management' version '1.1.6'
+    id 'org.springframework.boot.aot' version '3.4.3'
+    id 'com.google.protobuf' version '0.9.4'
+}
+
+group = 'com.example'
+version = '0.4.0-SNAPSHOT'
+
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+repositories {
+    mavenLocal()
+    mavenCentral()
+    maven { url 'https://repo.spring.io/milestone' }
+    maven { url 'https://repo.spring.io/snapshot' }
+}
+
+dependencyManagement {
+    imports {
+        mavenBom 'org.springframework.grpc:spring-grpc-dependencies:0.4.0-SNAPSHOT'
+    }
+}
+
+dependencies {
+    implementation 'org.springframework.grpc:spring-grpc-spring-boot-starter'
+    implementation 'io.grpc:grpc-services'
+    testImplementation 'org.springframework.boot:spring-boot-starter-test'
+    testImplementation 'org.springframework.grpc:spring-grpc-test'
+    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+    testRuntimeOnly "io.netty:netty-transport-native-epoll::linux-x86_64"
path: samples/grpc-server-aot/build.gradle
user: login: onobc
body: Ditto https://github.com/spring-projects-experimental/spring-grpc/pull/120/files#r1976721791
created_at: 2025-03-02T21:59:09Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,67 @@
+plugins {
+    id 'java'
+    id 'org.springframework.boot' version '3.4.3'
+    id 'io.spring.dependency-management' version '1.1.6'
+    id 'org.springframework.boot.aot' version '3.4.3'
+    id 'com.google.protobuf' version '0.9.4'
+}
+
+group = 'com.example'
+version = '0.4.0-SNAPSHOT'
+
+java {
+    toolchain {
+        languageVersion = JavaLanguageVersion.of(17)
+    }
+}
+
+repositories {
+    mavenLocal()
+    mavenCentral()
+    maven { url 'https://repo.spring.io/milestone' }
+    maven { url 'https://repo.spring.io/snapshot' }
+}
+
+dependencyManagement {
+    imports {
+        mavenBom 'org.springframework.grpc:spring-grpc-dependencies:0.4.0-SNAPSHOT'
+    }
+}
+
+dependencies {
+    implementation 'org.springframework.grpc:spring-grpc-spring-boot-starter'
+    implementation 'io.grpc:grpc-services'
+    testImplementation 'org.springframework.boot:spring-boot-starter-test'
+    testImplementation 'org.springframework.grpc:spring-grpc-test'
+    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
+    testRuntimeOnly "io.netty:netty-transport-native-epoll::linux-x86_64"
+}
+
+tasks.named("bootBuildImage") {
+    environment["BPE_DELIM_JAVA_TOOL_OPTIONS"] = " "
+    environment["BPE_APPEND_JAVA_TOOL_OPTIONS"] = "-Dspring.aot.enabled=true"
+    environment["BP_NATIVE_IMAGE"] = "true"
+}
path: samples/grpc-server-aot/build.gradle
user: login: onobc
body: Similar to the reasoning from [here](https://github.com/spring-projects-experimental/spring-grpc/pull/120/files#r1976722464) I don't think we should have to do this if we use the native build plugin.
created_at: 2025-03-02T22:01:11Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: dsyer
body: Darn it. Let's just remove it from all the samples t hen. I thought it was harmless.
created_at: 2025-03-03T09:30:02Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: therepanic
body: I'll remove it later.
created_at: 2025-03-03T10:27:58Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: dsyer
body: Just rebase to main. That should be enough.
created_at: 2025-03-03T10:51:10Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: therepanic
body: Perhaps this should be included in a separate PR? Still, these changes in all samples do not apply to the current ones, what do you think?
created_at: 2025-03-03T11:34:50Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: dsyer
body: Did you rebase?
created_at: 2025-03-03T11:39:22Z
author_association: MEMBER
diff_hunk: @@ -0,0 +1,2 @@
+# Ignored unless building in Nix (https://github.com/oracle/graal/issues/8639)
+Args = -ENIX_LDFLAGS -ENIX_CC_WRAPPER_TARGET_HOST_x86_64_unknown_linux_gnu
path: samples/grpc-server-aot/src/main/resources/META-INF/native-image/org.springframework.samples/grpc-server-sample/native-image.properties
user: login: therepanic
body: Sorry, I didn't notice that you already made a commit where you removed native.image.properties. I meant for me to make a PR to remove it, but you already did it yourself, so it's ok.
created_at: 2025-03-03T11:45:46Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,61 +0,0 @@
-# Spring Boot gRPC Sample
-
-This project is a copy one of the samples from the [gRPC Spring Boot Starter](https://github.com/yidongnan/grpc-spring-boot-starter/blob/master/examples/local-grpc-server/build.gradle). Build and run any way you like to run Spring Boot. E.g:
-
-```
-$ ./mvnw spring-boot:run
-...
-  .   ____          _            __ _ _
- /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
-( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
-  '  |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot ::                (v3.0.0)
-
-2022-12-08T05:32:24.934-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 17.0.5 with PID 551632 (/home/dsyer/dev/scratch/demo/target/classes started by dsyer in /home/dsyer/dev/scratch/demo)
-2022-12-08T05:32:24.938-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
-2022-12-08T05:32:25.377-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcHealthServiceAutoConfiguration
-2022-12-08T05:32:25.416-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration
-2022-12-08T05:32:25.425-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration
-2022-12-08T05:32:25.427-08:00  INFO 551632 --- [           main] g.s.a.GrpcServerFactoryAutoConfiguration : Detected grpc-netty: Creating NettyGrpcServerFactory
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: Simple, bean: grpcServerService, class: com.example.demo.GrpcServerService
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.health.v1.Health, bean: grpcHealthService, class: io.grpc.protobuf.services.HealthServiceImpl
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.reflection.v1alpha.ServerReflection, bean: protoReflectionService, class: io.grpc.protobuf.services.ProtoReflectionService
-2022-12-08T05:32:25.820-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.GrpcServerLifecycle          : gRPC Server started, listening on address: *, port: 9090
-2022-12-08T05:32:25.831-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.264 seconds (process running for 1.623)
-```
-
-The server starts by default on port 9090. Test with [gRPCurl](https://github.com/fullstorydev/grpcurl):
-
-```
-$ grpcurl -d '{"name":"Hi"}' -plaintext localhost:9090 Simple.SayHello
-{
-  "message": "Hello ==\u003e Hi"
-}
-```
-
-## Native Image
path: samples/grpc-server/README.md
user: login: onobc
body: I think it would be good to keep the README.md but w/ everything above this comment and then replace everything below w/ links to the HELP-<build>.md. Wdyt?
created_at: 2025-03-06T22:02:10Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,61 +0,0 @@
-# Spring Boot gRPC Sample
-
-This project is a copy one of the samples from the [gRPC Spring Boot Starter](https://github.com/yidongnan/grpc-spring-boot-starter/blob/master/examples/local-grpc-server/build.gradle). Build and run any way you like to run Spring Boot. E.g:
-
-```
-$ ./mvnw spring-boot:run
-...
-  .   ____          _            __ _ _
- /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
-( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
-  '  |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot ::                (v3.0.0)
-
-2022-12-08T05:32:24.934-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication using Java 17.0.5 with PID 551632 (/home/dsyer/dev/scratch/demo/target/classes started by dsyer in /home/dsyer/dev/scratch/demo)
-2022-12-08T05:32:24.938-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to 1 default profile: "default"
-2022-12-08T05:32:25.377-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcHealthServiceAutoConfiguration
-2022-12-08T05:32:25.416-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration
-2022-12-08T05:32:25.425-08:00  WARN 551632 --- [           main] ocalVariableTableParameterNameDiscoverer : Using deprecated '-debug' fallback for parameter name resolution. Compile the affected code with '-parameters' instead or avoid its introspection: net.devh.boot.grpc.server.autoconfigure.GrpcServerFactoryAutoConfiguration
-2022-12-08T05:32:25.427-08:00  INFO 551632 --- [           main] g.s.a.GrpcServerFactoryAutoConfiguration : Detected grpc-netty: Creating NettyGrpcServerFactory
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: Simple, bean: grpcServerService, class: com.example.demo.GrpcServerService
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.health.v1.Health, bean: grpcHealthService, class: io.grpc.protobuf.services.HealthServiceImpl
-2022-12-08T05:32:25.712-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.AbstractGrpcServerFactory    : Registered gRPC service: grpc.reflection.v1alpha.ServerReflection, bean: protoReflectionService, class: io.grpc.protobuf.services.ProtoReflectionService
-2022-12-08T05:32:25.820-08:00  INFO 551632 --- [           main] n.d.b.g.s.s.GrpcServerLifecycle          : gRPC Server started, listening on address: *, port: 9090
-2022-12-08T05:32:25.831-08:00  INFO 551632 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 1.264 seconds (process running for 1.623)
-```
-
-The server starts by default on port 9090. Test with [gRPCurl](https://github.com/fullstorydev/grpcurl):
-
-```
-$ grpcurl -d '{"name":"Hi"}' -plaintext localhost:9090 Simple.SayHello
-{
-  "message": "Hello ==\u003e Hi"
-}
-```
-
-## Native Image
path: samples/grpc-server/README.md
user: login: therepanic
body: I think it's a good idea
created_at: 2025-03-07T17:56:32Z
author_association: CONTRIBUTOR

PR comments:
user: login: therepanic
created_at: 2025-02-28T21:55:20Z
body: Also, if this is what we need, should we now, as I did, write that the build will not succeed until the missing hints problem is fixed?
author_association: CONTRIBUTOR
user: login: therepanic
created_at: 2025-03-04T21:14:09Z
body: Thank you so much for the review @onobc

I've fixed the unnecessary things you pointed out and brought the module as close as possible to what is generated in start.spring.io

> Wdyt?

I actually added the `org.springframework.boot.aot` plugin initially for a reason. It was with it that my build crashed, and I originally thought that it should crash, and that with `org.graalvm.buildtools.native` Spring AOT is not activated.

If we run a native build with the `org.graalvm.buildtools.native` plugin and use **Native Build Tools** or **Buildpacks**, we will somehow successfully build the project and be able to run it without crashing.

However, we will see some warnings in the logs. Here are the warnings that appear if I start building natively with `./gradlew nativeCompile`:
```
Warning: Could not resolve class com.github.luben.zstd.ZstdCompressCtx for reflection configuration. Reason: java.lang.ClassNotFoundException: com.github.luben.zstd.ZstdCompressCtx.
Warning: Could not resolve class io.netty.handler.ssl.OpenSslClientSessionCache for reflection configuration. Reason: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/SSLSessionCache.
Warning: Could not resolve class io.netty.handler.ssl.ReferenceCountedOpenSslClientContext$ExtendedTrustManagerVerifyCallback for reflection configuration. Reason: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/CertificateVerifier.
Warning: Could not resolve class io.netty.handler.ssl.ReferenceCountedOpenSslServerContext$ExtendedTrustManagerVerifyCallback for reflection configuration. Reason: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/CertificateVerifier.
Warning: Could not resolve class io.netty.handler.ssl.ReferenceCountedOpenSslServerContext$OpenSslServerCertificateCallback for reflection configuration. Reason: java.lang.NoClassDefFoundError: io/netty/internal/tcnative/CertificateCallback.
Warning: Could not resolve class org.conscrypt.ConscryptEngine for reflection configuration. Reason: java.lang.ClassNotFoundException: org.conscrypt.ConscryptEngine.
Warning: Could not resolve class org.conscrypt.ConscryptEngine for reflection configuration. Reason: java.lang.ClassNotFoundException: org.conscrypt.ConscryptEngine.
Warning: Could not resolve class org.conscrypt.ConscryptEngine for reflection configuration. Reason: java.lang.ClassNotFoundException: org.conscrypt.ConscryptEngine.
Warning: Could not resolve class io.netty.resolver.dns.macos.DnsResolver for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.resolver.dns.macos.DnsResolver.
Warning: Could not resolve class io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.resolver.dns.macos.MacOSDnsServerAddressStreamProvider.
Warning: Could not resolve class io.netty.channel.kqueue.BsdSocket for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.channel.kqueue.BsdSocket.
Warning: Could not resolve class io.netty.channel.kqueue.KQueueEventArray for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.channel.kqueue.KQueueEventArray.
Warning: Could not resolve class io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.channel.kqueue.KQueueStaticallyReferencedJniMethods.
Warning: Could not resolve class io.netty.channel.kqueue.Native for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.channel.kqueue.Native.
Warning: Method ch.qos.logback.core.encoder.LayoutWrappingEncoder.setParent(Appender) not found.
Warning: Could not resolve class com.aayushatharva.brotli4j.Brotli4jLoader for reflection configuration. Reason: java.lang.ClassNotFoundException: com.aayushatharva.brotli4j.Brotli4jLoader.
Warning: Could not resolve class com.github.luben.zstd.Zstd for reflection configuration. Reason: java.lang.ClassNotFoundException: com.github.luben.zstd.Zstd.
Warning: Could not resolve class com.ning.compress.lzf.impl.UnsafeChunkDecoder for reflection configuration. Reason: java.lang.ClassNotFoundException: com.ning.compress.lzf.impl.UnsafeChunkDecoder.

Warning: Could not resolve class io.netty.channel.epoll.EpollSocketChannel for reflection configuration. Reason: java.lang.ClassNotFoundException: io.netty.channel.epoll.EpollSocketChannel.
Warning: Method java.nio.DirectByteBuffer.<init>(long, long) not found.
Warning: Method java.nio.DirectByteBuffer.<init>(long, long) not found.
Warning: Could not resolve class org.apache.commons.logging.impl.Log4JLogger for reflection configuration. Reason: java.lang.ClassNotFoundException: org.apache.commons.logging.impl.Log4JLogger.
Warning: Could not resolve class org.apache.commons.logging.impl.LogFactoryImpl for reflection configuration. Reason: java.lang.ClassNotFoundException: org.apache.commons.logging.impl.LogFactoryImpl.
Warning: Could not resolve class org.apache.commons.logging.impl.WeakHashtable for reflection configuration. Reason: java.lang.ClassNotFoundException: org.apache.commons.logging.impl.WeakHashtable.
Warning: Could not resolve class org.apache.log4j.Level for reflection configuration. Reason: java.lang.ClassNotFoundException: org.apache.log4j.Level.
Warning: Could not resolve class org.apache.log4j.Priority for reflection configuration. Reason: java.lang.ClassNotFoundException: org.apache.log4j.Priority.
Warning: Could not resolve class org.conscrypt.Conscrypt for reflection configuration. Reason: java.lang.ClassNotFoundException: org.conscrypt.Conscrypt.
Warning: Could not resolve class org.conscrypt.OpenSSLContextImpl$TLSv13 for reflection configuration. Reason: java.lang.ClassNotFoundException: org.conscrypt.OpenSSLContextImpl$TLSv13.
Warning: Could not resolve class org.hamcrest.number.OrderingComparison for reflection configuration. Reason: java.lang.ClassNotFoundException: org.hamcrest.number.OrderingComparison.
Warning: Method ch.qos.logback.core.FileAppender.valueOf(String) not found.
Warning: Method ch.qos.logback.core.Layout.valueOf(String) not found.
Warning: Method ch.qos.logback.core.rolling.RollingPolicy.valueOf(String) not found.
Warning: Method ch.qos.logback.core.rolling.TriggeringPolicy.valueOf(String) not found.
Warning: Method ch.qos.logback.core.spi.ContextAware.valueOf(String) not found.
Warning: Could not resolve class jakarta.inject.Inject for reflection configuration. Reason: java.lang.ClassNotFoundException: jakarta.inject.Inject.
Warning: Could not resolve class jakarta.inject.Provider for reflection configuration. Reason: java.lang.ClassNotFoundException: jakarta.inject.Provider.
Warning: Could not resolve class jakarta.inject.Qualifier for reflection configuration. Reason: java.lang.ClassNotFoundException: jakarta.inject.Qualifier.
Warning: Could not resolve class javax.inject.Inject for reflection configuration. Reason: java.lang.ClassNotFoundException: javax.inject.Inject.
Warning: Could not resolve class javax.inject.Qualifier for reflection configuration. Reason: java.lang.ClassNotFoundException: javax.inject.Qualifier.
Warning: Could not resolve class javax.money.MonetaryAmount for reflection configuration. Reason: java.lang.ClassNotFoundException: javax.money.MonetaryAmount.
Warning: Could not resolve class kotlin.Metadata for reflection configuration. Reason: java.lang.ClassNotFoundException: kotlin.Metadata.
Warning: Could not resolve class kotlin.reflect.full.KClasses for reflection configuration. Reason: java.lang.ClassNotFoundException: kotlin.reflect.full.KClasses.
Warning: Could not resolve class org.eclipse.core.runtime.FileLocator for reflection configuration. Reason: java.lang.ClassNotFoundException: org.eclipse.core.runtime.FileLocator.
Warning: Could not resolve class org.reactivestreams.Publisher for reflection configuration. Reason: java.lang.ClassNotFoundException: org.reactivestreams.Publisher.
[1/8] Initializing...
                                                         
...
```
If we build with **Build Packs**, everything will also start and run fine, these warnings will still appear during the build phase
author_association: CONTRIBUTOR
user: login: dsyer
created_at: 2025-03-05T10:25:50Z
body: Do we really need a completely new sample? Wouldn't the existing grpc-server sample be minimal enough, and it already has the native plugin configured in Maven?
author_association: MEMBER
user: login: therepanic
created_at: 2025-03-05T12:53:13Z
body: > Do we really need a completely new sample? Wouldn't the existing grpc-server sample be minimal enough, and it already has the native plugin configured in Maven?

We take the new module as an it and its domain is exactly testing this functionality, as I think the new module will be not bad for this, what do you think?
author_association: CONTRIBUTOR
user: login: dsyer
created_at: 2025-03-05T13:02:13Z
body: I don't know what you mean. The old module is just fine IMO (it even works OOTB in Maven - for Gradle I had to add some settings).
author_association: MEMBER
user: login: therepanic
created_at: 2025-03-05T14:13:18Z
body: > I don't know what you mean. The old module is just fine IMO (it even works OOTB in Maven - for Gradle I had to add some settings).

I mean that this kind of integration test in my opinion is better to see in a separate module. I understand @onobc is of the same [opinion](https://github.com/spring-projects-experimental/spring-grpc/issues/116#issuecomment-2686403833)
author_association: CONTRIBUTOR
user: login: onobc
created_at: 2025-03-05T14:17:17Z
body: > I don't know what you mean. The old module is just fine IMO (it even works OOTB in Maven - for Gradle I had to add some settings).

My reasoning on creating a single module is:

1. separation of concerns - have one sample that does AOT/native and does it well and gives excellent docs on how to do so in Gradle vs. Maven
2. reduce maintenance toil - by not having AOT/native aspects spread across each sample it will likely reduce the maintenance footprint for the samples

I would propose (if we go forward w/ single AOT/native sample) that we remove the AOT/native mentions/configs from the other samples.

That being said, my goal is more to have AOT/native in a single sample; whether it be in the existing grpc-server sample or a new one. 
author_association: CONTRIBUTOR
user: login: dsyer
created_at: 2025-03-05T14:18:00Z
body: I don't really see how this separate module is better than the one we already have (the `grpc-server`). IMO it would be more interesting to concentrate on some github action declarations that we can use to verify that native images are working.
author_association: MEMBER
user: login: onobc
created_at: 2025-03-05T14:20:59Z
body: > I don't really see how this separate module is better than the one we already have (the `grpc-server`). IMO it would be more interesting to concentrate on some github action declarations that we can use to verify that native images are working.

I updated my previous comment w/ the goal of just having the native/AOT in a single place (rather than its own module). Is that a good compromise?
author_association: CONTRIBUTOR
user: login: onobc
created_at: 2025-03-05T17:21:50Z
body: We discussed this during our team meeting today and have agreed to put this AOT/native into the existing `grpc-server` sample. Sorry for the back and forth @panic08 . 

Do you mind targeting the relevant changes to the `grpc-server` sample instead?
author_association: CONTRIBUTOR
user: login: therepanic
created_at: 2025-03-06T07:23:11Z
body: > We discussed this during our team meeting today and have agreed to put this AOT/native into the existing `grpc-server` sample. Sorry for the back and forth @panic08 . 
> 
> 
> 
> Do you mind targeting the relevant changes to the `grpc-server` sample instead?

I guess we decided not to make a separate module after all, but to have just grpc-server. Then I guess as it sounds, of the changes that will be moved to grpc-server, it's only HELP-gradle.md, HELP-maven.md.

Anyway, after I move to grpc-server, I guess the build results will be the same as here https://github.com/spring-projects-experimental/spring-grpc/pull/120#issuecomment-2698922961. So the build is still successful? Now it is worth to add I guess workflow as dsyer said, which confirms that the build is successful?
author_association: CONTRIBUTOR
user: login: dsyer
created_at: 2025-03-06T08:41:29Z
body: Did you test the native image build (maven and gradle)? It didn't work for me in Gradle.
author_association: MEMBER
user: login: therepanic
created_at: 2025-03-06T09:20:50Z
body: > Did you test the native image build (maven and gradle)? It didn't work for me in Gradle.

In my current module native build via gradle works, I've discounted the log above. I'll try to see what's wrong with the ```grpc-server``` build
author_association: CONTRIBUTOR
user: login: onobc
created_at: 2025-03-06T14:32:58Z
body: > Now it is worth to add I guess workflow as dsyer said, which confirms that the build is successful?

We want to hold off on the workflows for a bit as there are some that we may be able leverage from other Spring projects.
author_association: CONTRIBUTOR
user: login: therepanic
created_at: 2025-03-06T21:00:33Z
body: > > Did you test the native image build (maven and gradle)? It didn't work for me in Gradle.
> 
> In my current module native build via gradle works, I've discounted the log above. I'll try to see what's wrong with the `grpc-server` build

I have native image builds working successfully with both **Build Packs** and **Native Build Tools** (gradle and maven respectively). I run all this on Ubuntu 22.04, also using sdkman with dependency: `17.0.9-graalce`

author_association: CONTRIBUTOR
user: login: therepanic
created_at: 2025-03-07T17:56:20Z
body: By the way, what do you think about adding HELP-.md to each sample?

Since we gave up a separate module with aot + native image, I think it would be worth supporting native images for each sample then. And right now we have such support (added `org.graalvm.buildtools.native` plugin to each sample and everything works well).

Then I think we should add HELP-.md to each sample?
author_association: CONTRIBUTOR
user: login: onobc
created_at: 2025-03-07T19:25:54Z
body: > By the way, what do you think about adding HELP-.md to each sample?
> 
> Since we gave up a separate module with aot + native image, I think it would be worth supporting native images for each sample then. And right now we have such support (added `org.graalvm.buildtools.native` plugin to each sample and everything works well).
> 
> Then I think we should add HELP-.md to each sample?

I'm actually in favor of removing native from all other samples as it can become a maintenance headache. I am in favor of doing it in one place and doing it well. Let's just focus on `grpc-server` for now and then we can decide what other samples it makes sense to add it to. 

author_association: CONTRIBUTOR