Skip to content

Commit 9f35deb

Browse files
committed
Unwrap raw target Query instance in case of proxy mismatch
Closes gh-32766 (cherry picked from commit 59a125d)
1 parent 8fe545e commit 9f35deb

File tree

2 files changed

+74
-52
lines changed

2 files changed

+74
-52
lines changed

Diff for: spring-orm/src/main/java/org/springframework/orm/jpa/SharedEntityManagerCreator.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -390,7 +390,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
390390
else if (targetClass.isInstance(proxy)) {
391391
return proxy;
392392
}
393-
break;
393+
else {
394+
return this.target.unwrap(targetClass);
395+
}
394396
case "getOutputParameterValue":
395397
if (this.entityManager == null) {
396398
Object key = args[0];

Diff for: spring-orm/src/test/java/org/springframework/orm/jpa/SharedEntityManagerCreatorTests.java

+70-50
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -38,143 +38,163 @@
3838
import static org.mockito.Mockito.withSettings;
3939

4040
/**
41-
* Unit tests for {@link SharedEntityManagerCreator}.
41+
* Tests for {@link SharedEntityManagerCreator}.
4242
*
4343
* @author Oliver Gierke
4444
* @author Juergen Hoeller
4545
*/
4646
@ExtendWith(MockitoExtension.class)
47-
public class SharedEntityManagerCreatorTests {
47+
class SharedEntityManagerCreatorTests {
4848

4949
@Test
50-
public void proxyingWorksIfInfoReturnsNullEntityManagerInterface() {
50+
void proxyingWorksIfInfoReturnsNullEntityManagerInterface() {
5151
EntityManagerFactory emf = mock(EntityManagerFactory.class,
5252
withSettings().extraInterfaces(EntityManagerFactoryInfo.class));
5353
// EntityManagerFactoryInfo.getEntityManagerInterface returns null
5454
assertThat(SharedEntityManagerCreator.createSharedEntityManager(emf)).isNotNull();
5555
}
5656

5757
@Test
58-
public void transactionRequiredExceptionOnJoinTransaction() {
58+
void transactionRequiredExceptionOnJoinTransaction() {
5959
EntityManagerFactory emf = mock(EntityManagerFactory.class);
6060
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
6161
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(
6262
em::joinTransaction);
6363
}
6464

6565
@Test
66-
public void transactionRequiredExceptionOnFlush() {
66+
void transactionRequiredExceptionOnFlush() {
6767
EntityManagerFactory emf = mock(EntityManagerFactory.class);
6868
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
6969
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(
7070
em::flush);
7171
}
7272

7373
@Test
74-
public void transactionRequiredExceptionOnPersist() {
74+
void transactionRequiredExceptionOnPersist() {
7575
EntityManagerFactory emf = mock(EntityManagerFactory.class);
7676
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
7777
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(() ->
7878
em.persist(new Object()));
7979
}
8080

8181
@Test
82-
public void transactionRequiredExceptionOnMerge() {
82+
void transactionRequiredExceptionOnMerge() {
8383
EntityManagerFactory emf = mock(EntityManagerFactory.class);
8484
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
8585
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(() ->
8686
em.merge(new Object()));
8787
}
8888

8989
@Test
90-
public void transactionRequiredExceptionOnRemove() {
90+
void transactionRequiredExceptionOnRemove() {
9191
EntityManagerFactory emf = mock(EntityManagerFactory.class);
9292
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
9393
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(() ->
9494
em.remove(new Object()));
9595
}
9696

9797
@Test
98-
public void transactionRequiredExceptionOnRefresh() {
98+
void transactionRequiredExceptionOnRefresh() {
9999
EntityManagerFactory emf = mock(EntityManagerFactory.class);
100100
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
101101
assertThatExceptionOfType(TransactionRequiredException.class).isThrownBy(() ->
102102
em.refresh(new Object()));
103103
}
104104

105105
@Test
106-
public void deferredQueryWithUpdate() {
106+
void deferredQueryWithUpdate() {
107107
EntityManagerFactory emf = mock(EntityManagerFactory.class);
108108
EntityManager targetEm = mock(EntityManager.class);
109-
Query query = mock(Query.class);
109+
Query targetQuery = mock(Query.class);
110110
given(emf.createEntityManager()).willReturn(targetEm);
111-
given(targetEm.createQuery("x")).willReturn(query);
111+
given(targetEm.createQuery("x")).willReturn(targetQuery);
112112
given(targetEm.isOpen()).willReturn(true);
113+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
113114

114115
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
115-
em.createQuery("x").executeUpdate();
116+
Query query = em.createQuery("x");
117+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
118+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
119+
assertThat(query.unwrap(Query.class)).isSameAs(query);
120+
query.executeUpdate();
116121

117-
verify(query).executeUpdate();
122+
verify(targetQuery).executeUpdate();
118123
verify(targetEm).close();
119124
}
120125

121126
@Test
122-
public void deferredQueryWithSingleResult() {
127+
void deferredQueryWithSingleResult() {
123128
EntityManagerFactory emf = mock(EntityManagerFactory.class);
124129
EntityManager targetEm = mock(EntityManager.class);
125-
Query query = mock(Query.class);
130+
Query targetQuery = mock(Query.class);
126131
given(emf.createEntityManager()).willReturn(targetEm);
127-
given(targetEm.createQuery("x")).willReturn(query);
132+
given(targetEm.createQuery("x")).willReturn(targetQuery);
128133
given(targetEm.isOpen()).willReturn(true);
134+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
129135

130136
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
131-
em.createQuery("x").getSingleResult();
137+
Query query = em.createQuery("x");
138+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
139+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
140+
assertThat(query.unwrap(Query.class)).isSameAs(query);
141+
query.getSingleResult();
132142

133-
verify(query).getSingleResult();
143+
verify(targetQuery).getSingleResult();
134144
verify(targetEm).close();
135145
}
136146

137147
@Test
138-
public void deferredQueryWithResultList() {
148+
void deferredQueryWithResultList() {
139149
EntityManagerFactory emf = mock(EntityManagerFactory.class);
140150
EntityManager targetEm = mock(EntityManager.class);
141-
Query query = mock(Query.class);
151+
Query targetQuery = mock(Query.class);
142152
given(emf.createEntityManager()).willReturn(targetEm);
143-
given(targetEm.createQuery("x")).willReturn(query);
153+
given(targetEm.createQuery("x")).willReturn(targetQuery);
144154
given(targetEm.isOpen()).willReturn(true);
155+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
145156

146157
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
147-
em.createQuery("x").getResultList();
158+
Query query = em.createQuery("x");
159+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
160+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
161+
assertThat(query.unwrap(Query.class)).isSameAs(query);
162+
query.getResultList();
148163

149-
verify(query).getResultList();
164+
verify(targetQuery).getResultList();
150165
verify(targetEm).close();
151166
}
152167

153168
@Test
154-
public void deferredQueryWithResultStream() {
169+
void deferredQueryWithResultStream() {
155170
EntityManagerFactory emf = mock(EntityManagerFactory.class);
156171
EntityManager targetEm = mock(EntityManager.class);
157-
Query query = mock(Query.class);
172+
Query targetQuery = mock(Query.class);
158173
given(emf.createEntityManager()).willReturn(targetEm);
159-
given(targetEm.createQuery("x")).willReturn(query);
174+
given(targetEm.createQuery("x")).willReturn(targetQuery);
160175
given(targetEm.isOpen()).willReturn(true);
176+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
161177

162178
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
163-
em.createQuery("x").getResultStream();
179+
Query query = em.createQuery("x");
180+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
181+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
182+
assertThat(query.unwrap(Query.class)).isSameAs(query);
183+
query.getResultStream();
164184

165-
verify(query).getResultStream();
185+
verify(targetQuery).getResultStream();
166186
verify(targetEm).close();
167187
}
168188

169189
@Test
170-
public void deferredStoredProcedureQueryWithIndexedParameters() {
190+
void deferredStoredProcedureQueryWithIndexedParameters() {
171191
EntityManagerFactory emf = mock(EntityManagerFactory.class);
172192
EntityManager targetEm = mock(EntityManager.class);
173-
StoredProcedureQuery query = mock(StoredProcedureQuery.class);
193+
StoredProcedureQuery targetQuery = mock(StoredProcedureQuery.class);
174194
given(emf.createEntityManager()).willReturn(targetEm);
175-
given(targetEm.createStoredProcedureQuery("x")).willReturn(query);
176-
willReturn("y").given(query).getOutputParameterValue(0);
177-
willReturn("z").given(query).getOutputParameterValue(2);
195+
given(targetEm.createStoredProcedureQuery("x")).willReturn(targetQuery);
196+
willReturn("y").given(targetQuery).getOutputParameterValue(0);
197+
willReturn("z").given(targetQuery).getOutputParameterValue(2);
178198
given(targetEm.isOpen()).willReturn(true);
179199

180200
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
@@ -188,24 +208,24 @@ public void deferredStoredProcedureQueryWithIndexedParameters() {
188208
spq.getOutputParameterValue(1));
189209
assertThat(spq.getOutputParameterValue(2)).isEqualTo("z");
190210

191-
verify(query).registerStoredProcedureParameter(0, String.class, ParameterMode.OUT);
192-
verify(query).registerStoredProcedureParameter(1, Number.class, ParameterMode.IN);
193-
verify(query).registerStoredProcedureParameter(2, Object.class, ParameterMode.INOUT);
194-
verify(query).execute();
211+
verify(targetQuery).registerStoredProcedureParameter(0, String.class, ParameterMode.OUT);
212+
verify(targetQuery).registerStoredProcedureParameter(1, Number.class, ParameterMode.IN);
213+
verify(targetQuery).registerStoredProcedureParameter(2, Object.class, ParameterMode.INOUT);
214+
verify(targetQuery).execute();
195215
verify(targetEm).close();
196-
verifyNoMoreInteractions(query);
216+
verifyNoMoreInteractions(targetQuery);
197217
verifyNoMoreInteractions(targetEm);
198218
}
199219

200220
@Test
201-
public void deferredStoredProcedureQueryWithNamedParameters() {
221+
void deferredStoredProcedureQueryWithNamedParameters() {
202222
EntityManagerFactory emf = mock(EntityManagerFactory.class);
203223
EntityManager targetEm = mock(EntityManager.class);
204-
StoredProcedureQuery query = mock(StoredProcedureQuery.class);
224+
StoredProcedureQuery targetQuery = mock(StoredProcedureQuery.class);
205225
given(emf.createEntityManager()).willReturn(targetEm);
206-
given(targetEm.createStoredProcedureQuery("x")).willReturn(query);
207-
willReturn("y").given(query).getOutputParameterValue("a");
208-
willReturn("z").given(query).getOutputParameterValue("c");
226+
given(targetEm.createStoredProcedureQuery("x")).willReturn(targetQuery);
227+
willReturn("y").given(targetQuery).getOutputParameterValue("a");
228+
willReturn("z").given(targetQuery).getOutputParameterValue("c");
209229
given(targetEm.isOpen()).willReturn(true);
210230

211231
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
@@ -219,12 +239,12 @@ public void deferredStoredProcedureQueryWithNamedParameters() {
219239
spq.getOutputParameterValue("b"));
220240
assertThat(spq.getOutputParameterValue("c")).isEqualTo("z");
221241

222-
verify(query).registerStoredProcedureParameter("a", String.class, ParameterMode.OUT);
223-
verify(query).registerStoredProcedureParameter("b", Number.class, ParameterMode.IN);
224-
verify(query).registerStoredProcedureParameter("c", Object.class, ParameterMode.INOUT);
225-
verify(query).execute();
242+
verify(targetQuery).registerStoredProcedureParameter("a", String.class, ParameterMode.OUT);
243+
verify(targetQuery).registerStoredProcedureParameter("b", Number.class, ParameterMode.IN);
244+
verify(targetQuery).registerStoredProcedureParameter("c", Object.class, ParameterMode.INOUT);
245+
verify(targetQuery).execute();
226246
verify(targetEm).close();
227-
verifyNoMoreInteractions(query);
247+
verifyNoMoreInteractions(targetQuery);
228248
verifyNoMoreInteractions(targetEm);
229249
}
230250

0 commit comments

Comments
 (0)