# Spring gRPC with Spring Boot 4 Companion repository for **[Spring gRPC with Spring Boot 4](https://ankurm.com/spring-grpc-spring-boot-4/)** on [ankurm.com](https://ankurm.com). The post covers the concepts. This repository adds the part that is hard to find written down: a symptom-first troubleshooting guide, with the failures reproduced as tests wherever a test can honestly reproduce them. Verified against **Spring Boot 4.1.0**, **spring-grpc 1.1.0**, **grpc-java 1.80.0**, **protobuf-java 4.34.2**, **JDK 25.0.3**. Full output in [`results-full.txt`](results-full.txt). --- ## Quick start Nothing to install — `protoc` and the gRPC codegen plugin are resolved as Maven artifacts, and every test runs over the in-process transport, so no port is bound. ```console git clone https://ankurm.com/git.app/asmhatre/spring-grpc-boot4.git cd spring-grpc-boot4 mvn test ``` 8 tests, a few seconds. --- ## What is here | Test | Covers | |---|---| | [`FourCallTypesTest`](src/test/java/com/ankurm/grpc/_01_basics/FourCallTypesTest.java) | Unary, server streaming, client streaming, bidirectional — and how their failure modes differ | | [`HardToDiagnoseTest`](src/test/java/com/ankurm/grpc/_02_troubleshooting/HardToDiagnoseTest.java) | Four failures reproduced and fixed: message size limits, missing deadlines, unobserved cancellation, useless error statuses | | [`ExceptionMappingTest`](src/test/java/com/ankurm/grpc/_03_exceptions/ExceptionMappingTest.java) | `@GrpcAdvice` / `@GrpcExceptionHandler` — domain exception → `NOT_FOUND`, validation → `INVALID_ARGUMENT`, catch-all → `INTERNAL` without leaking detail | | Document | Covers | |---|---| | [Troubleshooting](docs/01-troubleshooting.md) | Symptom-first index: every entry starts from the error message you actually see | | [Properties and versions](docs/02-properties-and-versions.md) | Complete `spring.grpc.*` reference, and which of the two projects owns what | ### Exception mapping [`OrderExceptionAdvice`](src/main/java/com/ankurm/grpc/orders/OrderExceptionAdvice.java) is the gRPC analogue of `@RestControllerAdvice`. The service throws plain domain exceptions and never mentions `Status`: ```java @GrpcAdvice public class OrderExceptionAdvice { @GrpcExceptionHandler(OrderNotFoundException.class) public StatusException handleNotFound(OrderNotFoundException ex) { Metadata trailers = new Metadata(); trailers.put(REASON_KEY, "ORDER_NOT_FOUND"); return Status.NOT_FOUND.withDescription(ex.getMessage()).asException(trailers); } } ``` Without it, every domain failure arrives as `UNKNOWN` with a **null description** — no code to branch on and no message to read. The service itself ([`OrderServiceImpl`](src/main/java/com/ankurm/grpc/orders/OrderServiceImpl.java)) is heavily commented and is where the correct patterns live — cancellation checks, half-close handling, `StreamObserver` thread-safety, structured errors. --- ## Five findings 1. **gRPC is a first-class Boot starter now, and "Spring gRPC" means two things.** `org.springframework.boot:spring-boot-starter-grpc-server` (version **4.1.0**) owns auto-configuration and every `spring.grpc.*` property; `org.springframework.grpc:spring-grpc-core` (version **1.1.0**) owns the programming model — `@GrpcService`, `@GrpcAdvice`, `GrpcChannelFactory`. The older standalone `spring-grpc-spring-boot-starter` stops at 1.0.3 and is what most search results describe. See [docs/02](docs/02-properties-and-versions.md). 2. **The in-process transport cannot enforce message size limits.** It passes messages by reference and never serialises them, so a 4 MB + 1 KB message sails through — and fails in production with `RESOURCE_EXHAUSTED`. Asserted in the test suite. The same blind spot covers compression, TLS, keepalive and load balancing. 3. **Two property names that cost real time.** `spring.grpc.server.inprocess.name` (not `in-process`) and `spring.grpc.client.channel..target` (singular `channel`, and `target` not `address`). Getting the second wrong yields `UnknownHostException` on the channel *name*, which sends you to look at DNS. 4. **gRPC has no default deadline.** A call without one waits forever. This is the single most common cause of a gRPC service that silently stops responding. 5. **Cancellation does not interrupt your thread.** It sets a `Context` flag. A server that never checks it keeps working for a client that left ten minutes ago. --- ## Reference machine AMD Ryzen 5 5600U, Windows 11, `java 25.0.3+9-LTS-195`, Maven 3.9.9. ## Licence MIT. See [LICENSE](LICENSE).