Description
The Problem
Spring allows classes annotated with @ControllerAdvice
and containing @ExceptionHandler
s to be extended and overridden as necessary, such that the behaviours of the overridden methods take precedence over base methods.
It seems we can not similarly inherit and extend classes annotated with @GrpcAdvice
and containing @GrpcExceptionHandler
s.
Steps to Reproduce
With Proper Annotations and Overriding in Derived Class
If one tries to extend one @GrpcAdvice
class with another, providing the @GrpcExceptionHandler
annotations as shown below, the application is unable to start up with Fatal Exception: Ambiguous "@GrpcExceptionHandler" method mapped for BadRequestException.
.
@GrpcAdvice
public class BaseGrpcExceptionHandler {
@GrpcExceptionHandler(BadRequestException.class)
public Status handleBadRequestException(BadRequestException ex) {
LOGGER.error("Bad Request Sent to Service: ", ex).log();
return embedStatusWithExceptionData(Status.INVALID_ARGUMENT, ex);
}
}
@GrpcAdvice
public class SpecialisedGrpcExceptionHandler extends BaseGrpcExceptionHandler {
@Override
@GrpcExceptionHandler(BadRequestException.class)
public Status handleBadRequestException(BadRequestException ex) {
final Status internalErrorStatus = super.handleBadRequestException(ex);
return resolveExceptionResponseDtoForClientSide(internalErrorStatus);
}
private Status resolveExceptionResponseDtoForClientSide(Status status) {
// ...Some custom logic
}
}
Without @GrpcExceptionHandler
annotation in Derived Class
If one tries to extend one @GrpcAdvice
class with another as shown below, without @GrpcExceptionHandler
annotation, the application is unable to start up with Fatal Exception: [net/devh/boot/grpc/server/autoconfigure/GrpcAdviceAutoConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: @GrpcExceptionHandler annotation not found.
.
@GrpcAdvice
public class BaseGrpcExceptionHandler {
@GrpcExceptionHandler(BadRequestException.class)
public Status handleBadRequestException(BadRequestException ex) {
LOGGER.error("Bad Request Sent to Service: ", ex).log();
return embedStatusWithExceptionData(Status.INVALID_ARGUMENT, ex);
}
}
@GrpcAdvice
public class SpecialisedGrpcExceptionHandler extends BaseGrpcExceptionHandler {
@Override
public Status handleBadRequestException(BadRequestException ex) {
final Status internalErrorStatus = super.handleBadRequestException(ex);
return resolveExceptionResponseDtoForClientSide(internalErrorStatus);
}
private Status resolveExceptionResponseDtoForClientSide(Status status) {
// ...Some custom logic
}
}
Additional Context
The dependency being used is:
<dependency>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<artifactId>grpc-core</artifactId>
<groupId>io.grpc</groupId>
</exclusion>
</exclusions>
<groupId>net.devh</groupId>
<version>2.13.1.RELEASE</version>
</dependency>
Other versions being used are as follows:
<properties>
<grpc.version>1.46.0</grpc.version>
<java.version>11</java.version>
<project.version>0.0.1-SNAPSHOT</project.version>
<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
<protobuf.version>3.20.1</protobuf.version>
<spring.boot.version>2.5.8</spring.boot.version>
<spring.cloud.kubernetes.version>1.1.10.RELEASE</spring.cloud.kubernetes.version>
<spring.cloud.version>2020.0.5</spring.cloud.version>
</properties>