Skip to content

Commit e62a040

Browse files
committed
Add @GrpcAdvice exception handling support
Closes gh-49053
1 parent 9bf698d commit e62a040

2 files changed

Lines changed: 77 additions & 1 deletion

File tree

module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerAutoConfiguration.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
import org.springframework.grpc.server.GlobalServerInterceptor;
3939
import org.springframework.grpc.server.GrpcServerFactory;
4040
import org.springframework.grpc.server.ServerBuilderCustomizer;
41+
import org.springframework.grpc.server.advice.GrpcAdvice;
42+
import org.springframework.grpc.server.advice.GrpcAdviceDiscoverer;
43+
import org.springframework.grpc.server.advice.GrpcAdviceExceptionHandler;
44+
import org.springframework.grpc.server.advice.GrpcExceptionHandlerMethodResolver;
4145
import org.springframework.grpc.server.exception.CompositeGrpcExceptionHandler;
4246
import org.springframework.grpc.server.exception.GrpcExceptionHandler;
4347
import org.springframework.grpc.server.exception.GrpcExceptionHandlerInterceptor;
@@ -91,7 +95,8 @@ DefaultGrpcServiceDiscoverer grpcServiceDiscoverer(ApplicationContext applicatio
9195
@Bean
9296
@GlobalServerInterceptor
9397
@ConditionalOnMissingBean
94-
GrpcExceptionHandlerInterceptor globalExceptionHandlerInterceptor(List<GrpcExceptionHandler> exceptionHandlers) {
98+
GrpcExceptionHandlerInterceptor grpcGlobalExceptionHandlerInterceptor(
99+
List<GrpcExceptionHandler> exceptionHandlers) {
95100
CompositeGrpcExceptionHandler compositeHandler = new CompositeGrpcExceptionHandler(
96101
exceptionHandlers.toArray(GrpcExceptionHandler[]::new));
97102
return new GrpcExceptionHandlerInterceptor(compositeHandler);
@@ -104,4 +109,30 @@ static class ReactiveStubConfiguration {
104109

105110
}
106111

112+
@Configuration(proxyBeanMethods = false)
113+
@ConditionalOnBean(annotation = GrpcAdvice.class)
114+
static class GrpcAdviceConfiguration {
115+
116+
@Bean
117+
@ConditionalOnMissingBean
118+
GrpcAdviceDiscoverer grpcAdviceDiscoverer(ApplicationContext applicationContext) {
119+
return new GrpcAdviceDiscoverer(applicationContext);
120+
}
121+
122+
@Bean
123+
@ConditionalOnMissingBean
124+
GrpcExceptionHandlerMethodResolver grpcExceptionHandlerMethodResolver(
125+
GrpcAdviceDiscoverer grpcAdviceDiscoverer) {
126+
return new GrpcExceptionHandlerMethodResolver(grpcAdviceDiscoverer);
127+
}
128+
129+
@Bean
130+
@ConditionalOnMissingBean
131+
GrpcAdviceExceptionHandler grpcAdviceExceptionHandler(
132+
GrpcExceptionHandlerMethodResolver grpcExceptionHandlerMethodResolver) {
133+
return new GrpcAdviceExceptionHandler(grpcExceptionHandlerMethodResolver);
134+
}
135+
136+
}
137+
107138
}

module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerAutoConfigurationTests.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
import io.grpc.BindableService;
2222
import io.grpc.ServerServiceDefinition;
2323
import io.grpc.ServiceDescriptor;
24+
import io.grpc.Status;
25+
import io.grpc.StatusException;
2426
import io.grpc.inprocess.InProcessServerBuilder;
2527
import io.grpc.internal.GrpcUtil;
2628
import io.grpc.netty.NettyServerBuilder;
@@ -36,6 +38,7 @@
3638
import org.springframework.boot.autoconfigure.AutoConfigurations;
3739
import org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration;
3840
import org.springframework.boot.grpc.server.GrpcServletRegistration;
41+
import org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration.GrpcAdviceConfiguration;
3942
import org.springframework.boot.test.context.FilteredClassLoader;
4043
import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider;
4144
import org.springframework.boot.test.context.runner.AbstractApplicationContextRunner;
@@ -51,6 +54,11 @@
5154
import org.springframework.grpc.server.NettyGrpcServerFactory;
5255
import org.springframework.grpc.server.ServerBuilderCustomizer;
5356
import org.springframework.grpc.server.ShadedNettyGrpcServerFactory;
57+
import org.springframework.grpc.server.advice.GrpcAdvice;
58+
import org.springframework.grpc.server.advice.GrpcAdviceDiscoverer;
59+
import org.springframework.grpc.server.advice.GrpcAdviceExceptionHandler;
60+
import org.springframework.grpc.server.advice.GrpcExceptionHandler;
61+
import org.springframework.grpc.server.advice.GrpcExceptionHandlerMethodResolver;
5462
import org.springframework.grpc.server.lifecycle.GrpcServerLifecycle;
5563
import org.springframework.grpc.server.service.DefaultGrpcServiceDiscoverer;
5664
import org.springframework.grpc.server.service.GrpcServiceDiscoverer;
@@ -469,6 +477,43 @@ void whenHttp2EnabledPropertyMissingAndValidationDisabled() {
469477

470478
}
471479

480+
@Nested
481+
class GrpcAdviceAutoConfigurationTests {
482+
483+
private final ApplicationContextRunner contextRunner = GrpcServerAutoConfigurationTests.this.contextRunner;
484+
485+
@Test
486+
void whenNoAdviceDoesNotCreateBeans() {
487+
this.contextRunner.run((context) -> {
488+
assertThat(context).doesNotHaveBean(GrpcAdviceConfiguration.class);
489+
assertThat(context).doesNotHaveBean(GrpcAdviceDiscoverer.class);
490+
assertThat(context).doesNotHaveBean(GrpcExceptionHandlerMethodResolver.class);
491+
assertThat(context).doesNotHaveBean(GrpcAdviceExceptionHandler.class);
492+
});
493+
}
494+
495+
@Test
496+
void whenHasAdviceCreatesBeans() {
497+
this.contextRunner.withBean(GrpAdviceComponent.class).run((context) -> {
498+
assertThat(context).hasSingleBean(GrpcAdviceConfiguration.class);
499+
assertThat(context).hasSingleBean(GrpcAdviceDiscoverer.class);
500+
assertThat(context).hasSingleBean(GrpcExceptionHandlerMethodResolver.class);
501+
assertThat(context).hasSingleBean(GrpcAdviceExceptionHandler.class);
502+
});
503+
}
504+
505+
@GrpcAdvice
506+
static class GrpAdviceComponent {
507+
508+
@GrpcExceptionHandler
509+
StatusException onIllegalStateException(IllegalStateException ex) {
510+
return Status.FAILED_PRECONDITION.withDescription(ex.getMessage()).withCause(ex).asException();
511+
}
512+
513+
}
514+
515+
}
516+
472517
@Configuration(proxyBeanMethods = false)
473518
static class ServerBuilderCustomizersConfig {
474519

0 commit comments

Comments
 (0)