Skip to content

add grpc client autowired #1309

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dapr-spring/dapr-spring-boot-autoconfigure/pom.xml
Original file line number Diff line number Diff line change
@@ -21,6 +21,12 @@
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seal90 why do we need a new module?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my head a new module makes sense if we want to isolate the gRPC dependencies because we think they might clash with other dependencies on the client application.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The abilities possessed by DAPR:service invocation, publish/subscribe, workflow, statemanagement, bindings...
dapr-spring model: data(state), messageing, workflows
example page: https://github.com/dapr/java-sdk/tree/master/examples/src/main/java/io/dapr/examples
I think we split the module by abilitie, so i create a new module.

<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-invoke</artifactId>
<version>${project.parent.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-messaging</artifactId>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package io.dapr.spring.boot.autoconfigure.client;

import io.dapr.spring.invoke.grpc.client.DaprGrpcBeanPostProcessor;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;

@AutoConfiguration
@AutoConfigureAfter(DaprClientAutoConfiguration.class)
public class DaprInvokeAutoConfiguration {

@Bean
@ConditionalOnProperty(name = "dapr.invoke.grpc.client.daprGrpcClient.enabled", havingValue = "true",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seal90 what's the use case for this? When will people enable this property?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if instead of having this, we have something like @EnableDaprWorkflows, but looking at this example: https://www.baeldung.com/spring-boot-grpc, there is no need to disable this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature is enabled by default. For users who only use the HTTP protocol, there will be no impact as they do not use @ DaprGrpcClient.
Due to the possibility that the matching logic initialized below may not be able to handle new API issues, such ashttps://github.com/grpc-ecosystem/grpc-spring/issues/1177. If the user is in a hurry to use the new API, they can close this area and implement this logic again on their own.

  private <T extends AbstractStub<T>> T createStub(final Class<T> stubClass, final Channel channel) {
    try {
      // Search for public static *Grpc#new*Stub(Channel)
      final Class<?> declaringClass = stubClass.getDeclaringClass();
      if (declaringClass != null) {
        for (final Method method : declaringClass.getMethods()) {
          final String name = method.getName();
          final int modifiers = method.getModifiers();
          final Parameter[] parameters = method.getParameters();
          if (name.startsWith("new") && name.endsWith("Stub")
              && Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
              && method.getReturnType().isAssignableFrom(stubClass)
              && parameters.length == 1
              && Channel.class.equals(parameters[0].getType())) {
            return stubClass.cast(method.invoke(null, channel));
          }
        }
      }

      // Search for a public constructor *Stub(Channel)
      final Constructor<T> constructor = stubClass.getConstructor(Channel.class);
      return constructor.newInstance(channel);
    } catch (final Exception e) {
      throw new BeanInstantiationException(stubClass, "Failed to create gRPC client", e);
    }
  }

matchIfMissing = true)
static DaprGrpcBeanPostProcessor daprGrpcClientBeanPostProcessor(
final ApplicationContext applicationContext) {
return new DaprGrpcBeanPostProcessor(applicationContext);
}
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
io.dapr.spring.boot.autoconfigure.client.DaprClientAutoConfiguration
io.dapr.spring.boot.autoconfigure.client.DaprInvokeAutoConfiguration
Original file line number Diff line number Diff line change
@@ -35,6 +35,11 @@
<artifactId>dapr-spring-data</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-invoke</artifactId>
<version>${project.parent.version}</version>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-messaging</artifactId>
25 changes: 25 additions & 0 deletions dapr-spring/dapr-spring-invoke/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
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>io.dapr.spring</groupId>
<artifactId>dapr-spring-parent</artifactId>
<version>0.15.0-SNAPSHOT</version>
</parent>

<artifactId>dapr-spring-invoke</artifactId>
<name>dapr-spring-invoke</name>
<description>Dapr Spring Invoke</description>
<packaging>jar</packaging>

<build>
<plugins>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package io.dapr.spring.invoke.grpc.client;

import com.google.common.collect.Lists;
import io.dapr.client.DaprClient;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientInterceptor;
import io.grpc.ClientInterceptors;
import io.grpc.stub.AbstractAsyncStub;
import io.grpc.stub.AbstractStub;
import org.springframework.beans.BeanInstantiationException;
import org.springframework.beans.BeansException;
import org.springframework.beans.InvalidPropertyException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.List;

import static java.util.Objects.requireNonNull;

/**
* Handlers Dapr gRPC client in spring boot.
* Searches for fields and methods in beans that are annotated with {@link DaprGrpcClient} and sets them.
*
*/
public class DaprGrpcBeanPostProcessor implements BeanPostProcessor {

private final ApplicationContext applicationContext;

private DaprClient daprClient;

public DaprGrpcBeanPostProcessor(ApplicationContext applicationContext) {
this.applicationContext = requireNonNull(applicationContext, "applicationContext");
}

@Override
public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException {
processDaprGprcClients(bean);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the checkstyle working?


return bean;
}

/**
* Process Dapr gRPC client in bean.
* @param bean The bean to process.
*/
private void processDaprGprcClients(final Object bean) {
Class<?> clazz = bean.getClass();
do {
processDaprGprcClientFields(clazz, bean);
clazz = clazz.getSuperclass();
} while (clazz != null);
}

/**
* Process DaprGrpcClient annotation in bean.
* @param clazz The class to process.
* @param bean The bean to process.
*/
private void processDaprGprcClientFields(final Class<?> clazz, final Object bean) {
for (final Field field : clazz.getDeclaredFields()) {
final DaprGrpcClient annotation = AnnotationUtils.findAnnotation(field, DaprGrpcClient.class);
if (annotation != null) {
ReflectionUtils.makeAccessible(field);
ReflectionUtils.setField(field, bean, processDaprGrpcClientPoint(field, field.getType(), annotation));
}
}
}

/**
* Processes DaprGrpcClient announce and computes the appropriate value for the injection.
*
* @param <T> The type to be injected for the given injection point.
* @param injectionTarget The target member for the injection.
* @param injectionType The class that should injected type.
* @param annotation The DaprGrpcClient annotation instance.
* @return The value to be injected for the given injection point.
*/
private <T> T processDaprGrpcClientPoint(final Member injectionTarget, final Class<T> injectionType,
final DaprGrpcClient annotation) {
final String name = annotation.value();

final List<ClientInterceptor> interceptors = interceptorsFromAnnotation(annotation);
if (annotation.sortInterceptors()) {
interceptors.sort(AnnotationAwareOrderComparator.INSTANCE);
}

return valueForMember(name, injectionTarget, injectionType, interceptors);
}

/**
* Processes DaprGrpcClient announce with Channel or AbstractStub type.
*
* @param <T> The type of the instance to be injected.
* @param <ST> The type of the AbstractStub implement class.
* @param name The name of target service name.
* @param injectionTarget The target member for the injection.
* @param injectionType The class that should injected type.
* @param interceptors The interceptors defined on DaprGrpcClient.
* @return The value that matches the type of the given field.
* @throws BeansException If the value of the field could not be created or the type of the field is unsupported.
*/
protected <T, ST extends AbstractStub<ST>> T valueForMember(final String name, final Member injectionTarget,
final Class<T> injectionType,
final List<ClientInterceptor> interceptors)
throws BeansException {
if (Channel.class.equals(injectionType)) {
Channel channel = getDaprClient().newGrpcStub(name, DaprGrpcBeanPostProcessor::newStub).getChannel();
channel = ClientInterceptors.interceptForward(channel, interceptors);
return injectionType.cast(channel);
} else if (AbstractStub.class.isAssignableFrom(injectionType)) {
@SuppressWarnings("unchecked")
ST stub = getDaprClient().newGrpcStub(name, (daprChannel ->
createStub((Class<ST>)injectionType.asSubclass(AbstractStub.class), daprChannel)));
stub = stub.withInterceptors(interceptors.toArray(new ClientInterceptor[0]));
return injectionType.cast(stub);
} else {
if (injectionTarget != null) {
throw new InvalidPropertyException(injectionTarget.getDeclaringClass(), injectionTarget.getName(),
"Unsupported type " + injectionType.getName());
} else {
throw new BeanInstantiationException(injectionType, "Unsupported grpc stub or channel type");
}
}
}

/**
* Create a new stub by stubType and channel.
*
* @param stubClass The stub class that needs to be created.
* @param channel The gRPC channel associated with the created stub, passed as a parameter to the stub factory.
* @return A newly created gRPC stub.
*/
private <T extends AbstractStub<T>> T createStub(final Class<T> stubClass, final Channel channel) {
try {
// Search for public static *Grpc#new*Stub(Channel)
final Class<?> declaringClass = stubClass.getDeclaringClass();
if (declaringClass != null) {
for (final Method method : declaringClass.getMethods()) {
final String name = method.getName();
final int modifiers = method.getModifiers();
final Parameter[] parameters = method.getParameters();
if (name.startsWith("new") && name.endsWith("Stub")
&& Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)
&& method.getReturnType().isAssignableFrom(stubClass)
&& parameters.length == 1
&& Channel.class.equals(parameters[0].getType())) {
return stubClass.cast(method.invoke(null, channel));
}
}
}

// Search for a public constructor *Stub(Channel)
final Constructor<T> constructor = stubClass.getConstructor(Channel.class);
return constructor.newInstance(channel);
} catch (final Exception e) {
throw new BeanInstantiationException(stubClass, "Failed to create gRPC client", e);
}
}

/**
* Create a new stub by stubType and channel.
*
* @param channel The grpc channel.
* @return The transparent stub instance.
*/
private static DaprTransparentStub newStub(final Channel channel) {
AbstractStub.StubFactory<DaprTransparentStub> factory = new AbstractStub.StubFactory<DaprTransparentStub>() {
public DaprTransparentStub newStub(final Channel channel, final CallOptions callOptions) {
return new DaprTransparentStub(channel, callOptions);
}
};
return DaprTransparentStub.newStub(factory, channel);
}

/**
* A transparent stub that for DaprClient get channel.
*/
private static class DaprTransparentStub extends AbstractAsyncStub<DaprTransparentStub> {
private DaprTransparentStub(final Channel channel, final CallOptions callOptions) {
super(channel, callOptions);
}

protected DaprTransparentStub build(final Channel channel, final CallOptions callOptions) {
return new DaprTransparentStub(channel, callOptions);
}
}

/**
* Gets or creates the {@link ClientInterceptor}s that are referenced in the given annotation.
*
* @param annotation The annotation to get the interceptors for.
* @return A list containing the interceptors for the given annotation.
* @throws BeansException If the referenced interceptors weren't found or could not be created.
*/
protected List<ClientInterceptor> interceptorsFromAnnotation(final DaprGrpcClient annotation) throws BeansException {
final List<ClientInterceptor> list = Lists.newArrayList();
for (final Class<? extends ClientInterceptor> interceptorClass : annotation.interceptors()) {
final ClientInterceptor clientInterceptor;
if (this.applicationContext.getBeanNamesForType(interceptorClass).length > 0) {
clientInterceptor = this.applicationContext.getBean(interceptorClass);
} else {
try {
clientInterceptor = interceptorClass.getConstructor().newInstance();
} catch (final Exception e) {
throw new BeanCreationException("Failed to create interceptor instance", e);
}
}
list.add(clientInterceptor);
}
for (final String interceptorName : annotation.interceptorNames()) {
list.add(this.applicationContext.getBean(interceptorName, ClientInterceptor.class));
}
return list;
}

private DaprClient getDaprClient() {
if (this.daprClient == null) {
this.daprClient = this.applicationContext.getBean(DaprClient.class);
}
return this.daprClient;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package io.dapr.spring.invoke.grpc.client;

import io.grpc.Channel;
import io.grpc.ClientInterceptor;
import io.grpc.stub.AbstractStub;
import org.springframework.beans.factory.annotation.Autowired;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* An annotation for fields of type {@link Channel} or subclasses of {@link AbstractStub}/gRPC client services.
*
* <p>
* <b>Note:</b> Fields that are annotated with this annotation should NOT be annotated with
* {@link Autowired} (conflict).
* </p>
*
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DaprGrpcClient {

/**
* The name of the target service. The channel use DaprClient's grpc channel.
*
* <p>
* <b>Example:</b> <code>@DaprGrpcClient("exampleService")</code> &lt;-&gt;
* {@code headers.put(Metadata.Key.of("dapr-app-id", Metadata.ASCII_STRING_MARSHALLER), name); }
* </p>
*
* @return The name of the target service.
*/
String value();

/**
* A list of {@link ClientInterceptor} classes that should be used with this client in addition to the globally
* defined ones. If a bean of the given type exists, it will be used; otherwise a new instance of that class will be
* created via no-args constructor.
*
* @return A list of ClientInterceptor classes that should be used.
*/
Class<? extends ClientInterceptor>[] interceptors() default {};

/**
* A list of {@link ClientInterceptor} beans that should be used with this client in addition to the globally
* defined ones.
*
* @return A list of ClientInterceptor beans that should be used.
*/
String[] interceptorNames() default {};

/**
* Whether the custom ClientInterceptor defined by interceptors and interceptorNames should be sorted.
*
* <p>
* Sorted by
* {@code interceptors.sort(AnnotationAwareOrderComparator.INSTANCE)}
* </p>
*
*
* @return True, if the custom interceptors will be sorted. False otherwise.
*/
boolean sortInterceptors() default false;
}
1 change: 1 addition & 0 deletions dapr-spring/pom.xml
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@

<modules>
<module>dapr-spring-data</module>
<module>dapr-spring-invoke</module>
<module>dapr-spring-messaging</module>
<module>dapr-spring-workflows</module>
<module>dapr-spring-boot-autoconfigure</module>
11 changes: 11 additions & 0 deletions spring-boot-examples/consumer-app/pom.xml
Original file line number Diff line number Diff line change
@@ -13,6 +13,10 @@
<description>Spring Boot, Testcontainers and Dapr Integration Examples :: Consumer App</description>

<dependencies>
<dependency>
<groupId>io.dapr</groupId>
<artifactId>grpc-lib</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@@ -62,6 +66,13 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.dapr.springboot.examples.consumer.invoke.grpc;

import io.dapr.springboot.examples.DaprExamplesProtos;
import io.dapr.springboot.examples.HelloWorldGrpc;
import io.dapr.spring.invoke.grpc.client.DaprGrpcClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

@DaprGrpcClient("producer-app")
Copy link
Contributor

@salaboy salaboy Apr 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@seal90 ok.. I think I understand what is going on here..

Looking at this example: https://www.baeldung.com/spring-boot-grpc having it named @DaprGrpcClient makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea from https://github.com/grpc-ecosystem/grpc-spring.
At first, I wanted to expand its capabilities, but I found that it hasn't changed in a year, but this usage method is really useful.

private HelloWorldGrpc.HelloWorldBlockingStub blockingStub;

@RequestMapping("/hello")
public String sayHello(@RequestParam("name") String name) {
DaprExamplesProtos.HelloRequest request = DaprExamplesProtos.HelloRequest.newBuilder().setName(name).build();
DaprExamplesProtos.HelloReply reply = blockingStub.sayHello(request);
return reply.getMessage();

Check warning on line 20 in spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/invoke/grpc/HelloWorldController.java

Codecov / codecov/patch

spring-boot-examples/consumer-app/src/main/java/io/dapr/springboot/examples/consumer/invoke/grpc/HelloWorldController.java#L18-L20

Added lines #L18 - L20 were not covered by tests
}
}
106 changes: 106 additions & 0 deletions spring-boot-examples/grpc-lib/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?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>io.dapr</groupId>
<artifactId>spring-boot-examples</artifactId>
<version>0.15.0-SNAPSHOT</version>
</parent>

<artifactId>grpc-lib</artifactId>
<name>grpc-lib</name>
<description>protobuf files</description>

<properties>
<protobuf.output.directory>${project.build.directory}/generated-sources</protobuf.output.directory>
<protobuf.input.directory>${project.basedir}/src/main/proto</protobuf.input.directory>
</properties>

<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-api</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java-util</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.11.4</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocVersion>${protobuf.version}</protocVersion>
<addProtoSources>inputs</addProtoSources>
<includeMavenTypes>direct</includeMavenTypes>
<includeStdTypes>true</includeStdTypes>
<inputDirectories>
<include>${protobuf.input.directory}</include>
</inputDirectories>
<outputTargets>
<outputTarget>
<type>java</type>
<outputDirectory>${protobuf.output.directory}</outputDirectory>
</outputTarget>
<outputTarget>
<type>grpc-java</type>
<outputDirectory>${protobuf.output.directory}</outputDirectory>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}</pluginArtifact>
</outputTarget>
</outputTargets>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<!-- Skip checkstyle for auto-generated code -->
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>

</project>
23 changes: 23 additions & 0 deletions spring-boot-examples/grpc-lib/src/main/proto/helloworld.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
syntax = "proto3";

package daprexamples;

option java_outer_classname = "DaprExamplesProtos";
option java_package = "io.dapr.springboot.examples";

// User Code definitions
service HelloWorld {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}

}

// The request message containing the user's name.
message HelloRequest {
string name = 1;
}

// The response message containing the greetings
message HelloReply {
string message = 1;
}
7 changes: 6 additions & 1 deletion spring-boot-examples/pom.xml
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@
</properties>

<modules>
<module>grpc-lib</module>
<module>producer-app</module>
<module>consumer-app</module>
</modules>
@@ -30,7 +31,11 @@
<artifactId>spring-boot-dependencies</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
<scope>import</scope>
<scope>import</scope></dependency>
<dependency>
<groupId>io.dapr</groupId>
<artifactId>grpc-lib</artifactId>
<version>0.15.0-SNAPSHOT</version>
</dependency>
</dependencies>
</dependencyManagement>
16 changes: 16 additions & 0 deletions spring-boot-examples/producer-app/pom.xml
Original file line number Diff line number Diff line change
@@ -14,6 +14,10 @@
<description>Spring Boot, Testcontainers and Dapr Integration Examples :: Producer App</description>

<dependencies>
<dependency>
<groupId>io.dapr</groupId>
<artifactId>grpc-lib</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
@@ -30,6 +34,11 @@
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>io.dapr.spring</groupId>
<artifactId>dapr-spring-boot-starter-test</artifactId>
@@ -57,6 +66,13 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.dapr.springboot.examples.producer.invoke.grpc;

import io.dapr.springboot.examples.HelloWorldGrpc;
import net.devh.boot.grpc.server.service.GrpcService;

@GrpcService
public class HelloWorldProducer extends HelloWorldGrpc.HelloWorldImplBase {

@Override
public void sayHello(io.dapr.springboot.examples.DaprExamplesProtos.HelloRequest request,
io.grpc.stub.StreamObserver<io.dapr.springboot.examples.DaprExamplesProtos.HelloReply> responseObserver) {
io.dapr.springboot.examples.DaprExamplesProtos.HelloReply reply = io.dapr.springboot.examples.DaprExamplesProtos.HelloReply.newBuilder()
.setMessage("Hello " + request.getName())
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}

Check warning on line 17 in spring-boot-examples/producer-app/src/main/java/io/dapr/springboot/examples/producer/invoke/grpc/HelloWorldProducer.java

Codecov / codecov/patch

spring-boot-examples/producer-app/src/main/java/io/dapr/springboot/examples/producer/invoke/grpc/HelloWorldProducer.java#L12-L17

Added lines #L12 - L17 were not covered by tests
}