From 211f8ea854bfb7d7424e5bef5a83023be629ec9d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 5 Jan 2012 15:08:06 +0100 Subject: [PATCH 1/8] JBossNativeJdbcExtractor is compatible with JBoss AS 7 as well (SPR-8957) --- .../nativejdbc/JBossNativeJdbcExtractor.java | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) 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); } } From affa733927143407fe997fd2dd843ca4a0920c48 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 5 Jan 2012 15:18:42 +0100 Subject: [PATCH 2/8] Hibernate exception translation covers NonUniqueObjectException to DuplicateKeyException case (SPR-8996) --- .../orm/hibernate3/SessionFactoryUtils.java | 21 ++++++++++++------- .../orm/hibernate4/SessionFactoryUtils.java | 21 ++++++++++++------- 2 files changed, 28 insertions(+), 14 deletions(-) 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); } From adac38f91b0d023db35926ca7d016f6465c78868 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 5 Jan 2012 15:35:28 +0100 Subject: [PATCH 3/8] fixed documented bean class names in jdbc namespace xsd (SPR-8972) --- .../org/springframework/jdbc/config/spring-jdbc-3.0.xsd | 5 ++--- .../org/springframework/jdbc/config/spring-jdbc-3.1.xsd | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) 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. ]]> From e208a2de5f1ddbe9d330a051cc61c2903afbc668 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 5 Jan 2012 17:36:11 +0100 Subject: [PATCH 4/8] JBoss AS 7, etc --- build-spring-framework/resources/changelog.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From 66d4e45b58b626e7fdd3f25206e06a20694a99e5 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Fri, 6 Jan 2012 18:12:25 +0200 Subject: [PATCH 5/8] add getCacheManager() for access to native class --- .../cache/ehcache/EhCacheCacheManager.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) 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 From a4b33533d3608c2124c076476ed8835273582ec0 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Fri, 6 Jan 2012 17:54:00 -0500 Subject: [PATCH 6/8] SPR-9001 Javadoc fix --- .../web/servlet/mvc/condition/ConsumesRequestCondition.java | 4 ++-- .../web/servlet/mvc/condition/HeadersRequestCondition.java | 4 ++-- .../web/servlet/mvc/condition/ParamsRequestCondition.java | 4 ++-- .../servlet/mvc/condition/RequestMethodsRequestCondition.java | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) 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 From fe0ffec8b93305a78274e3fc9f78edc584187141 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 9 Jan 2012 19:13:50 -0500 Subject: [PATCH 7/8] SPR-7799 Minor fix in documentation. --- spring-framework-reference/src/view.xml | 4 ++++ 1 file changed, 4 insertions(+) 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 From 66df039b03347c4e01fa5965754eba90316999f7 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 9 Jan 2012 20:18:44 -0500 Subject: [PATCH 8/8] SPR-8698 Support flash attrs and a ModelAndView return value. Before this change, flash attributes could only be added if via RedirectAttributes.addFlashAttribute(..) if the method returned a view name or a View instance. With this change, the above is supported with a ModelAndView return value as well. --- .../ModelAndViewMethodReturnValueHandler.java | 28 ++++++-- ...lAndViewMethodReturnValueHandlerTests.java | 67 ++++++++++++++++--- 2 files changed, 79 insertions(+), 16 deletions(-) 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);