@Test
  public void supportedParameters() throws Exception {
    // Only @ModelAttribute arguments
    assertTrue(processor.supportsParameter(paramNamedValidModelAttr));
    assertTrue(processor.supportsParameter(paramModelAttr));

    assertFalse(processor.supportsParameter(paramErrors));
    assertFalse(processor.supportsParameter(paramInt));
    assertFalse(processor.supportsParameter(paramNonSimpleType));
  }
  @Test
  public void supportedParametersInDefaultResolutionMode() throws Exception {
    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));

    assertFalse(processor.supportsParameter(paramInt));
  }
  @Test
  public void handleNotAnnotatedReturnValue() throws Exception {
    TestBean testBean = new TestBean("expected");
    processor.handleReturnValue(testBean, returnParamNonSimpleType, mavContainer, webRequest);

    assertSame(testBean, mavContainer.getModel().get("testBean"));
  }
  @Test
  public void resolveArgumentOrdering() throws Exception {
    String name = "testBean";
    Object testBean = new TestBean(name);
    mavContainer.addAttribute(name, testBean);
    mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, testBean);

    Object anotherTestBean = new TestBean();
    mavContainer.addAttribute("anotherTestBean", anotherTestBean);

    StubRequestDataBinder dataBinder = new StubRequestDataBinder(testBean, name);
    WebDataBinderFactory binderFactory = createMock(WebDataBinderFactory.class);
    expect(binderFactory.createBinder(webRequest, testBean, name)).andReturn(dataBinder);
    replay(binderFactory);

    processor.resolveArgument(paramModelAttr, mavContainer, webRequest, 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]);
  }
  @Test
  public void resovleArgumentViaDefaultConstructor() throws Exception {
    WebDataBinder dataBinder = new WebRequestDataBinder(null);

    WebDataBinderFactory factory = createMock(WebDataBinderFactory.class);
    expect(factory.createBinder((NativeWebRequest) anyObject(), notNull(), eq("attrName")))
        .andReturn(dataBinder);
    replay(factory);

    processor.resolveArgument(paramNamedValidModelAttr, mavContainer, webRequest, factory);

    verify(factory);
  }
  private void getAttributeFromModel(String expectedAttributeName, MethodParameter param)
      throws Exception {
    Object target = new TestBean();
    mavContainer.addAttribute(expectedAttributeName, target);

    WebDataBinder dataBinder = new WebRequestDataBinder(target);
    WebDataBinderFactory factory = createMock(WebDataBinderFactory.class);
    expect(factory.createBinder(webRequest, target, expectedAttributeName)).andReturn(dataBinder);
    replay(factory);

    processor.resolveArgument(param, mavContainer, webRequest, factory);

    verify(factory);
  }
  @Test(expected = BindException.class)
  public void resovleArgumentBindException() throws Exception {
    String name = "testBean";
    Object target = new TestBean();
    mavContainer.getModel().addAttribute(target);

    StubRequestDataBinder dataBinder = new StubRequestDataBinder(target, name);
    dataBinder.getBindingResult().reject("error");

    WebDataBinderFactory binderFactory = createMock(WebDataBinderFactory.class);
    expect(binderFactory.createBinder(webRequest, target, name)).andReturn(dataBinder);
    replay(binderFactory);

    processor.resolveArgument(paramNonSimpleType, mavContainer, webRequest, binderFactory);
  }
  @Test
  public void resovleArgumentValidation() throws Exception {
    String name = "attrName";
    Object target = new TestBean();
    mavContainer.addAttribute(name, target);

    StubRequestDataBinder dataBinder = new StubRequestDataBinder(target, name);
    WebDataBinderFactory binderFactory = createMock(WebDataBinderFactory.class);
    expect(binderFactory.createBinder(webRequest, target, name)).andReturn(dataBinder);
    replay(binderFactory);

    processor.resolveArgument(paramNamedValidModelAttr, mavContainer, webRequest, binderFactory);

    assertTrue(dataBinder.isBindInvoked());
    assertTrue(dataBinder.isValidateInvoked());
  }
 @Test
 public void handleAnnotatedReturnValue() throws Exception {
   processor.handleReturnValue("expected", returnParamNamedModelAttr, mavContainer, webRequest);
   assertEquals("expected", mavContainer.getModel().get("modelAttrName"));
 }
 @Test
 public void bindExceptionNotRequired() throws Exception {
   assertFalse(processor.isBindExceptionRequired(null, paramNamedValidModelAttr));
 }
 @Test
 public void bindExceptionRequired() throws Exception {
   assertTrue(processor.isBindExceptionRequired(null, paramNonSimpleType));
 }
 @Test
 public void supportedReturnTypesInDefaultResolutionMode() throws Exception {
   processor = new ModelAttributeMethodProcessor(true);
   assertTrue(processor.supportsReturnType(returnParamNamedModelAttr));
   assertTrue(processor.supportsReturnType(returnParamNonSimpleType));
 }
 @Test
 public void supportedReturnTypes() throws Exception {
   processor = new ModelAttributeMethodProcessor(false);
   assertTrue(processor.supportsReturnType(returnParamNamedModelAttr));
   assertFalse(processor.supportsReturnType(returnParamNonSimpleType));
 }