grpc-spring-boot-starter icon indicating copy to clipboard operation
grpc-spring-boot-starter copied to clipboard

add gRPC exception advice support for factory beans

Open bitbrain opened this issue 4 years ago • 7 comments

This pull request addresses #265

When currently using @GRpcServiceAdvice on a bean that is being created within a @Configuration like so (Spring Boot 2.5.6):

 @Bean
 public GrpcExceptionAdvice grpcExceptionAdvice() {
     return new GrpcExceptionAdvice();
 }

it will produce the following exception on startup:

Caused by: java.lang.NullPointerException
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:315)
	at org.lognet.springboot.grpc.autoconfigure.OnMissingErrorHandlerCondition.getMatchOutcome(OnMissingErrorHandlerCondition.java:35)
	at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
	... 95 more

The reason is that the current logic does not support beans created through factory methods: https://github.com/LogNet/grpc-spring-boot-starter/blob/19fc75177a40d5b7b64cf6dcde81dfd4bb9a5eb9/grpc-spring-boot-starter/src/main/java/org/lognet/springboot/grpc/autoconfigure/OnMissingErrorHandlerCondition.java#L29

The solution

bitbrain avatar Nov 24 '21 15:11 bitbrain

Codecov Report

Merging #266 (860950d) into master (d70346b) will decrease coverage by 0.14%. The diff coverage is 71.42%.

Impacted file tree graph

@@             Coverage Diff              @@
##             master     #266      +/-   ##
============================================
- Coverage     88.24%   88.09%   -0.15%     
- Complexity      317      318       +1     
============================================
  Files            50       50              
  Lines          1531     1537       +6     
  Branches         86       87       +1     
============================================
+ Hits           1351     1354       +3     
- Misses          143      144       +1     
- Partials         37       39       +2     
Impacted Files Coverage Δ
.../autoconfigure/OnMissingErrorHandlerCondition.java 77.77% <71.42%> (-7.94%) :arrow_down:

Continue to review full report at Codecov.

Legend - Click here to learn more Δ = absolute <relative> (impact), ø = not affected, ? = missing data Powered by Codecov. Last update d70346b...860950d. Read the comment docs.

codecov[bot] avatar Nov 24 '21 15:11 codecov[bot]

I will add tests for this.

bitbrain avatar Nov 24 '21 16:11 bitbrain

what is the spring boot version you are running with?

jvmlet avatar Nov 25 '21 09:11 jvmlet

what is the spring boot version you are running with?

@jvmlet 2.5.6

bitbrain avatar Nov 25 '21 20:11 bitbrain

@jvmlet any recommendations on how I can get the code coverage to pass? I checked https://app.codecov.io/gh/LogNet/grpc-spring-boot-starter/compare/266/changes and it seems to have no changes and I also added tests to ensure the bean loading works correctly but it complains about +0.15% coverage decrease.

bitbrain avatar Nov 29 '21 10:11 bitbrain

I did some digging why that newly added code is not called during the integration tests. Here is my summary. Feedback welcome on how we could change these tests to reproduce this behaviour, as I am currently unable to determine what specifically is causing this behaviour to occur.

Scenario 1: AnnotatedGenericBeanDefinition

This is the current logic within the unit tests of this Spring Boot starter. Setting up the bean like this: https://github.com/LogNet/grpc-spring-boot-starter/blob/860950d7f261f41fe733f419d13ec7b3f7b529b0/grpc-spring-boot-starter-demo/src/test/java/org/lognet/springboot/grpc/recovery/GRpcRecoveryTest.java#L77

...will internally create an AnnotatedGenericBeanDefinition and set it on the internal beanFactoryMap within the beanFactory. As a result, beanDefinition.getBeanClassName() is not null.

Scenario 2: ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition

Within our codebase, we use a custom Spring Boot starter to define a custom advice like so:

@Bean
public GrpcExceptionAdvice grpcExceptionAdvice() {
        return new GrpcExceptionAdvice();
 }

which itself looks like this:

@GRpcServiceAdvice
public class GrpcExceptionAdvice {
 /* exception handlers go here*/
}

This is literally the same setup, however, for some reason it is using a different bean definition where beanDefinition.getBeanClassName() returns null and instead the class name can be obtained from the internal MethodMetadata on the AnnotatedBeanDefinition.

Question time!

How can I change the tests within this Spring Boot starter to replicate Scenario 2?

bitbrain avatar Dec 02 '21 16:12 bitbrain

See behavior difference if you define the inner advice class as static/non-static

jvmlet avatar Dec 06 '21 20:12 jvmlet