I'm fighting with AOP and custom error handler. I have one controller "WorkingController" - it is working as expected.
@Controller
public class WorkingController extends BaseController {
@RequestMapping("/welcome")
public ModelAndView helloWorld() {
return new ModelAndView("welcome", "message", "<h3>********** Hello World, Success!</h3>");
}
@RequestMapping("/success")
public void test(HttpServletResponse response) {
writeResponse(response, "Success!", ContentType.TEXT_JSON);
}
@RequestMapping("/test")
public void test2(HttpServletResponse response) throws IOException {
throw new IOException("This exception should be handled by custom handler.");
}
@InterestingMethod
@RequestMapping("/aspect")
public void test3(@InterestingArg @RequestParam(value = "id", required = false) String id,
HttpServletResponse response) throws IOException, AccessDeniedException {
throw new IOException("This exception should also be handled by custom handler.");
}
}
class BaseController {
@ExceptionHandler(Exception.class)
public void handleException(Throwable ex, HttpServletRequest request, HttpServletResponse response) {
System.out.println("Exception handled by BaseController, great work!: " + ex.getMessage());
ServletUtil.writeResponse(response, JSONObject.fromObject("Error").toString(),
ContentType.TEXT_JSON.toString(), false, "UTF-8");
}
void writeResponse(HttpServletResponse response, String data, ContentType contentType) {
ServletUtil.writeResponse(response, data, contentType.toString(), false, "UTF-8");
}
}
My case forces me to create interface, mark my controller and Aspect will check if user has access to given endpoint - so I have MarkedController interface and NotWorkingController.
@Controller
public class NotWorkingController extends BaseController implements MarkedController {
public void test2(HttpServletResponse response) throws IOException {
throw new IOException("NotWorkingController, This exception should be handled by custom handler.");
}
@InterestingMethod
public void test3(@InterestingArg String id,
HttpServletResponse response) throws IOException, AccessDeniedException {
throw new IOException("NotWorkingController, This exception should also be handled by custom handler.");
}
}
@Controller
public interface MarkedController {
@RequestMapping("/test2")
void test2(HttpServletResponse response) throws IOException;
@RequestMapping("/aspect2")
void test3(@RequestParam(value = "id", required = false) String id,
HttpServletResponse response) throws IOException, AccessDeniedException;
}
@Aspect
public class InterestingMethodAspect {
@Pointcut("@annotation(interestingMethod)")
public void interestingMethodPointcut(InterestingMethod interestingMethod) {
}
@Before("(interestingMethodPointcut(interestingMethod))")
public void asd(JoinPoint joinPoint, InterestingMethod interestingMethod) throws AccessDeniedException {
processArguments(joinPoint);
}
private void processArguments(JoinPoint joinPoint) throws AccessDeniedException {
throw new AccessDeniedException("You don't have access to this endpoint.");
}
}
And this is kind of magic for me, because:
So, where should i look, what should I check?
Thanks in advance for any suggestions.
BTW: Complete maven project is available here.
Yhm, and I have the answers.
For the first problem (exception catching):
HandlerExceptionResolver did all what I needed.
I've removed @ExceptionHandler
annotation from handleException
method in BaseController
and custom implementantion of HandlerExceptionResolver
is catching all my exceptions).
Second problem: I had to switch from JDK-based proxies to CGLIB-based one.