@ -24,6 +24,7 @@ import org.junit.Before;
@@ -24,6 +24,7 @@ import org.junit.Before;
import org.junit.Test ;
import org.springframework.core.MethodParameter ;
import org.springframework.core.annotation.SynthesizingMethodParameter ;
import org.springframework.mock.web.test.MockHttpServletRequest ;
import org.springframework.tests.sample.beans.TestBean ;
import org.springframework.validation.BindException ;
@ -51,56 +52,53 @@ import static org.mockito.BDDMockito.*;
@@ -51,56 +52,53 @@ import static org.mockito.BDDMockito.*;
* /
public class ModelAttributeMethodProcessorTests {
private NativeWebRequest request ;
private ModelAndViewContainer container ;
private ModelAttributeMethodProcessor processor ;
private MethodParameter paramNamedValidModelAttr ;
private MethodParameter paramErrors ;
private MethodParameter paramInt ;
private MethodParameter paramModelAttr ;
private MethodParameter paramNonSimpleType ;
private MethodParameter returnParamNamedModelAttr ;
private MethodParameter returnParamNonSimpleType ;
private ModelAndViewContainer mavContainer ;
private NativeWebRequest webRequest ;
@Before
public void setUp ( ) throws Exception {
processor = new ModelAttributeMethodProcessor ( false ) ;
this . request = new ServletWebRequest ( new MockHttpServletRequest ( ) ) ;
this . container = new ModelAndViewContainer ( ) ;
this . processor = new ModelAttributeMethodProcessor ( false ) ;
Method method = ModelAttributeHandler . class . getDeclaredMethod ( "modelAttribute" ,
TestBean . class , Errors . class , int . class , TestBean . class , TestBean . class ) ;
paramNamedValidModelAttr = new MethodParameter ( method , 0 ) ;
paramErrors = new MethodParameter ( method , 1 ) ;
paramInt = new MethodParameter ( method , 2 ) ;
paramModelAttr = new MethodParameter ( method , 3 ) ;
paramNonSimpleType = new MethodParameter ( method , 4 ) ;
this . paramNamedValidModelAttr = new Synthesizing MethodParameter( method , 0 ) ;
this . paramErrors = new Synthesizing MethodParameter( method , 1 ) ;
this . paramInt = new Synthesizing MethodParameter( method , 2 ) ;
this . paramModelAttr = new Synthesizing MethodParameter( method , 3 ) ;
this . paramNonSimpleType = new Synthesizing MethodParameter( method , 4 ) ;
returnParamNamedModelAttr = new MethodParameter ( getClass ( ) . getDeclaredMethod ( "annotatedReturnValue" ) , - 1 ) ;
returnParamNonSimpleType = new MethodParameter ( getClass ( ) . getDeclaredMethod ( "notAnnotatedReturnValue" ) , - 1 ) ;
method = getClass ( ) . getDeclaredMethod ( "annotatedReturnValue" ) ;
this . returnParamNamedModelAttr = new MethodParameter ( method , - 1 ) ;
mavContainer = new ModelAndViewContainer ( ) ;
webRequest = new ServletWebRequest ( new MockHttpServletRequest ( ) ) ;
method = getClass ( ) . getDeclaredMethod ( "notAnnotatedReturnValue" ) ;
this . returnParamNonSimpleType = new MethodParameter ( method , - 1 ) ;
}
@Test
public void supportedParameters ( ) throws Exception {
// Only @ModelAttribute arguments
assertTrue ( processor . supportsParameter ( paramNamedValidModelAttr ) ) ;
assertTrue ( processor . supportsParameter ( paramModelAttr ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramNamedValidModelAttr ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramModelAttr ) ) ;
assertFalse ( processor . supportsParameter ( paramErrors ) ) ;
assertFalse ( processor . supportsParameter ( paramInt ) ) ;
assertFalse ( processor . supportsParameter ( paramNonSimpleType ) ) ;
assertFalse ( this . processor . supportsParameter ( this . paramErrors ) ) ;
assertFalse ( this . processor . supportsParameter ( this . paramInt ) ) ;
assertFalse ( this . processor . supportsParameter ( this . paramNonSimpleType ) ) ;
}
@Test
@ -108,135 +106,127 @@ public class ModelAttributeMethodProcessorTests {
@@ -108,135 +106,127 @@ public class ModelAttributeMethodProcessorTests {
processor = new ModelAttributeMethodProcessor ( true ) ;
// Only non-simple types, even if not annotated
assertTrue ( processor . supportsParameter ( paramNamedValidModelAttr ) ) ;
assertTrue ( processor . supportsParameter ( paramErrors ) ) ;
assertTrue ( processor . supportsParameter ( paramModelAttr ) ) ;
assertTrue ( processor . supportsParameter ( paramNonSimpleType ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramNamedValidModelAttr ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramErrors ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramModelAttr ) ) ;
assertTrue ( this . processor . supportsParameter ( this . paramNonSimpleType ) ) ;
assertFalse ( processor . supportsParameter ( paramInt ) ) ;
assertFalse ( this . processor . supportsParameter ( this . paramInt ) ) ;
}
@Test
public void supportedReturnTypes ( ) throws Exception {
processor = new ModelAttributeMethodProcessor ( false ) ;
assertTrue ( processor . supportsReturnType ( returnParamNamedModelAttr ) ) ;
assertFalse ( processor . supportsReturnType ( returnParamNonSimpleType ) ) ;
assertTrue ( this . processor . supportsReturnType ( returnParamNamedModelAttr ) ) ;
assertFalse ( this . processor . supportsReturnType ( returnParamNonSimpleType ) ) ;
}
@Test
public void supportedReturnTypesInDefaultResolutionMode ( ) throws Exception {
processor = new ModelAttributeMethodProcessor ( true ) ;
assertTrue ( processor . supportsReturnType ( returnParamNamedModelAttr ) ) ;
assertTrue ( processor . supportsReturnType ( returnParamNonSimpleType ) ) ;
assertTrue ( this . processor . supportsReturnType ( returnParamNamedModelAttr ) ) ;
assertTrue ( this . processor . supportsReturnType ( returnParamNonSimpleType ) ) ;
}
@Test
public void bindExceptionRequired ( ) throws Exception {
assertTrue ( processor . isBindExceptionRequired ( null , paramNonSimpleType ) ) ;
}
@Test
public void bindExceptionNotRequired ( ) throws Exception {
assertFalse ( processor . isBindExceptionRequired ( null , paramNamedValidModelAttr ) ) ;
assertTrue ( this . processor . isBindExceptionRequired ( null , this . paramNonSimpleType ) ) ;
assertFalse ( this . processor . isBindExceptionRequired ( null , this . paramNamedValidModelAttr ) ) ;
}
@Test
public void resovleArgumentFromModel ( ) throws Exception {
getAttributeFromModel ( "attrName" , paramNamedValidModelAttr ) ;
getAttributeFromModel ( "testBean" , paramModelAttr ) ;
getAttributeFromModel ( "testBean" , paramNonSimpleType ) ;
}
private void getAttributeFromModel ( String expectedAttributeName , MethodParameter param ) throws Exception {
Object target = new TestBean ( ) ;
mavContainer . addAttribute ( expectedAttributeName , target ) ;
WebDataBinder dataBinder = new WebRequestDataBinder ( target ) ;
WebDataBinderFactory factory = mock ( WebDataBinderFactory . class ) ;
given ( factory . createBinder ( webRequest , target , expectedAttributeName ) ) . willReturn ( dataBinder ) ;
processor . resolveArgument ( param , mavContainer , webRequest , factory ) ;
verify ( factory ) . createBinder ( webRequest , target , expectedAttributeName ) ;
public void resolveArgumentFromModel ( ) throws Exception {
testGetAttributeFromModel ( "attrName" , this . paramNamedValidModelAttr ) ;
testGetAttributeFromModel ( "testBean" , this . paramModelAttr ) ;
testGetAttributeFromModel ( "testBean" , this . paramNonSimpleType ) ;
}
@Test
public void resovleArgumentViaDefaultConstructor ( ) throws Exception {
WebDataBinder dataBinder = new WebRequestDataBinder ( null ) ;
WebDataBinderFactory factory = mock ( WebDataBinderFactory . class ) ;
given ( factory . createBinder ( ( NativeWebRequest ) anyObject ( ) , notNull ( ) , eq ( "attrName" ) ) ) . willReturn ( dataBinder ) ;
given ( factory . createBinder ( anyObject ( ) , notNull ( ) , eq ( "attrName" ) ) ) . willReturn ( dataBinder ) ;
processor . resolveArgument ( paramNamedValidModelAttr , mavContainer , webRequest , factory ) ;
verify ( factory ) . createBinder ( ( NativeWebRequest ) anyObject ( ) , notNull ( ) , eq ( "attrName" ) ) ;
this . processor . resolveArgument ( this . paramNamedValidModelAttr , this . container , this . request , factory ) ;
verify ( factory ) . createBinder ( anyObject ( ) , notNull ( ) , eq ( "attrName" ) ) ;
}
@Test
public void resolveArgumentValidation ( ) throws Exception {
String name = "attrName" ;
Object target = new TestBean ( ) ;
mavC ontainer. addAttribute ( name , target ) ;
this . c ontainer. addAttribute ( name , target ) ;
StubRequestDataBinder dataBinder = new StubRequestDataBinder ( target , name ) ;
WebDataBinderFactory binderF actory = mock ( WebDataBinderFactory . class ) ;
given ( binderF actory. createBinder ( webR equest, target , name ) ) . willReturn ( dataBinder ) ;
WebDataBinderFactory f actory = mock ( WebDataBinderFactory . class ) ;
given ( f actory. createBinder ( this . r equest, target , name ) ) . willReturn ( dataBinder ) ;
processor . resolveArgument ( paramNamedValidModelAttr , mavContainer , webRequest , binderF actory) ;
this . processor . resolveArgument ( this . paramNamedValidModelAttr , this . container , this . request , f actory) ;
assertTrue ( dataBinder . isBindInvoked ( ) ) ;
assertTrue ( dataBinder . isValidateInvoked ( ) ) ;
}
@Test ( expected = BindException . class )
public void resov leArgumentBindException ( ) throws Exception {
public void resolv eArgumentBindException ( ) throws Exception {
String name = "testBean" ;
Object target = new TestBean ( ) ;
mavC ontainer. getModel ( ) . addAttribute ( target ) ;
this . c ontainer. getModel ( ) . addAttribute ( target ) ;
StubRequestDataBinder dataBinder = new StubRequestDataBinder ( target , name ) ;
dataBinder . getBindingResult ( ) . reject ( "error" ) ;
WebDataBinderFactory binderFactory = mock ( WebDataBinderFactory . class ) ;
given ( binderFactory . createBinder ( webR equest, target , name ) ) . willReturn ( dataBinder ) ;
given ( binderFactory . createBinder ( this . r equest, target , name ) ) . willReturn ( dataBinder ) ;
processor . resolveArgument ( paramNonSimpleType , mavContainer , webR equest, binderFactory ) ;
verify ( binderFactory ) . createBinder ( webR equest, target , name ) ;
this . processor . resolveArgument ( this . paramNonSimpleType , this . container , this . r equest, binderFactory ) ;
verify ( binderFactory ) . createBinder ( this . r equest, target , name ) ;
}
@Test // SPR-9378
public void resolveArgumentOrdering ( ) throws Exception {
String name = "testBean" ;
Object testBean = new TestBean ( name ) ;
mavC ontainer. addAttribute ( name , testBean ) ;
mavC ontainer. addAttribute ( BindingResult . MODEL_KEY_PREFIX + name , testBean ) ;
this . c ontainer. addAttribute ( name , testBean ) ;
this . c ontainer. addAttribute ( BindingResult . MODEL_KEY_PREFIX + name , testBean ) ;
Object anotherTestBean = new TestBean ( ) ;
mavC ontainer. addAttribute ( "anotherTestBean" , anotherTestBean ) ;
this . c ontainer. addAttribute ( "anotherTestBean" , anotherTestBean ) ;
StubRequestDataBinder dataBinder = new StubRequestDataBinder ( testBean , name ) ;
WebDataBinderFactory binderFactory = mock ( WebDataBinderFactory . class ) ;
given ( binderFactory . createBinder ( webR equest, testBean , name ) ) . willReturn ( dataBinder ) ;
given ( binderFactory . createBinder ( this . r equest, testBean , name ) ) . willReturn ( dataBinder ) ;
processor . resolveArgument ( paramModelAttr , mavContainer , webR equest, binderFactory ) ;
this . processor . resolveArgument ( this . paramModelAttr , this . container , this . r equest, binderFactory ) ;
assertSame ( "Resolved attribute should be updated to be last in the order" ,
testBean , mavContainer . getModel ( ) . values ( ) . toArray ( ) [ 1 ] ) ;
assertSame ( "BindingResult of resolved attribute should be last in the order" ,
dataBinder . getBindingResult ( ) , mavContainer . getModel ( ) . values ( ) . toArray ( ) [ 2 ] ) ;
Object [ ] values = this . container . getModel ( ) . values ( ) . toArray ( ) ;
assertSame ( "Resolved attribute should be updated to be last" , testBean , values [ 1 ] ) ;
assertSame ( "BindingResult of resolved attr should be last" , dataBinder . getBindingResult ( ) , values [ 2 ] ) ;
}
@Test
public void handleAnnotatedReturnValue ( ) throws Exception {
processor . handleReturnValue ( "expected" , returnParamNamedModelAttr , mavContainer , webR equest) ;
assertEquals ( "expected" , mavC ontainer. getModel ( ) . get ( "modelAttrName" ) ) ;
this . processor . handleReturnValue ( "expected" , this . returnParamNamedModelAttr , this . container , this . r equest) ;
assertEquals ( "expected" , this . c ontainer. getModel ( ) . get ( "modelAttrName" ) ) ;
}
@Test
public void handleNotAnnotatedReturnValue ( ) throws Exception {
TestBean testBean = new TestBean ( "expected" ) ;
processor . handleReturnValue ( testBean , returnParamNonSimpleType , mavContainer , webRequest ) ;
this . processor . handleReturnValue ( testBean , this . returnParamNonSimpleType , this . container , this . request ) ;
assertSame ( testBean , this . container . getModel ( ) . get ( "testBean" ) ) ;
}
private void testGetAttributeFromModel ( String expectedAttrName , MethodParameter param ) throws Exception {
Object target = new TestBean ( ) ;
this . container . addAttribute ( expectedAttrName , target ) ;
assertSame ( testBean , mavContainer . getModel ( ) . get ( "testBean" ) ) ;
WebDataBinder dataBinder = new WebRequestDataBinder ( target ) ;
WebDataBinderFactory factory = mock ( WebDataBinderFactory . class ) ;
given ( factory . createBinder ( this . request , target , expectedAttrName ) ) . willReturn ( dataBinder ) ;
this . processor . resolveArgument ( param , this . container , this . request , factory ) ;
verify ( factory ) . createBinder ( this . request , target , expectedAttrName ) ;
}
@ -246,6 +236,7 @@ public class ModelAttributeMethodProcessorTests {
@@ -246,6 +236,7 @@ public class ModelAttributeMethodProcessorTests {
private boolean validateInvoked ;
public StubRequestDataBinder ( Object target , String objectName ) {
super ( target , objectName ) ;
}
@ -285,13 +276,17 @@ public class ModelAttributeMethodProcessorTests {
@@ -285,13 +276,17 @@ public class ModelAttributeMethodProcessorTests {
private static class ModelAttributeHandler {
@SuppressWarnings ( "unused" )
public void modelAttribute ( @ModelAttribute ( "attrName" ) @Valid TestBean annotatedAttr , Errors errors ,
int intArg , @ModelAttribute TestBean defaultNameAttr , TestBean notAnnotatedAttr ) {
public void modelAttribute (
@ModelAttribute ( "attrName" ) @Valid TestBean annotatedAttr ,
Errors errors ,
int intArg ,
@ModelAttribute TestBean defaultNameAttr ,
TestBean notAnnotatedAttr ) {
}
}
@ModelAttribute ( "modelAttrName" )
@ModelAttribute ( "modelAttrName" ) @SuppressWarnings ( "unused" )
private String annotatedReturnValue ( ) {
return null ;
}