Skip to content

Commit dfe437a

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

File tree

2 files changed

+74
-52
lines changed

2 files changed

+74
-52
lines changed

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

Lines changed: 4 additions & 2 deletions
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.
@@ -385,7 +385,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
385385
else if (targetClass.isInstance(proxy)) {
386386
return proxy;
387387
}
388-
break;
388+
else {
389+
return this.target.unwrap(targetClass);
390+
}
389391
case "getOutputParameterValue":
390392
if (this.entityManager == null) {
391393
Object key = args[0];

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

Lines changed: 70 additions & 50 deletions
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.
@@ -37,143 +37,163 @@
3737
import static org.mockito.Mockito.withSettings;
3838

3939
/**
40-
* Unit tests for {@link SharedEntityManagerCreator}.
40+
* Tests for {@link SharedEntityManagerCreator}.
4141
*
4242
* @author Oliver Gierke
4343
* @author Juergen Hoeller
4444
*/
4545
@ExtendWith(MockitoExtension.class)
46-
public class SharedEntityManagerCreatorTests {
46+
class SharedEntityManagerCreatorTests {
4747

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

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

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

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

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

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

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

104104
@Test
105-
public void deferredQueryWithUpdate() {
105+
void deferredQueryWithUpdate() {
106106
EntityManagerFactory emf = mock();
107107
EntityManager targetEm = mock();
108-
Query query = mock();
108+
Query targetQuery = mock();
109109
given(emf.createEntityManager()).willReturn(targetEm);
110-
given(targetEm.createQuery("x")).willReturn(query);
110+
given(targetEm.createQuery("x")).willReturn(targetQuery);
111111
given(targetEm.isOpen()).willReturn(true);
112+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
112113

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

116-
verify(query).executeUpdate();
121+
verify(targetQuery).executeUpdate();
117122
verify(targetEm).close();
118123
}
119124

120125
@Test
121-
public void deferredQueryWithSingleResult() {
126+
void deferredQueryWithSingleResult() {
122127
EntityManagerFactory emf = mock();
123128
EntityManager targetEm = mock();
124-
Query query = mock();
129+
Query targetQuery = mock();
125130
given(emf.createEntityManager()).willReturn(targetEm);
126-
given(targetEm.createQuery("x")).willReturn(query);
131+
given(targetEm.createQuery("x")).willReturn(targetQuery);
127132
given(targetEm.isOpen()).willReturn(true);
133+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
128134

129135
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
130-
em.createQuery("x").getSingleResult();
136+
Query query = em.createQuery("x");
137+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
138+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
139+
assertThat(query.unwrap(Query.class)).isSameAs(query);
140+
query.getSingleResult();
131141

132-
verify(query).getSingleResult();
142+
verify(targetQuery).getSingleResult();
133143
verify(targetEm).close();
134144
}
135145

136146
@Test
137-
public void deferredQueryWithResultList() {
147+
void deferredQueryWithResultList() {
138148
EntityManagerFactory emf = mock();
139149
EntityManager targetEm = mock();
140-
Query query = mock();
150+
Query targetQuery = mock();
141151
given(emf.createEntityManager()).willReturn(targetEm);
142-
given(targetEm.createQuery("x")).willReturn(query);
152+
given(targetEm.createQuery("x")).willReturn(targetQuery);
143153
given(targetEm.isOpen()).willReturn(true);
154+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
144155

145156
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
146-
em.createQuery("x").getResultList();
157+
Query query = em.createQuery("x");
158+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
159+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
160+
assertThat(query.unwrap(Query.class)).isSameAs(query);
161+
query.getResultList();
147162

148-
verify(query).getResultList();
163+
verify(targetQuery).getResultList();
149164
verify(targetEm).close();
150165
}
151166

152167
@Test
153-
public void deferredQueryWithResultStream() {
168+
void deferredQueryWithResultStream() {
154169
EntityManagerFactory emf = mock();
155170
EntityManager targetEm = mock();
156-
Query query = mock();
171+
Query targetQuery = mock();
157172
given(emf.createEntityManager()).willReturn(targetEm);
158-
given(targetEm.createQuery("x")).willReturn(query);
173+
given(targetEm.createQuery("x")).willReturn(targetQuery);
159174
given(targetEm.isOpen()).willReturn(true);
175+
given((Query) targetQuery.unwrap(targetQuery.getClass())).willReturn(targetQuery);
160176

161177
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
162-
em.createQuery("x").getResultStream();
178+
Query query = em.createQuery("x");
179+
assertThat((Query) query.unwrap(null)).isSameAs(targetQuery);
180+
assertThat((Query) query.unwrap(targetQuery.getClass())).isSameAs(targetQuery);
181+
assertThat(query.unwrap(Query.class)).isSameAs(query);
182+
query.getResultStream();
163183

164-
verify(query).getResultStream();
184+
verify(targetQuery).getResultStream();
165185
verify(targetEm).close();
166186
}
167187

168188
@Test
169-
public void deferredStoredProcedureQueryWithIndexedParameters() {
189+
void deferredStoredProcedureQueryWithIndexedParameters() {
170190
EntityManagerFactory emf = mock();
171191
EntityManager targetEm = mock();
172-
StoredProcedureQuery query = mock();
192+
StoredProcedureQuery targetQuery = mock();
173193
given(emf.createEntityManager()).willReturn(targetEm);
174-
given(targetEm.createStoredProcedureQuery("x")).willReturn(query);
175-
willReturn("y").given(query).getOutputParameterValue(0);
176-
willReturn("z").given(query).getOutputParameterValue(2);
194+
given(targetEm.createStoredProcedureQuery("x")).willReturn(targetQuery);
195+
willReturn("y").given(targetQuery).getOutputParameterValue(0);
196+
willReturn("z").given(targetQuery).getOutputParameterValue(2);
177197
given(targetEm.isOpen()).willReturn(true);
178198

179199
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
@@ -187,24 +207,24 @@ public void deferredStoredProcedureQueryWithIndexedParameters() {
187207
spq.getOutputParameterValue(1));
188208
assertThat(spq.getOutputParameterValue(2)).isEqualTo("z");
189209

190-
verify(query).registerStoredProcedureParameter(0, String.class, ParameterMode.OUT);
191-
verify(query).registerStoredProcedureParameter(1, Number.class, ParameterMode.IN);
192-
verify(query).registerStoredProcedureParameter(2, Object.class, ParameterMode.INOUT);
193-
verify(query).execute();
210+
verify(targetQuery).registerStoredProcedureParameter(0, String.class, ParameterMode.OUT);
211+
verify(targetQuery).registerStoredProcedureParameter(1, Number.class, ParameterMode.IN);
212+
verify(targetQuery).registerStoredProcedureParameter(2, Object.class, ParameterMode.INOUT);
213+
verify(targetQuery).execute();
194214
verify(targetEm).close();
195-
verifyNoMoreInteractions(query);
215+
verifyNoMoreInteractions(targetQuery);
196216
verifyNoMoreInteractions(targetEm);
197217
}
198218

199219
@Test
200-
public void deferredStoredProcedureQueryWithNamedParameters() {
220+
void deferredStoredProcedureQueryWithNamedParameters() {
201221
EntityManagerFactory emf = mock();
202222
EntityManager targetEm = mock();
203-
StoredProcedureQuery query = mock();
223+
StoredProcedureQuery targetQuery = mock();
204224
given(emf.createEntityManager()).willReturn(targetEm);
205-
given(targetEm.createStoredProcedureQuery("x")).willReturn(query);
206-
willReturn("y").given(query).getOutputParameterValue("a");
207-
willReturn("z").given(query).getOutputParameterValue("c");
225+
given(targetEm.createStoredProcedureQuery("x")).willReturn(targetQuery);
226+
willReturn("y").given(targetQuery).getOutputParameterValue("a");
227+
willReturn("z").given(targetQuery).getOutputParameterValue("c");
208228
given(targetEm.isOpen()).willReturn(true);
209229

210230
EntityManager em = SharedEntityManagerCreator.createSharedEntityManager(emf);
@@ -218,12 +238,12 @@ public void deferredStoredProcedureQueryWithNamedParameters() {
218238
spq.getOutputParameterValue("b"));
219239
assertThat(spq.getOutputParameterValue("c")).isEqualTo("z");
220240

221-
verify(query).registerStoredProcedureParameter("a", String.class, ParameterMode.OUT);
222-
verify(query).registerStoredProcedureParameter("b", Number.class, ParameterMode.IN);
223-
verify(query).registerStoredProcedureParameter("c", Object.class, ParameterMode.INOUT);
224-
verify(query).execute();
241+
verify(targetQuery).registerStoredProcedureParameter("a", String.class, ParameterMode.OUT);
242+
verify(targetQuery).registerStoredProcedureParameter("b", Number.class, ParameterMode.IN);
243+
verify(targetQuery).registerStoredProcedureParameter("c", Object.class, ParameterMode.INOUT);
244+
verify(targetQuery).execute();
225245
verify(targetEm).close();
226-
verifyNoMoreInteractions(query);
246+
verifyNoMoreInteractions(targetQuery);
227247
verifyNoMoreInteractions(targetEm);
228248
}
229249

0 commit comments

Comments
 (0)