A common java rpc/rest result wrapper.
results-apiis for the client-side using (e.g., api, client or sdk), it should be referenced in those libraries.results-supportis for the server-side supporting (e.g., result wrapping, exception converting, etc), it should NOT be referenced in the client-side libraries.
NOTE: All modules in this project are not deployed to maven center. Deploy to your own nexus or install to local repository to use them!
project structure:
foo-project
|-- foo-client
| |-- src
| |-- pom.xml
|-- foo-server
| |-- src
| |-- pom.xml
|-- pom.xml
Reference the libraries:
foo-client/pom.xml:
<dependency> <groupId>com.github.jasomming.results</groupId> <artifactId>results-api</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
foo-server/pom.xml:
<dependency> <groupId>com.github.jasomming.results</groupId> <artifactId>results-support</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
Declare a rpc method with an exact type of result wrapper in client-side library:
importcom.github.jasonnming.results.result.generic.SingleResult; publicinterfaceFooClient { SingleResult<FooResultCode, FooInfo> queryFooInfo(); }
Implements it:
importcom.github.jasonnming.results.result.support.Results; classFooClientImplimplementsFooClient { @OverridepublicSingleResult<FooResultCode, FooInfo> queryFooInfo() { FooInfofooInfo = ...; returnResults.singleResult(FooResultCode.SUCCESS, fooInfo); } }
project structure:
foo-project
|-- src
|-- pom.xml
Reference the libraries:
./pom.xml:
<dependency> <groupId>com.github.jasomming.results</groupId> <artifactId>results-support</artifactId> <version>1.0.0-SNAPSHOT</version> </dependency>
Uses in the controller/handler:
importcom.github.jasonnming.results.result.support.Results; @RestControllerclassFooController { @GetMapping("/foo") publicObjectqueryFooInfo() { FooInfofooInfo = ...; returnResults.singleResult(FooResultCode.SUCCESS, fooInfo); } }
Usually, exceptions have to be converted to a unified form for returning.
If your exceptions are extending from BusinessException, then you can simply use ResultInterceptor to convert exceptions to corresponding result.
Registers ResultInterceptor as an spring-aop advisor to enable above features.
First, you need adding spring-aop and spring-aspects (if using any AspectJ feature, e.g., pointcut expression):
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>RELEASE</version>
</dependency>Then, configure a pointcut to the interceptor:
Using application.xml
<beanid="resultInterceptor"class="com.github.jasonnming.results.result.support.ResultInterceptor"/> <aop:config> <!-- RPC support --> <aop:advisoradvice-ref="resultInterceptor"pointcut="execution(* foo.client..*Client.*(..))"/> <!-- REST support --> <aop:advisoradvice-ref="resultInterceptor"pointcut="@target(org.springframework.web.bind.annotation.RestController)"/> </aop:config>
Using Java-config (Spring-boot)
importcom.github.jasonnming.results.result.support.ResultInterceptor; importorg.springframework.aop.Advisor; importorg.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration@EnableAspectJAutoProxyclassFooConfig { @BeanAdvisorrpcInterceptor() { finalAspectJExpressionPointcutAdvisoradvisor = newAspectJExpressionPointcutAdvisor(); { advisor.setExpression("execution(* foo.client..*Client.*(..))"); advisor.setAdvice(newResultInterceptor()); } returnadvisor; } @BeanAdvisorwebInterceptor() { finalAspectJExpressionPointcutAdvisoradvisor = newAspectJExpressionPointcutAdvisor(); { advisor.setExpression("@target(org.springframework.web.bind.annotation.RestController)"); advisor.setAdvice(newResultInterceptor()); } returnadvisor; } // Just register another advisors if necessary. }
Using
@Aspectimportcom.github.jasonming.results.result.support.MethodReturnWrapper; importorg.aspectj.lang.ProceedingJoinPoint; importorg.aspectj.lang.annotation.Around; importorg.aspectj.lang.annotation.Aspect; importorg.aspectj.lang.annotation.Pointcut; importorg.aspectj.lang.reflect.MethodSignature; @AspectclassFooAspect { @Pointcut("execution(* foo.client..*Client.*(..))") voidrpcPointcut() {} @Pointcut("@target(org.springframework.web.bind.annotation.RestController)") voidwebPointcut() {} @Around(value = "rpcPointcut() || webPointcut()") Objectintercept(finalProceedingJoinPointjoinPoint) throwsThrowable { returnMethodReturnWrapper.forMethod(((MethodSignature)joinPoint.getSignature()).getMethod()) .wrapInvocation(joinPoint::proceed); } }
Enjoy!