From b4bbc940ada517bf68bf787318569dfac83a31da Mon Sep 17 00:00:00 2001
From: Ralf Ueberfuhr <40685729+ueberfuhr@users.noreply.github.com>
Date: Fri, 5 Jan 2024 10:37:23 +0100
Subject: [PATCH] BAEL-7141: Create project structure with API stubs, service
provider and service consumer. (#15478)
---
spring-boot-modules/pom.xml | 1 +
.../helloworld-grpc-consumer/pom.xml | 35 ++++++++
.../helloworld/consumer/HelloWorldClient.java | 61 +++++++++++++
.../HelloWorldConsumerApplication.java | 13 +++
.../src/main/resources/application.yml | 11 +++
.../helloworld-grpc-java/pom.xml | 89 +++++++++++++++++++
.../helloworld/stubs/package-info.java | 5 ++
.../src/main/proto/helloworld.proto | 19 ++++
.../helloworld-grpc-provider/pom.xml | 35 ++++++++
.../provider/HelloWorldController.java | 42 +++++++++
.../HelloWorldProviderApplication.java | 13 +++
.../provider/StreamObserverUtility.java | 35 ++++++++
.../src/main/resources/application.yml | 9 ++
.../spring-boot-3-grpc/pom.xml | 25 ++++++
14 files changed, 393 insertions(+)
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java
create mode 100644 spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml
create mode 100644 spring-boot-modules/spring-boot-3-grpc/pom.xml
diff --git a/spring-boot-modules/pom.xml b/spring-boot-modules/pom.xml
index 890edd6cc5..4c8102f1c8 100644
--- a/spring-boot-modules/pom.xml
+++ b/spring-boot-modules/pom.xml
@@ -91,6 +91,7 @@
spring-boot-cassandre
spring-boot-react
+ spring-boot-3-grpc
spring-boot-3-native
spring-boot-3-observation
spring-boot-3-test-pitfalls
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml
new file mode 100644
index 0000000000..cebedf64f2
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/pom.xml
@@ -0,0 +1,35 @@
+
+
+ 4.0.0
+ helloworld-grpc-consumer
+ 0.0.1-SNAPSHOT
+ helloworld-grpc-consumer
+
+
+ com.baeldung
+ parent-boot-3
+ 0.0.1-SNAPSHOT
+ ../../../parent-boot-3
+
+
+
+
+ net.devh
+ grpc-client-spring-boot-starter
+ ${grpc-spring-boot-starter.version}
+
+
+ com.baeldung.spring-boot-modules
+ helloworld-grpc-java
+ 1.0.0-SNAPSHOT
+
+
+
+
+ 3.2.0
+ 2.15.0.RELEASE
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java
new file mode 100644
index 0000000000..166759544f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldClient.java
@@ -0,0 +1,61 @@
+package com.baeldung.helloworld.consumer;
+
+import com.baeldung.helloworld.stubs.HelloWorldRequest;
+import com.baeldung.helloworld.stubs.HelloWorldResponse;
+import com.baeldung.helloworld.stubs.HelloWorldServiceGrpc;
+import io.grpc.stub.StreamObserver;
+import net.devh.boot.grpc.client.inject.GrpcClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import java.util.stream.Stream;
+
+@Component
+public class HelloWorldClient {
+
+ private static final Logger log = LoggerFactory.getLogger(HelloWorldClient.class);
+
+ // constructor injection not possible
+ // "Do not use in conjunction with @Autowired or @Inject"
+ // (see https://github.com/grpc-ecosystem/grpc-spring)
+ @GrpcClient("hello")
+ HelloWorldServiceGrpc.HelloWorldServiceStub stub;
+
+ @EventListener(ContextRefreshedEvent.class)
+ void sendRequests() {
+ // prepare the response callback
+ final StreamObserver responseObserver = new StreamObserver() {
+ @Override
+ public void onNext(HelloWorldResponse helloWorldResponse) {
+ log.info("Hello World Response: {}", helloWorldResponse.getGreeting());
+ }
+
+ @Override
+ public void onError(Throwable throwable) {
+ log.error("Error occured", throwable);
+ }
+
+ @Override
+ public void onCompleted() {
+ log.info("Hello World request finished");
+ }
+ };
+ // connect to the server
+ final StreamObserver request = stub.sayHello(responseObserver);
+ // send multiple requests (streaming)
+ Stream.of("Tom", "Julia", "Baeldung", "", "Ralf")
+ .map(HelloWorldRequest.newBuilder()::setName)
+ .map(HelloWorldRequest.Builder::build)
+ .forEach(request::onNext);
+ request.onCompleted();
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java
new file mode 100644
index 0000000000..3df4667b77
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/java/com/baeldung/helloworld/consumer/HelloWorldConsumerApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.helloworld.consumer;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class HelloWorldConsumerApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(HelloWorldConsumerApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml
new file mode 100644
index 0000000000..9b0ed68375
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-consumer/src/main/resources/application.yml
@@ -0,0 +1,11 @@
+grpc:
+ client:
+ hello:
+ address: localhost:9090
+ negotiation-type: plaintext
+logging:
+ pattern:
+ console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%t] [%logger - %line]: %m%n"
+ level:
+ com.baeldung.helloworld.consumer: info
+ include-application-name: false
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml
new file mode 100644
index 0000000000..0a5bea3e0b
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/pom.xml
@@ -0,0 +1,89 @@
+
+
+ 4.0.0
+
+ com.baeldung.spring-boot-modules
+ spring-boot-3-grpc
+ 1.0.0-SNAPSHOT
+
+
+ helloworld-grpc-java
+
+
+
+ io.grpc
+ grpc-protobuf
+ ${io.grpc.version}
+
+
+ io.grpc
+ grpc-stub
+ ${io.grpc.version}
+
+
+ io.grpc
+ grpc-testing
+ ${io.grpc.version}
+ test
+
+
+
+ javax.annotation
+ javax.annotation-api
+ ${annotation-api.version}
+ provided
+ true
+
+
+
+
+
+
+ kr.motd.maven
+ os-maven-plugin
+ ${os-maven-plugin.version}
+
+
+
+
+ org.xolstice.maven.plugins
+ protobuf-maven-plugin
+ ${protobuf-maven-plugin.version}
+
+ com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
+
+ grpc-java
+ io.grpc:protoc-gen-grpc-java:${io.grpc.version}:exe:${os.detected.classifier}
+
+
+
+
+ protobuf-compile
+
+ compile
+ test-compile
+
+
+
+ protobuf-compile-custom
+
+ compile-custom
+ test-compile-custom
+
+
+
+
+
+
+
+
+ 1.58.0
+ 3.25.1
+ 1.7.1
+ 0.6.1
+ 1.3.2
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java
new file mode 100644
index 0000000000..a7d7190612
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/java/com/baeldung/helloworld/stubs/package-info.java
@@ -0,0 +1,5 @@
+/**
+ * This package contains the gRPC stubs
+ * generated by the protoc compiler.
+ */
+package com.baeldung.helloworld.stubs;
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto
new file mode 100644
index 0000000000..19461bae0a
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-java/src/main/proto/helloworld.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+option java_package = "com.baeldung.helloworld.stubs";
+option java_multiple_files = true;
+
+message HelloWorldRequest {
+ // a name to greet, default is "World"
+ optional string name = 1;
+}
+
+message HelloWorldResponse {
+ string greeting = 1;
+}
+
+service HelloWorldService {
+
+ rpc SayHello(stream HelloWorldRequest) returns (stream HelloWorldResponse);
+
+}
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml
new file mode 100644
index 0000000000..f13d65203d
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/pom.xml
@@ -0,0 +1,35 @@
+
+
+ 4.0.0
+ helloworld-grpc-provider
+ 0.0.1-SNAPSHOT
+ helloworld-grpc-provider
+
+
+ com.baeldung
+ parent-boot-3
+ 0.0.1-SNAPSHOT
+ ../../../parent-boot-3
+
+
+
+
+ net.devh
+ grpc-server-spring-boot-starter
+ ${grpc-spring-boot-starter.version}
+
+
+ com.baeldung.spring-boot-modules
+ helloworld-grpc-java
+ 1.0.0-SNAPSHOT
+
+
+
+
+ 3.2.0
+ 2.15.0.RELEASE
+
+
+
\ No newline at end of file
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java
new file mode 100644
index 0000000000..2d9426a46e
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldController.java
@@ -0,0 +1,42 @@
+package com.baeldung.helloworld.provider;
+
+import com.baeldung.helloworld.stubs.HelloWorldRequest;
+import com.baeldung.helloworld.stubs.HelloWorldResponse;
+import com.baeldung.helloworld.stubs.HelloWorldServiceGrpc;
+import io.grpc.stub.StreamObserver;
+import net.devh.boot.grpc.server.service.GrpcService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+@GrpcService
+public class HelloWorldController extends HelloWorldServiceGrpc.HelloWorldServiceImplBase {
+
+ private static final Logger log = LoggerFactory.getLogger(HelloWorldController.class);
+
+ private HelloWorldResponse sayHello(HelloWorldRequest request) {
+ log.info("Received request: {}", request);
+ return HelloWorldResponse
+ .newBuilder()
+ .setGreeting("Hello "
+ + Optional
+ .of(request.getName())
+ .map(String::trim)
+ .filter(s -> !s.isEmpty())
+ .orElse("World")
+ + "!"
+ )
+ .build();
+ }
+
+ @Override
+ public StreamObserver sayHello(
+ StreamObserver responseObserver
+ ) {
+ return StreamObserverUtility.proxyStream(
+ responseObserver,
+ this::sayHello
+ );
+ }
+}
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java
new file mode 100644
index 0000000000..fa69ed8d57
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/HelloWorldProviderApplication.java
@@ -0,0 +1,13 @@
+package com.baeldung.helloworld.provider;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class HelloWorldProviderApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(HelloWorldProviderApplication.class, args);
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java
new file mode 100644
index 0000000000..394f3a999c
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/java/com/baeldung/helloworld/provider/StreamObserverUtility.java
@@ -0,0 +1,35 @@
+package com.baeldung.helloworld.provider;
+
+import io.grpc.stub.StreamObserver;
+
+import java.util.function.Function;
+
+final class StreamObserverUtility {
+
+ private StreamObserverUtility() {
+ }
+
+ static StreamObserver proxyStream(
+ StreamObserver target,
+ Function handler
+ ) {
+ return new StreamObserver() {
+ @Override
+ public void onNext(Source value) {
+ final Target targetValue = handler.apply(value);
+ target.onNext(targetValue);
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ target.onError(t);
+ }
+
+ @Override
+ public void onCompleted() {
+ target.onCompleted();
+ }
+ };
+ }
+
+}
diff --git a/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml
new file mode 100644
index 0000000000..2ccf6ad95f
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/helloworld-grpc-provider/src/main/resources/application.yml
@@ -0,0 +1,9 @@
+grpc:
+ server:
+ port: 9090
+logging:
+ pattern:
+ console: "[%d{yyyy-MM-dd HH:mm:ss.SSS}] %-5level [%t] [%logger - %line]: %m%n"
+ level:
+ com.baeldung.helloworld.provider: info
+ include-application-name: false
diff --git a/spring-boot-modules/spring-boot-3-grpc/pom.xml b/spring-boot-modules/spring-boot-3-grpc/pom.xml
new file mode 100644
index 0000000000..3b5ef15048
--- /dev/null
+++ b/spring-boot-modules/spring-boot-3-grpc/pom.xml
@@ -0,0 +1,25 @@
+
+
+ 4.0.0
+ com.baeldung.spring-boot-modules
+ spring-boot-3-grpc
+ 1.0.0-SNAPSHOT
+ spring-boot-3-grpc
+ pom
+
+
+ com.baeldung
+ parent-modules
+ 1.0.0-SNAPSHOT
+ ../../pom.xml
+
+
+
+ helloworld-grpc-java
+ helloworld-grpc-provider
+ helloworld-grpc-consumer
+
+
+