为什么不能使用spring AOP更改响应类型,除了return Object

时间:2018-12-04 15:21:55

标签: java spring-mvc spring-boot aspectj spring-aop

我正在使用Spring AOP来切入我的控制器方法,并尝试将常见的结构响应返回到前端。 定义应如下所示:

public class CommonResponse {

private String status;

private String message;

private Object data;
}

我还有一个点定义,如下所示:

@Aspect
@Component
public class PostMessageInterceptor {


@Pointcut("within(org.moa.controller.*)")
public void postMessageConvert() {}

@Around("postMessageConvert()")
public CommonResponse modifyResult(ProceedingJoinPoint pjp) {
    CommonResponse response = new CommonResponse();
    try {
        Object result = pjp.proceed();
        response.setStatus("success");
        response.setData(result);
    }catch(Throwable t) {
        response.setStatus("failure");
        response.setMessage(t.getMessage());
    }
    return response;
}
}

例如,当控制器返回类型中的方法为Map<String,String>时,执行modifyResult后,返回类型已从CommonResponse转换为Map<String,String>,则将发生Spring AOP异常java.lang.ClassCastException: CommonResponse cannot be cast to java.util.Map

如果我将此方法的返回类型更改为Object,它将正常工作。

我只想这样设计吗?否则,有什么方法可以实现我的目标而无需修改Object的返回类型。因为感觉很奇怪,所有方法都返回相同的Object类型。

1 个答案:

答案 0 :(得分:1)

您不能更改包围方法的返回类型。 JVM的机制不允许这样做(请参见this问题的答案)。

您的方法的调用者会根据原始方法的接口编译其代码,但是在执行您的指令后,该方法将返回不同的类型。应该如何工作?

一种可能性是使用接口并返回由您的建议创建的不同实现,例如:

interface MyReturnType {
  int getStatus();
  Map<String, String> getData();
}

class MethodReturnType implements MyReturnType {
  int getStatus() { throw NotImplementedException(); } 
  // should never be called; every other method in the interface can be implemented in the exact same way


  Map<String, String> getData() { return data; } // I omit the constructor and field decleration here
}

class AdviceReturnType implements MyReturnType {
  int status;
  Map<String, String> data;

  int getStatus() { return status; } 
  Map<String, String> getData() { return data; }
}


public MyReturnType myAdvicedMethod(...) {
  // ...
  return new MethodReturnType(myCalculatedData);
}

public Object aroundAdvice(ProceedingJoinPoint pjp) {
  MyReturnType retVal = (MyReturnType) pjp.proceed();
  // calculate status and stuff
  return new AdviceReturnType(retVal.getData(), caluclatedStatus, ...);
}