Skip to content

Commit 50faabb

Browse files
thomasdarimontodrotbohm
authored andcommitted
spring-projects#119 - Added example for use of SpEL expressions in JPQL update statements.
1 parent fbcded1 commit 50faabb

File tree

3 files changed

+105
-16
lines changed

3 files changed

+105
-16
lines changed

jpa/security/src/main/java/example/springdata/jpa/security/BusinessObject.java

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
*/
1616
package example.springdata.jpa.security;
1717

18-
import javax.persistence.*;
18+
import java.util.Date;
19+
20+
import javax.persistence.Entity;
21+
import javax.persistence.GeneratedValue;
22+
import javax.persistence.Id;
23+
import javax.persistence.ManyToOne;
1924

2025
/**
2126
* @author Thomas Darimont
@@ -26,27 +31,76 @@ public class BusinessObject {
2631
@Id @GeneratedValue Long id;
2732
String data;
2833

34+
@ManyToOne User owner;
35+
36+
String lastModifiedByUsername;
37+
38+
Date lastModifiedDate;
2939

30-
@ManyToOne
31-
User owner;
40+
public BusinessObject() {}
3241

3342
public BusinessObject(String data, User owner) {
3443

3544
this.data = data;
3645
this.owner = owner;
3746
}
47+
48+
public Long getId() {
49+
return id;
50+
}
51+
52+
public void setId(Long id) {
53+
this.id = id;
54+
}
55+
56+
public String getData() {
57+
return data;
58+
}
59+
60+
public void setData(String data) {
61+
this.data = data;
62+
}
63+
64+
public User getOwner() {
65+
return owner;
66+
}
67+
68+
public void setOwner(User owner) {
69+
this.owner = owner;
70+
}
71+
72+
public String getLastModifiedByUsername() {
73+
return lastModifiedByUsername;
74+
}
75+
76+
public void setLastModifiedByUsername(String lastModifiedByUsername) {
77+
this.lastModifiedByUsername = lastModifiedByUsername;
78+
}
79+
80+
public Date getLastModifiedDate() {
81+
return lastModifiedDate;
82+
}
83+
84+
public void setLastModifiedDate(Date lastModifiedDate) {
85+
this.lastModifiedDate = lastModifiedDate;
86+
}
3887

3988
@Override
4089
public boolean equals(Object o) {
4190

42-
if (this == o) return true;
43-
if (o == null || getClass() != o.getClass()) return false;
91+
if (this == o)
92+
return true;
93+
if (o == null || getClass() != o.getClass())
94+
return false;
4495

4596
BusinessObject that = (BusinessObject) o;
4697

47-
if (data != null ? !data.equals(that.data) : that.data != null) return false;
48-
if (id != null ? !id.equals(that.id) : that.id != null) return false;
49-
if (owner != null ? !owner.equals(that.owner) : that.owner != null) return false;
98+
if (data != null ? !data.equals(that.data) : that.data != null)
99+
return false;
100+
if (id != null ? !id.equals(that.id) : that.id != null)
101+
return false;
102+
if (owner != null ? !owner.equals(that.owner) : that.owner != null)
103+
return false;
50104

51105
return true;
52106
}

jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.util.List;
1919

20+
import org.springframework.data.jpa.repository.Modifying;
2021
import org.springframework.data.jpa.repository.Query;
2122
import org.springframework.data.repository.Repository;
2223

@@ -51,4 +52,11 @@ public interface SecureBusinessObjectRepository extends Repository<BusinessObjec
5152
*/
5253
@Query("select o from BusinessObject o where o.owner.id = ?#{principal.id} or 1=?#{hasRole('ROLE_ADMIN') ? 1 : 0}")
5354
List<BusinessObject> findBusinessObjectsForCurrentUserById();
55+
56+
/**
57+
* Here we demonstrate the use of SecurityContext information in dynamic SPEL parameters in a JPAQL update statement.
58+
*/
59+
@Modifying
60+
@Query("update BusinessObject b set b.data = upper(b.data), b.lastModifiedByUsername = :#{#security.principal.firstname}, b.lastModifiedDate = :#{new java.util.Date()}")
61+
void modifiyDataWithRecordingSecurityContext();
5462
}

jpa/security/src/test/java/example/springdata/jpa/security/SecurityIntegrationTests.java

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import java.util.List;
2323

24+
import javax.persistence.EntityManager;
25+
2426
import org.junit.Before;
2527
import org.junit.Test;
2628
import org.junit.runner.RunWith;
@@ -46,10 +48,15 @@ public class SecurityIntegrationTests {
4648
@Autowired UserRepository userRepository;
4749
@Autowired BusinessObjectRepository businessObjectRepository;
4850
@Autowired SecureBusinessObjectRepository secureBusinessObjectRepository;
51+
@Autowired EntityManager em;
4952

5053
User tom;
5154
User olli;
5255
User admin;
56+
57+
UsernamePasswordAuthenticationToken olliAuth;
58+
UsernamePasswordAuthenticationToken tomAuth;
59+
UsernamePasswordAuthenticationToken adminAuth;
5360

5461
BusinessObject object1;
5562
BusinessObject object2;
@@ -65,12 +72,16 @@ public void setup() {
6572
object1 = businessObjectRepository.save(new BusinessObject("object1", olli));
6673
object2 = businessObjectRepository.save(new BusinessObject("object2", olli));
6774
object3 = businessObjectRepository.save(new BusinessObject("object3", tom));
75+
76+
olliAuth = new UsernamePasswordAuthenticationToken(olli, "x");
77+
tomAuth = new UsernamePasswordAuthenticationToken(tom, "x");
78+
adminAuth = new UsernamePasswordAuthenticationToken(admin, "x", singleton(new SimpleGrantedAuthority("ROLE_ADMIN")));
6879
}
6980

7081
@Test
7182
public void findBusinessObjectsForCurrentUserShouldReturnOnlyBusinessObjectsWhereCurrentUserIsOwner() {
7283

73-
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(tom, "x"));
84+
SecurityContextHolder.getContext().setAuthentication(tomAuth);
7485

7586
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUser();
7687

@@ -88,8 +99,7 @@ public void findBusinessObjectsForCurrentUserShouldReturnOnlyBusinessObjectsWher
8899
@Test
89100
public void findBusinessObjectsForCurrentUserShouldReturnAllObjectsForAdmin() {
90101

91-
SecurityContextHolder.getContext().setAuthentication(
92-
new UsernamePasswordAuthenticationToken(admin, "x", singleton(new SimpleGrantedAuthority("ROLE_ADMIN"))));
102+
SecurityContextHolder.getContext().setAuthentication(adminAuth);
93103

94104
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUser();
95105

@@ -100,14 +110,14 @@ public void findBusinessObjectsForCurrentUserShouldReturnAllObjectsForAdmin() {
100110
@Test
101111
public void findBusinessObjectsForCurrentUserByIdShouldReturnOnlyBusinessObjectsWhereCurrentUserIsOwner() {
102112

103-
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(tom, "x"));
113+
SecurityContextHolder.getContext().setAuthentication(tomAuth);
104114

105115
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
106116

107117
assertThat(businessObjects, hasSize(1));
108118
assertThat(businessObjects, contains(object3));
109119

110-
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(olli, "x"));
120+
SecurityContextHolder.getContext().setAuthentication(olliAuth);
111121

112122
businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
113123

@@ -118,13 +128,30 @@ public void findBusinessObjectsForCurrentUserByIdShouldReturnOnlyBusinessObjects
118128
@Test
119129
public void findBusinessObjectsForCurrentUserByIdShouldReturnAllObjectsForAdmin() {
120130

121-
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(admin, "x",
122-
singleton(new SimpleGrantedAuthority("ROLE_ADMIN")));
123-
SecurityContextHolder.getContext().setAuthentication(auth);
131+
SecurityContextHolder.getContext().setAuthentication(adminAuth);
124132

125133
List<BusinessObject> businessObjects = secureBusinessObjectRepository.findBusinessObjectsForCurrentUserById();
126134

127135
assertThat(businessObjects, hasSize(3));
128136
assertThat(businessObjects, contains(object1, object2, object3));
129137
}
138+
139+
@Test
140+
public void customUpdateStatementShouldAllowToUseSecurityContextInformationViaSpelParameters() {
141+
142+
SecurityContextHolder.getContext().setAuthentication(adminAuth);
143+
144+
//Detaching items to get them out of the query cache in order to see the updated values.
145+
em.detach(object1);
146+
em.detach(object2);
147+
em.detach(object3);
148+
149+
secureBusinessObjectRepository.modifiyDataWithRecordingSecurityContext();
150+
151+
for(BusinessObject bo : businessObjectRepository.findAll()) {
152+
153+
assertThat(bo.getLastModifiedDate(), is(notNullValue()));
154+
assertThat(bo.getLastModifiedByUsername(), is("admin"));
155+
}
156+
}
130157
}

0 commit comments

Comments
 (0)