diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java index f5b170855fb..386ca7969f2 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HandlerMethodAnnotationDetectionTests.java @@ -18,8 +18,6 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.lang.reflect.Method; import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Collection; import java.util.Date; import org.junit.Test; @@ -77,6 +75,13 @@ public class HandlerMethodAnnotationDetectionTests { { ParameterizedAbstractClassController.class, true }, // CGLib proxy { ParameterizedAbstractClassController.class, false }, + { ParameterizedSubclassOverridesDefaultMappings.class, true }, // CGLib proxy + { ParameterizedSubclassOverridesDefaultMappings.class, false }, + + // TODO [SPR-9517] Enable ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass test cases + // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, true }, // CGLib proxy + // { ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass.class, false }, + { InterfaceController.class, true }, // JDK dynamic proxy { InterfaceController.class, false }, @@ -138,8 +143,8 @@ public class HandlerMethodAnnotationDetectionTests { ModelAndView mav = handlerAdapter.handle(request, new MockHttpServletResponse(), chain.getHandler()); - assertEquals(mav.getModel().get("attr1"), dateFormat.parse(dateA)); - assertEquals(mav.getModel().get("attr2"), dateFormat.parse(dateB)); + assertEquals("model attr1:", dateFormat.parse(dateA), mav.getModel().get("attr1")); + assertEquals("model attr2:", dateFormat.parse(dateB), mav.getModel().get("attr2")); MockHttpServletResponse response = new MockHttpServletResponse(); exceptionResolver.resolveException(request, response, chain.getHandler(), new Exception("failure")); @@ -281,7 +286,7 @@ public class HandlerMethodAnnotationDetectionTests { @Controller - static abstract class MappingParameterizedAbstractClass { + static abstract class MappingGenericAbstractClass { @InitBinder public abstract void initBinder(WebDataBinder dataBinder, A thePattern); @@ -303,7 +308,93 @@ public class HandlerMethodAnnotationDetectionTests { * *

All annotations can be on methods in the abstract class except parameter annotations. */ - static class ParameterizedAbstractClassController extends MappingParameterizedAbstractClass { + static class ParameterizedAbstractClassController extends MappingGenericAbstractClass { + + @Override + public void initBinder(WebDataBinder dataBinder, @RequestParam("datePattern") String thePattern) { + CustomDateEditor dateEditor = new CustomDateEditor(new SimpleDateFormat(thePattern), false); + dataBinder.registerCustomEditor(Date.class, dateEditor); + } + + @Override + public void initModel(@RequestHeader("header1") Date date, Model model) { + model.addAttribute("attr1", date); + } + + @Override + public Date handle(@RequestHeader("header2") Date date, Model model) throws Exception { + return date; + } + + @Override + public String handleException(Exception exception) { + return exception.getMessage(); + } + } + + @Controller + static abstract class MappedGenericAbstractClassWithConcreteImplementations { + + @InitBinder + public abstract void initBinder(WebDataBinder dataBinder, A thePattern); + + @ModelAttribute + public abstract void initModel(B date, Model model); + + @RequestMapping(value = "/path1/path2", method = RequestMethod.POST) + @ModelAttribute("attr2") + public Date handle(C date, Model model) throws Exception { + return (Date) date; + } + + @ExceptionHandler(Exception.class) + @ResponseBody + public abstract String handleException(Exception exception); + } + + static class ParameterizedSubclassDoesNotOverrideConcreteImplementationsFromGenericAbstractSuperclass extends + MappedGenericAbstractClassWithConcreteImplementations { + + @Override + public void initBinder(WebDataBinder dataBinder, @RequestParam("datePattern") String thePattern) { + CustomDateEditor dateEditor = new CustomDateEditor(new SimpleDateFormat(thePattern), false); + dataBinder.registerCustomEditor(Date.class, dateEditor); + } + + @Override + public void initModel(@RequestHeader("header1") Date date, Model model) { + model.addAttribute("attr1", date); + } + + // does not override handle() + + @Override + public String handleException(Exception exception) { + return exception.getMessage(); + } + } + + @Controller + static abstract class GenericAbstractClassDeclaresDefaultMappings { + + @InitBinder + public abstract void initBinder(WebDataBinder dataBinder, A thePattern); + + @ModelAttribute + public abstract void initModel(B date, Model model); + + // /foo/bar should be overridden in concrete subclass + @RequestMapping(value = "/foo/bar", method = RequestMethod.POST) + // attrFoo should be overridden in concrete subclass + @ModelAttribute("attrFoo") + public abstract Date handle(C date, Model model) throws Exception; + + @ExceptionHandler(Exception.class) + @ResponseBody + public abstract String handleException(Exception exception); + } + + static class ParameterizedSubclassOverridesDefaultMappings extends GenericAbstractClassDeclaresDefaultMappings { @Override public void initBinder(WebDataBinder dataBinder, @RequestParam("datePattern") String thePattern) { @@ -317,6 +408,11 @@ public class HandlerMethodAnnotationDetectionTests { } @Override + @RequestMapping(value = "/path1/path2", method = RequestMethod.POST) + // NOTE: @ModelAttribute will NOT be found on the abstract superclass if + // @RequestMapping is declared locally. Thus, we have to redeclare + // @ModelAttribute locally as well. + @ModelAttribute("attr2") public Date handle(@RequestHeader("header2") Date date, Model model) throws Exception { return date; } @@ -328,7 +424,7 @@ public class HandlerMethodAnnotationDetectionTests { } @RequestMapping - static interface MappingParameterizedInterface { + static interface MappingGenericInterface { @InitBinder void initBinder(WebDataBinder dataBinder, A thePattern); @@ -352,7 +448,7 @@ public class HandlerMethodAnnotationDetectionTests { * *

Cannot be used as JDK dynamic proxy since parameterized interface does not contain type information. */ - static class ParameterizedInterfaceController implements MappingParameterizedInterface { + static class ParameterizedInterfaceController implements MappingGenericInterface { @Override @InitBinder