Skip to content

Commit a780668

Browse files
committed
Retrieve newly created attribute from underlying request (marking it for update)
Issue: SPR-15300 (cherry picked from commit f30c498)
1 parent 77c771e commit a780668

File tree

2 files changed

+54
-4
lines changed

2 files changed

+54
-4
lines changed

spring-web/src/main/java/org/springframework/web/context/request/AbstractRequestAttributesScope.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -43,6 +43,14 @@ public Object get(String name, ObjectFactory<?> objectFactory) {
4343
if (scopedObject == null) {
4444
scopedObject = objectFactory.getObject();
4545
attributes.setAttribute(name, scopedObject, getScope());
46+
// Retrieve object again, registering it for implicit session attribute updates.
47+
// As a bonus, we also allow for potential decoration at the getAttribute level.
48+
Object retrievedObject = attributes.getAttribute(name, getScope());
49+
if (retrievedObject != null) {
50+
// Only proceed with retrieved object if still present (the expected case).
51+
// If it disappeared concurrently, we return our locally created instance.
52+
scopedObject = retrievedObject;
53+
}
4654
}
4755
return scopedObject;
4856
}

spring-web/src/test/java/org/springframework/web/context/request/SessionScopeTests.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
package org.springframework.web.context.request;
1818

1919
import java.io.Serializable;
20+
import java.util.concurrent.atomic.AtomicInteger;
2021

2122
import org.junit.After;
2223
import org.junit.Before;
@@ -48,7 +49,7 @@ public class SessionScopeTests {
4849

4950

5051
@Before
51-
public void setUp() throws Exception {
52+
public void setup() throws Exception {
5253
this.beanFactory.registerScope("session", new SessionScope());
5354
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this.beanFactory);
5455
reader.loadBeanDefinitions(new ClassPathResource("sessionScopeTests.xml", getClass()));
@@ -59,9 +60,17 @@ public void resetRequestAttributes() {
5960
RequestContextHolder.setRequestAttributes(null);
6061
}
6162

63+
6264
@Test
6365
public void getFromScope() throws Exception {
64-
MockHttpSession session = new MockHttpSession();
66+
AtomicInteger count = new AtomicInteger();
67+
MockHttpSession session = new MockHttpSession() {
68+
@Override
69+
public void setAttribute(String name, Object value) {
70+
super.setAttribute(name, value);
71+
count.incrementAndGet();
72+
}
73+
};
6574
MockHttpServletRequest request = new MockHttpServletRequest();
6675
request.setSession(session);
6776
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
@@ -70,8 +79,41 @@ public void getFromScope() throws Exception {
7079
String name = "sessionScopedObject";
7180
assertNull(session.getAttribute(name));
7281
TestBean bean = (TestBean) this.beanFactory.getBean(name);
82+
assertEquals(1, count.intValue());
7383
assertEquals(session.getAttribute(name), bean);
7484
assertSame(bean, this.beanFactory.getBean(name));
85+
assertEquals(1, count.intValue());
86+
87+
// should re-propagate updated attribute
88+
requestAttributes.requestCompleted();
89+
assertEquals(session.getAttribute(name), bean);
90+
assertEquals(2, count.intValue());
91+
}
92+
93+
@Test
94+
public void getFromScopeWithSingleAccess() throws Exception {
95+
AtomicInteger count = new AtomicInteger();
96+
MockHttpSession session = new MockHttpSession() {
97+
@Override
98+
public void setAttribute(String name, Object value) {
99+
super.setAttribute(name, value);
100+
count.incrementAndGet();
101+
}
102+
};
103+
MockHttpServletRequest request = new MockHttpServletRequest();
104+
request.setSession(session);
105+
ServletRequestAttributes requestAttributes = new ServletRequestAttributes(request);
106+
107+
RequestContextHolder.setRequestAttributes(requestAttributes);
108+
String name = "sessionScopedObject";
109+
assertNull(session.getAttribute(name));
110+
TestBean bean = (TestBean) this.beanFactory.getBean(name);
111+
assertEquals(1, count.intValue());
112+
113+
// should re-propagate updated attribute
114+
requestAttributes.requestCompleted();
115+
assertEquals(session.getAttribute(name), bean);
116+
assertEquals(2, count.intValue());
75117
}
76118

77119
@Test

0 commit comments

Comments
 (0)