Skip to content

Commit ea05e0b

Browse files
committed
Improve @SessionAttributes support during redirect
Before this change attributes listed with @SessionAttributes would not be saved in the session when there was a redirect and the controller method declared a parameter of type RedirectAttributes. This change ensures it's the "default" model that is always the one checked for @SessionAttributes under all circumstances since RedirectAttributes is really only meant to provide String values to insert into or append to the the redirect URL. Issue: SPR-12542
1 parent ea2943f commit ea05e0b

File tree

3 files changed

+43
-3
lines changed

3 files changed

+43
-3
lines changed

spring-web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,14 +224,15 @@ public static String getNameForReturnValue(Object returnValue, MethodParameter r
224224
* @throws Exception if creating BindingResult attributes fails
225225
*/
226226
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
227+
ModelMap defaultModel = mavContainer.getDefaultModel();
227228
if (mavContainer.getSessionStatus().isComplete()){
228229
this.sessionAttributesHandler.cleanupAttributes(request);
229230
}
230231
else {
231-
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
232+
this.sessionAttributesHandler.storeAttributes(request, defaultModel);
232233
}
233-
if (!mavContainer.isRequestHandled()) {
234-
updateBindingResult(request, mavContainer.getModel());
234+
if (!mavContainer.isRequestHandled() && mavContainer.getModel() == defaultModel) {
235+
updateBindingResult(request, defaultModel);
235236
}
236237
}
237238

spring-web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,19 @@ private boolean useDefaultModel() {
137137
return (!this.redirectModelScenario || (this.redirectModel == null && !this.ignoreDefaultModelOnRedirect));
138138
}
139139

140+
/**
141+
* Return the "default" model created at instantiation.
142+
* <p>In general it is recommended to use {@link #getModel()} instead which
143+
* returns either the "default" model (template rendering) or the "redirect"
144+
* model (redirect URL preparation). Use of this method may be needed for
145+
* advanced cases when access to the "default" model is needed regardless,
146+
* e.g. to save model attributes specified via {@code @SessionAttributes}.
147+
* @return the default model, never {@code null}
148+
*/
149+
public ModelMap getDefaultModel() {
150+
return this.defaultModel;
151+
}
152+
140153
/**
141154
* Provide a separate model instance to use in a redirect scenario.
142155
* The provided additional model however is not used used unless

spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,32 @@ public void updateModelSessionAttributesRemoved() throws Exception {
215215
assertNull(this.sessionAttributeStore.retrieveAttribute(this.webRequest, attributeName));
216216
}
217217

218+
// SPR-12542
219+
220+
@Test
221+
public void updateModelWhenRedirecting() throws Exception {
222+
String attributeName = "sessionAttr";
223+
String attribute = "value";
224+
ModelAndViewContainer container = new ModelAndViewContainer();
225+
container.addAttribute(attributeName, attribute);
226+
227+
String queryParam = "123";
228+
String queryParamName = "q";
229+
container.setRedirectModel(new ModelMap(queryParamName, queryParam));
230+
container.setRedirectModelScenario(true);
231+
232+
WebDataBinder dataBinder = new WebDataBinder(attribute, attributeName);
233+
WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class);
234+
given(binderFactory.createBinder(this.webRequest, attribute, attributeName)).willReturn(dataBinder);
235+
236+
ModelFactory modelFactory = new ModelFactory(null, binderFactory, this.sessionAttrsHandler);
237+
modelFactory.updateModel(this.webRequest, container);
238+
239+
assertEquals(queryParam, container.getModel().get(queryParamName));
240+
assertEquals(1, container.getModel().size());
241+
assertEquals(attribute, this.sessionAttributeStore.retrieveAttribute(this.webRequest, attributeName));
242+
}
243+
218244

219245
private String bindingResultKey(String key) {
220246
return BindingResult.MODEL_KEY_PREFIX + key;

0 commit comments

Comments
 (0)