A common java rpc/rest result wrapper.
results-api
is for the client-side using (e.g., api, client or sdk), it should be referenced in those libraries.results-support
is 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:
import com.github.jasonnming.results.result.generic.SingleResult; public interface FooClient { SingleResult<FooResultCode, FooInfo> queryFooInfo(); }
-
Implements it:
import com.github.jasonnming.results.result.support.Results; class FooClientImpl implements FooClient { @Override public SingleResult<FooResultCode, FooInfo> queryFooInfo() { FooInfo fooInfo = ...; return Results.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:
import com.github.jasonnming.results.result.support.Results; @RestController class FooController { @GetMapping("/foo") public Object queryFooInfo() { FooInfo fooInfo = ...; return Results.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
<bean id="resultInterceptor" class="com.github.jasonnming.results.result.support.ResultInterceptor"/> <aop:config> <!-- RPC support --> <aop:advisor advice-ref="resultInterceptor" pointcut="execution(* foo.client..*Client.*(..))"/> <!-- REST support --> <aop:advisor advice-ref="resultInterceptor" pointcut="@target(org.springframework.web.bind.annotation.RestController)"/> </aop:config>
-
Using Java-config (Spring-boot)
import com.github.jasonnming.results.result.support.ResultInterceptor; import org.springframework.aop.Advisor; import org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; @Configuration @EnableAspectJAutoProxy class FooConfig { @Bean Advisor rpcInterceptor() { final AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor(); { advisor.setExpression("execution(* foo.client..*Client.*(..))"); advisor.setAdvice(new ResultInterceptor()); } return advisor; } @Bean Advisor webInterceptor() { final AspectJExpressionPointcutAdvisor advisor = new AspectJExpressionPointcutAdvisor(); { advisor.setExpression("@target(org.springframework.web.bind.annotation.RestController)"); advisor.setAdvice(new ResultInterceptor()); } return advisor; } // Just register another advisors if necessary. }
-
Using
@Aspect
import com.github.jasonming.results.result.support.MethodReturnWrapper; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; @Aspect class FooAspect { @Pointcut("execution(* foo.client..*Client.*(..))") void rpcPointcut() {} @Pointcut("@target(org.springframework.web.bind.annotation.RestController)") void webPointcut() {} @Around(value = "rpcPointcut() || webPointcut()") Object intercept(final ProceedingJoinPoint joinPoint) throws Throwable { return MethodReturnWrapper.forMethod(((MethodSignature)joinPoint.getSignature()).getMethod()) .wrapInvocation(joinPoint::proceed); } }
Enjoy!