Skip to content

Commit 59a125d

Browse files
committed
Unwrap raw target Query instance in case of proxy mismatch
Closes gh-32766
1 parent aebc48e commit 59a125d

File tree

2 files changed

+58
-35
lines changed

2 files changed

+58
-35
lines changed

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

Lines changed: 4 additions & 1 deletion
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.
@@ -394,6 +394,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
394394
else if (targetClass.isInstance(proxy)) {
395395
return proxy;
396396
}
397+
else {
398+
return this.target.unwrap(targetClass);
399+
}
397400
}
398401
case "getOutputParameterValue" -> {
399402
if (this.entityManager == null) {

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

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -105,75 +105,95 @@ void transactionRequiredExceptionOnRefresh() {
105105
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
121126
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
137147
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
153168
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
169189
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 @@ 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
200220
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 @@ 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)