diff --git a/build-spring-framework/resources/changelog.txt b/build-spring-framework/resources/changelog.txt index 73b3466171e..2a723d7b2cf 100644 --- a/build-spring-framework/resources/changelog.txt +++ b/build-spring-framework/resources/changelog.txt @@ -3,10 +3,11 @@ SPRING FRAMEWORK CHANGELOG http://www.springsource.org -Changes in version 3.1.1 (2012-01-16) +Changes in version 3.1.1 (2012-02-06) ------------------------------------- * official support for Hibernate 4.0 GA +* JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well * context:property-placeholder's "file-encoding" attribute value is being applied correctly * DataBinder correctly handles ParseException from Formatter for String->String case * CacheNamespaceHandler actually parses cache:annotation-driven's "key-generator" attribute @@ -14,6 +15,7 @@ Changes in version 3.1.1 (2012-01-16) * fixed LocalContainerEntityManagerFactoryBean's "packagesToScan" to avoid additional provider scan * added protected "isPersistenceUnitOverrideAllowed()" method to DefaultPersistenceUnitManager * Hibernate synchronization properly unbinds Session even in case of afterCompletion exception +* Hibernate exception translation covers NonUniqueObjectException to DuplicateKeyException case * Hibernate 4 LocalSessionFactoryBean implements PersistenceExceptionTranslator interface as well * Hibernate 4 LocalSessionFactoryBean does not insist on a "dataSource" reference being set * added "entityInterceptor" property to Hibernate 4 LocalSessionFactoryBean diff --git a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java index 2004597ef73..2fb21c7e637 100644 --- a/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java +++ b/org.springframework.context/src/main/java/org/springframework/cache/ehcache/EhCacheCacheManager.java @@ -39,7 +39,15 @@ public class EhCacheCacheManager extends AbstractCacheManager { /** - * Set the backing EhCache {@link net.sf.ehcache.CacheManager}. + * Returns the backing Ehcache {@link net.sf.ehcache.CacheManager}. + * @return + */ + public net.sf.ehcache.CacheManager getCacheManager() { + return cacheManager; + } + + /** + * Sets the backing EhCache {@link net.sf.ehcache.CacheManager}. */ public void setCacheManager(net.sf.ehcache.CacheManager cacheManager) { this.cacheManager = cacheManager; @@ -75,5 +83,4 @@ public class EhCacheCacheManager extends AbstractCacheManager { } return cache; } - -} +} \ No newline at end of file diff --git a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/JBossNativeJdbcExtractor.java b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/JBossNativeJdbcExtractor.java index 52b4a55e4e7..d5f24aaee1d 100644 --- a/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/JBossNativeJdbcExtractor.java +++ b/org.springframework.jdbc/src/main/java/org/springframework/jdbc/support/nativejdbc/JBossNativeJdbcExtractor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,8 @@ import org.springframework.util.ReflectionUtils; /** * Implementation of the {@link NativeJdbcExtractor} interface for JBoss, - * supporting JBoss Application Server 3.2.4+. + * supporting JBoss Application Server 3.2.4+. As of Spring 3.1.1, it also + * supports JBoss 7. * *

Returns the underlying native Connection, Statement, etc to * application code instead of JBoss' wrapper implementations. @@ -47,11 +48,11 @@ import org.springframework.util.ReflectionUtils; */ public class JBossNativeJdbcExtractor extends NativeJdbcExtractorAdapter { - private static final String WRAPPED_CONNECTION_NAME = "org.jboss.resource.adapter.jdbc.WrappedConnection"; + // JBoss 7 + private static final String JBOSS_JCA_PREFIX = "org.jboss.jca.adapters.jdbc."; - private static final String WRAPPED_STATEMENT_NAME = "org.jboss.resource.adapter.jdbc.WrappedStatement"; - - private static final String WRAPPED_RESULT_SET_NAME = "org.jboss.resource.adapter.jdbc.WrappedResultSet"; + // JBoss <= 6 + private static final String JBOSS_RESOURCE_PREFIX = "org.jboss.resource.adapter.jdbc."; private Class wrappedConnectionClass; @@ -72,10 +73,26 @@ public class JBossNativeJdbcExtractor extends NativeJdbcExtractorAdapter { * so we can get the underlying vendor connection using reflection. */ public JBossNativeJdbcExtractor() { + String prefix = JBOSS_JCA_PREFIX; + try { + // trying JBoss 7 jca package first... + this.wrappedConnectionClass = getClass().getClassLoader().loadClass(prefix + "WrappedConnection"); + } + catch (ClassNotFoundException ex) { + // JBoss 7 jca package not found -> try traditional resource package. + prefix = JBOSS_RESOURCE_PREFIX; + try { + this.wrappedConnectionClass = getClass().getClassLoader().loadClass(prefix + "WrappedConnection"); + } + catch (ClassNotFoundException ex2) { + throw new IllegalStateException("Could not initialize JBossNativeJdbcExtractor: neither JBoss 7's [" + + JBOSS_JCA_PREFIX + ".WrappedConnection] nor traditional JBoss [" + JBOSS_RESOURCE_PREFIX + + ".WrappedConnection] found"); + } + } try { - this.wrappedConnectionClass = getClass().getClassLoader().loadClass(WRAPPED_CONNECTION_NAME); - this.wrappedStatementClass = getClass().getClassLoader().loadClass(WRAPPED_STATEMENT_NAME); - this.wrappedResultSetClass = getClass().getClassLoader().loadClass(WRAPPED_RESULT_SET_NAME); + this.wrappedStatementClass = getClass().getClassLoader().loadClass(prefix + "WrappedStatement"); + this.wrappedResultSetClass = getClass().getClassLoader().loadClass(prefix + "WrappedResultSet"); this.getUnderlyingConnectionMethod = this.wrappedConnectionClass.getMethod("getUnderlyingConnection", (Class[]) null); this.getUnderlyingStatementMethod = @@ -85,7 +102,7 @@ public class JBossNativeJdbcExtractor extends NativeJdbcExtractorAdapter { } catch (Exception ex) { throw new IllegalStateException( - "Could not initialize JBossNativeJdbcExtractor because JBoss API classes are not available: " + ex); + "Could not initialize JBossNativeJdbcExtractor because of missing JBoss API methods/classes: " + ex); } } diff --git a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd index 9c25333a08e..72c896051f9 100644 --- a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd +++ b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.0.xsd @@ -12,8 +12,7 @@ - @@ -48,7 +47,7 @@ - elements. ]]> diff --git a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd index 8eef9cb6fb2..cc1fb608d8d 100644 --- a/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd +++ b/org.springframework.jdbc/src/main/resources/org/springframework/jdbc/config/spring-jdbc-3.1.xsd @@ -12,7 +12,7 @@ - @@ -47,7 +47,7 @@ - elements. ]]> diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java index 44c528df6c2..0fbddd87f7b 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate3/SessionFactoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,6 +32,7 @@ import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Interceptor; import org.hibernate.JDBCException; +import org.hibernate.NonUniqueObjectException; import org.hibernate.NonUniqueResultException; import org.hibernate.ObjectDeletedException; import org.hibernate.PersistentObjectException; @@ -58,6 +59,7 @@ import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessResourceUsageException; @@ -648,6 +650,17 @@ public abstract class SessionFactoryUtils { if (ex instanceof JDBCException) { return new HibernateJdbcException((JDBCException) ex); } + // end of JDBCException (subclass) handling + + if (ex instanceof QueryException) { + return new HibernateQueryException((QueryException) ex); + } + if (ex instanceof NonUniqueResultException) { + return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); + } + if (ex instanceof NonUniqueObjectException) { + return new DuplicateKeyException(ex.getMessage(), ex); + } if (ex instanceof PropertyValueException) { return new DataIntegrityViolationException(ex.getMessage(), ex); } @@ -660,18 +673,12 @@ public abstract class SessionFactoryUtils { if (ex instanceof ObjectDeletedException) { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } - if (ex instanceof QueryException) { - return new HibernateQueryException((QueryException) ex); - } if (ex instanceof UnresolvableObjectException) { return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); } if (ex instanceof WrongClassException) { return new HibernateObjectRetrievalFailureException((WrongClassException) ex); } - if (ex instanceof NonUniqueResultException) { - return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); - } if (ex instanceof StaleObjectStateException) { return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); } diff --git a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SessionFactoryUtils.java b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SessionFactoryUtils.java index 0cdffdc2c54..db67bb66bda 100644 --- a/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SessionFactoryUtils.java +++ b/org.springframework.orm/src/main/java/org/springframework/orm/hibernate4/SessionFactoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2012 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.HibernateException; import org.hibernate.JDBCException; +import org.hibernate.NonUniqueObjectException; import org.hibernate.NonUniqueResultException; import org.hibernate.ObjectDeletedException; import org.hibernate.PersistentObjectException; @@ -47,6 +48,7 @@ import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.DuplicateKeyException; import org.springframework.dao.IncorrectResultSizeDataAccessException; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessResourceUsageException; @@ -164,6 +166,17 @@ public abstract class SessionFactoryUtils { if (ex instanceof JDBCException) { return new HibernateJdbcException((JDBCException) ex); } + // end of JDBCException (subclass) handling + + if (ex instanceof QueryException) { + return new HibernateQueryException((QueryException) ex); + } + if (ex instanceof NonUniqueResultException) { + return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); + } + if (ex instanceof NonUniqueObjectException) { + return new DuplicateKeyException(ex.getMessage(), ex); + } if (ex instanceof PropertyValueException) { return new DataIntegrityViolationException(ex.getMessage(), ex); } @@ -176,18 +189,12 @@ public abstract class SessionFactoryUtils { if (ex instanceof ObjectDeletedException) { return new InvalidDataAccessApiUsageException(ex.getMessage(), ex); } - if (ex instanceof QueryException) { - return new HibernateQueryException((QueryException) ex); - } if (ex instanceof UnresolvableObjectException) { return new HibernateObjectRetrievalFailureException((UnresolvableObjectException) ex); } if (ex instanceof WrongClassException) { return new HibernateObjectRetrievalFailureException((WrongClassException) ex); } - if (ex instanceof NonUniqueResultException) { - return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex); - } if (ex instanceof StaleObjectStateException) { return new HibernateOptimisticLockingFailureException((StaleObjectStateException) ex); } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java index a98b7f18ecc..8de3ddd4318 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ConsumesRequestCondition.java @@ -173,8 +173,8 @@ public final class ConsumesRequestCondition extends AbstractRequestCondition *

  • 0 if the two conditions have the same number of expressions - *
  • Less than 1 if "this" has more or more specific media type expressions - *
  • Greater than 1 if "other" has more or more specific media type expressions + *
  • Less than 0 if "this" has more or more specific media type expressions + *
  • Greater than 0 if "other" has more or more specific media type expressions * * *

    It is assumed that both instances have been obtained via diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/HeadersRequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/HeadersRequestCondition.java index 911cbbb5763..ab005ad2bf6 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/HeadersRequestCondition.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/HeadersRequestCondition.java @@ -114,8 +114,8 @@ public final class HeadersRequestCondition extends AbstractRequestCondition *

  • 0 if the two conditions have the same number of header expressions - *
  • Less than 1 if "this" instance has more header expressions - *
  • Greater than 1 if the "other" instance has more header expressions + *
  • Less than 0 if "this" instance has more header expressions + *
  • Greater than 0 if the "other" instance has more header expressions * * *

    It is assumed that both instances have been obtained via diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java index 46e74843c56..c4c199133d5 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/ParamsRequestCondition.java @@ -105,8 +105,8 @@ public final class ParamsRequestCondition extends AbstractRequestCondition *

  • 0 if the two conditions have the same number of parameter expressions - *
  • Less than 1 if "this" instance has more parameter expressions - *
  • Greater than 1 if the "other" instance has more parameter expressions + *
  • Less than 0 if "this" instance has more parameter expressions + *
  • Greater than 0 if the "other" instance has more parameter expressions * * *

    It is assumed that both instances have been obtained via diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java index 1b4d1b61a56..3670a7f0cfd 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestMethodsRequestCondition.java @@ -111,8 +111,8 @@ public final class RequestMethodsRequestCondition extends AbstractRequestConditi * Returns: *

    * *

    It is assumed that both instances have been obtained via diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java index 661e403b724..b5494f50614 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandler.java @@ -21,6 +21,8 @@ import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.ModelAndView; +import org.springframework.web.servlet.SmartView; +import org.springframework.web.servlet.View; /** * Handles return values of type {@link ModelAndView} copying view and model @@ -48,17 +50,29 @@ public class ModelAndViewMethodReturnValueHandler implements HandlerMethodReturn MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { - if (returnValue != null) { - ModelAndView mav = (ModelAndView) returnValue; - mavContainer.setViewName(mav.getViewName()); - if (!mav.isReference()) { - mavContainer.setView(mav.getView()); + if (returnValue == null) { + mavContainer.setRequestHandled(true); + return; + } + + ModelAndView mav = (ModelAndView) returnValue; + if (mav.isReference()) { + String viewName = mav.getViewName(); + mavContainer.setViewName(viewName); + if (viewName != null && viewName.startsWith("redirect:")) { + mavContainer.setRedirectModelScenario(true); } - mavContainer.addAllAttributes(mav.getModel()); } else { - mavContainer.setRequestHandled(true); + View view = mav.getView(); + mavContainer.setView(view); + if (view instanceof SmartView) { + if (((SmartView) view).isRedirectView()) { + mavContainer.setRedirectModelScenario(true); + } + } } + mavContainer.addAllAttributes(mav.getModel()); } } \ No newline at end of file diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java index cb99e9566b7..cfec1453542 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ModelAndViewMethodReturnValueHandlerTests.java @@ -18,6 +18,8 @@ package org.springframework.web.servlet.mvc.method.annotation; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.lang.reflect.Method; @@ -26,10 +28,11 @@ import org.junit.Before; import org.junit.Test; import org.springframework.core.MethodParameter; import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.ui.ModelMap; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler; +import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap; import org.springframework.web.servlet.view.RedirectView; /** @@ -45,44 +48,90 @@ public class ModelAndViewMethodReturnValueHandlerTests { private ServletWebRequest webRequest; + private MethodParameter returnParamModelAndView; + @Before - public void setUp() { + public void setUp() throws Exception { this.handler = new ModelAndViewMethodReturnValueHandler(); this.mavContainer = new ModelAndViewContainer(); this.webRequest = new ServletWebRequest(new MockHttpServletRequest()); + this.returnParamModelAndView = getReturnValueParam("modelAndView"); } @Test public void supportsReturnType() throws Exception { - assertTrue(handler.supportsReturnType(getReturnValueParam("modelAndView"))); + assertTrue(handler.supportsReturnType(returnParamModelAndView)); assertFalse(handler.supportsReturnType(getReturnValueParam("viewName"))); } @Test - public void handleReturnValueViewName() throws Exception { + public void handleViewReference() throws Exception { ModelAndView mav = new ModelAndView("viewName", "attrName", "attrValue"); - handler.handleReturnValue(mav, getReturnValueParam("modelAndView"), mavContainer, webRequest); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); assertEquals("viewName", mavContainer.getView()); assertEquals("attrValue", mavContainer.getModel().get("attrName")); } @Test - public void handleReturnValueView() throws Exception { + public void handleViewInstance() throws Exception { ModelAndView mav = new ModelAndView(new RedirectView(), "attrName", "attrValue"); - handler.handleReturnValue(mav, getReturnValueParam("modelAndView"), mavContainer, webRequest); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); assertEquals(RedirectView.class, mavContainer.getView().getClass()); assertEquals("attrValue", mavContainer.getModel().get("attrName")); } @Test - public void handleReturnValueNull() throws Exception { - handler.handleReturnValue(null, getReturnValueParam("modelAndView"), mavContainer, webRequest); + public void handleNull() throws Exception { + handler.handleReturnValue(null, returnParamModelAndView, mavContainer, webRequest); assertTrue(mavContainer.isRequestHandled()); } + @Test + public void handleRedirectAttributesWithViewReference() throws Exception { + RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap(); + mavContainer.setRedirectModel(redirectAttributes); + + ModelAndView mav = new ModelAndView(new RedirectView(), "attrName", "attrValue"); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); + + assertEquals(RedirectView.class, mavContainer.getView().getClass()); + assertEquals("attrValue", mavContainer.getModel().get("attrName")); + assertSame("RedirectAttributes should be used if controller redirects", redirectAttributes, + mavContainer.getModel()); + } + + @Test + public void handleRedirectAttributesWithViewInstance() throws Exception { + RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap(); + mavContainer.setRedirectModel(redirectAttributes); + + ModelAndView mav = new ModelAndView("redirect:viewName", "attrName", "attrValue"); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); + + ModelMap model = mavContainer.getModel(); + assertEquals("redirect:viewName", mavContainer.getViewName()); + assertEquals("attrValue", model.get("attrName")); + assertSame("RedirectAttributes should be used if controller redirects", redirectAttributes, model); + } + + @Test + public void handleRedirectAttributesWithoutRedirect() throws Exception { + RedirectAttributesModelMap redirectAttributes = new RedirectAttributesModelMap(); + mavContainer.setRedirectModel(redirectAttributes); + + ModelAndView mav = new ModelAndView(); + handler.handleReturnValue(mav, returnParamModelAndView, mavContainer, webRequest); + + ModelMap model = mavContainer.getModel(); + assertEquals(null, mavContainer.getView()); + assertTrue(mavContainer.getModel().isEmpty()); + assertNotSame("RedirectAttributes should not be used if controller doesn't redirect", redirectAttributes, model); + } + + private MethodParameter getReturnValueParam(String methodName) throws Exception { Method method = getClass().getDeclaredMethod(methodName); return new MethodParameter(method, -1); diff --git a/spring-framework-reference/src/view.xml b/spring-framework-reference/src/view.xml index 452fdf4d086..b9e27ed603f 100644 --- a/spring-framework-reference/src/view.xml +++ b/spring-framework-reference/src/view.xml @@ -707,6 +707,10 @@ productList.url=/WEB-INF/jsp/productlist.jsp path="lastName" - displays all errors associated with the lastName field + + + if path is omitted - object errors only are displayed + The example below will display a list of errors at the top of