Skip to content

Commit 94da183

Browse files
committed
Adopt JpaParameters to reflect the actual parameter type when using generics.
Closes #3254
1 parent 970b7f0 commit 94da183

13 files changed

+143
-83
lines changed

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaParameters.java

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,15 @@
2020
import java.lang.reflect.Method;
2121
import java.util.Date;
2222
import java.util.List;
23+
import java.util.function.Function;
2324

2425
import org.springframework.core.MethodParameter;
2526
import org.springframework.data.jpa.repository.Temporal;
2627
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
2728
import org.springframework.data.repository.query.Parameter;
2829
import org.springframework.data.repository.query.Parameters;
30+
import org.springframework.data.repository.query.ParametersSource;
31+
import org.springframework.data.util.TypeInformation;
2932
import org.springframework.lang.Nullable;
3033

3134
/**
@@ -37,24 +40,33 @@
3740
*/
3841
public class JpaParameters extends Parameters<JpaParameters, JpaParameter> {
3942

43+
/**
44+
* Creates a new {@link JpaParameters} instance from the given {@link ParametersSource}.
45+
*
46+
* @param parametersSource must not be {@literal null}.
47+
* @since 3.2.1
48+
*/
49+
public JpaParameters(ParametersSource parametersSource) {
50+
super(parametersSource,
51+
methodParameter -> new JpaParameter(methodParameter, parametersSource.getDomainTypeInformation()));
52+
}
53+
4054
/**
4155
* Creates a new {@link JpaParameters} instance from the given {@link Method}.
4256
*
43-
* @param method must not be {@literal null}.
57+
* @param parametersSource must not be {@literal null}.
58+
* @param parameterFactory must not be {@literal null}.
59+
* @since 3.2.1
4460
*/
45-
public JpaParameters(Method method) {
46-
super(method);
61+
protected JpaParameters(ParametersSource parametersSource,
62+
Function<MethodParameter, JpaParameter> parameterFactory) {
63+
super(parametersSource, parameterFactory);
4764
}
4865

4966
private JpaParameters(List<JpaParameter> parameters) {
5067
super(parameters);
5168
}
5269

53-
@Override
54-
protected JpaParameter createParameter(MethodParameter parameter) {
55-
return new JpaParameter(parameter);
56-
}
57-
5870
@Override
5971
protected JpaParameters createFrom(List<JpaParameter> parameters) {
6072
return new JpaParameters(parameters);
@@ -82,14 +94,31 @@ public static class JpaParameter extends Parameter {
8294
* Creates a new {@link JpaParameter}.
8395
*
8496
* @param parameter must not be {@literal null}.
97+
* @deprecated since 3.2.1
8598
*/
99+
@Deprecated(since = "3.2.1", forRemoval = true)
86100
protected JpaParameter(MethodParameter parameter) {
87101

88102
super(parameter);
89103

90104
this.annotation = parameter.getParameterAnnotation(Temporal.class);
91105
this.temporalType = null;
106+
if (!isDateParameter() && hasTemporalParamAnnotation()) {
107+
throw new IllegalArgumentException(
108+
Temporal.class.getSimpleName() + " annotation is only allowed on Date parameter");
109+
}
110+
}
111+
112+
/**
113+
* Creates a new {@link JpaParameter}.
114+
*
115+
* @param parameter must not be {@literal null}.
116+
*/
117+
protected JpaParameter(MethodParameter parameter, TypeInformation<?> domainType) {
92118

119+
super(parameter, domainType);
120+
this.annotation = parameter.getParameterAnnotation(Temporal.class);
121+
this.temporalType = null;
93122
if (!isDateParameter() && hasTemporalParamAnnotation()) {
94123
throw new IllegalArgumentException(
95124
Temporal.class.getSimpleName() + " annotation is only allowed on Date parameter");

spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
import org.springframework.data.repository.core.RepositoryMetadata;
4343
import org.springframework.data.repository.query.Parameter;
4444
import org.springframework.data.repository.query.Parameters;
45+
import org.springframework.data.repository.query.ParametersSource;
4546
import org.springframework.data.repository.query.QueryMethod;
4647
import org.springframework.data.repository.util.QueryExecutionConverters;
4748
import org.springframework.data.util.Lazy;
@@ -447,8 +448,8 @@ private <T> T getMergedOrDefaultAnnotationValue(String attribute, Class annotati
447448
}
448449

449450
@Override
450-
protected JpaParameters createParameters(Method method) {
451-
return new JpaParameters(method);
451+
protected Parameters<?, ?> createParameters(ParametersSource parametersSource) {
452+
return new JpaParameters(parametersSource);
452453
}
453454

454455
@Override

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
3838
import org.springframework.data.projection.ProjectionFactory;
3939
import org.springframework.data.repository.core.RepositoryMetadata;
40+
import org.springframework.data.repository.query.ParametersSource;
41+
import org.springframework.data.util.TypeInformation;
4042
import org.springframework.test.context.ContextConfiguration;
4143
import org.springframework.test.context.junit.jupiter.SpringExtension;
4244

@@ -70,8 +72,8 @@ private static class NonBindableAwareJpaParameter extends JpaParameters.JpaParam
7072

7173
private final MethodParameter parameter;
7274

73-
NonBindableAwareJpaParameter(MethodParameter parameter) {
74-
super(parameter);
75+
NonBindableAwareJpaParameter(MethodParameter parameter, TypeInformation<?> domainType) {
76+
super(parameter, domainType);
7577
this.parameter = parameter;
7678
}
7779

@@ -83,14 +85,11 @@ public boolean isBindable() {
8385

8486
private static class NonBindableAwareJpaParameters extends JpaParameters {
8587

86-
NonBindableAwareJpaParameters(Method method) {
87-
super(method);
88+
NonBindableAwareJpaParameters(ParametersSource parametersSource) {
89+
super(parametersSource,
90+
param -> new NonBindableAwareJpaParameter(param, parametersSource.getDomainTypeInformation()));
8891
}
8992

90-
@Override
91-
protected JpaParameter createParameter(MethodParameter parameter) {
92-
return new NonBindableAwareJpaParameter(parameter);
93-
}
9493
}
9594

9695
private static class NonBindableAwareJpaQueryMethod extends JpaQueryMethod {
@@ -101,8 +100,8 @@ private static class NonBindableAwareJpaQueryMethod extends JpaQueryMethod {
101100
}
102101

103102
@Override
104-
protected JpaParameters createParameters(Method method) {
105-
return new NonBindableAwareJpaParameters(method);
103+
protected JpaParameters createParameters(ParametersSource source) {
104+
return new NonBindableAwareJpaParameters(source);
106105
}
107106
}
108107

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/HibernateJpaParametersParameterAccessorUnitTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import org.junit.jupiter.api.Assertions;
88
import org.junit.jupiter.api.Test;
99
import org.junit.jupiter.api.extension.ExtendWith;
10+
1011
import org.springframework.beans.factory.annotation.Autowired;
11-
import org.springframework.data.jpa.repository.query.HibernateJpaParametersParameterAccessor;
12-
import org.springframework.data.jpa.repository.query.JpaParameters;
12+
import org.springframework.data.repository.query.ParametersSource;
1313
import org.springframework.test.context.ContextConfiguration;
1414
import org.springframework.test.context.junit.jupiter.SpringExtension;
1515
import org.springframework.transaction.PlatformTransactionManager;
@@ -48,7 +48,7 @@ void withinTransaction() throws Exception {
4848
private void parametersCanGetAccessesOutsideTransaction() throws NoSuchMethodException {
4949

5050
Method method = EntityManager.class.getMethod("flush");
51-
JpaParameters parameters = new JpaParameters(method);
51+
JpaParameters parameters = new JpaParameters(ParametersSource.of(method));
5252
HibernateJpaParametersParameterAccessor accessor = new HibernateJpaParametersParameterAccessor(parameters,
5353
new Object[] {}, em);
5454
Assertions.assertEquals(0, accessor.getValues().length);

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersParameterAccessorTests.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
import org.junit.jupiter.api.Test;
1616
import org.junit.jupiter.api.extension.ExtendWith;
1717
import org.mockito.ArgumentCaptor;
18+
1819
import org.springframework.data.jpa.domain.sample.User;
19-
import org.springframework.data.jpa.provider.PersistenceProvider;
20+
import org.springframework.data.repository.query.ParametersSource;
2021
import org.springframework.test.context.ContextConfiguration;
2122
import org.springframework.test.context.junit.jupiter.SpringExtension;
2223

@@ -42,7 +43,7 @@ void createsJpaParametersParameterAccessor() throws Exception {
4243

4344
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
4445
Object[] values = { null };
45-
JpaParameters parameters = new JpaParameters(withNativeQuery);
46+
JpaParameters parameters = new JpaParameters(ParametersSource.of(withNativeQuery));
4647
JpaParametersParameterAccessor accessor = new JpaParametersParameterAccessor(parameters, values);
4748

4849
bind(parameters, accessor);
@@ -55,7 +56,7 @@ void createsHibernateParametersParameterAccessor() throws Exception {
5556

5657
Method withNativeQuery = SampleRepository.class.getMethod("withNativeQuery", Integer.class);
5758
Object[] values = { null };
58-
JpaParameters parameters = new JpaParameters(withNativeQuery);
59+
JpaParameters parameters = new JpaParameters(ParametersSource.of(withNativeQuery));
5960
JpaParametersParameterAccessor accessor = new HibernateJpaParametersParameterAccessor(parameters, values, em);
6061

6162
bind(parameters, accessor);

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaParametersUnitTests.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,24 @@
1818
import static jakarta.persistence.TemporalType.*;
1919
import static org.assertj.core.api.Assertions.*;
2020

21+
import jakarta.persistence.TemporalType;
22+
2123
import java.lang.reflect.Method;
2224
import java.util.Date;
2325

24-
import jakarta.persistence.TemporalType;
25-
2626
import org.junit.jupiter.api.Test;
27+
2728
import org.springframework.data.jpa.repository.Temporal;
2829
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
30+
import org.springframework.data.repository.Repository;
31+
import org.springframework.data.repository.query.ParametersSource;
2932

3033
/**
3134
* Unit tests for {@link JpaParameters}.
3235
*
3336
* @author Oliver Gierke
3437
* @author Jens Schauder
38+
* @author Mark Paluch
3539
*/
3640
class JpaParametersUnitTests {
3741

@@ -40,7 +44,7 @@ void findsTemporalParameterConfiguration() throws Exception {
4044

4145
Method method = SampleRepository.class.getMethod("foo", Date.class, String.class);
4246

43-
JpaParameters parameters = new JpaParameters(method);
47+
JpaParameters parameters = new JpaParameters(ParametersSource.of(method));
4448

4549
JpaParameter parameter = parameters.getBindableParameter(0);
4650
assertThat(parameter.isSpecialParameter()).isFalse();
@@ -51,7 +55,7 @@ void findsTemporalParameterConfiguration() throws Exception {
5155
assertThat(parameter.isTemporalParameter()).isFalse();
5256
}
5357

54-
interface SampleRepository {
58+
interface SampleRepository extends Repository<String, String> {
5559

5660
void foo(@Temporal(TIMESTAMP) Date date, String firstname);
5761
}

spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,15 @@
2020
import static org.mockito.Mockito.*;
2121

2222
import io.vavr.control.Try;
23+
import jakarta.persistence.EntityManager;
24+
import jakarta.persistence.Query;
25+
import jakarta.persistence.TypedQuery;
2326

2427
import java.lang.reflect.Method;
2528
import java.util.Arrays;
2629
import java.util.Collections;
2730
import java.util.Optional;
2831

29-
import jakarta.persistence.EntityManager;
30-
import jakarta.persistence.Query;
31-
import jakarta.persistence.TypedQuery;
32-
3332
import org.junit.jupiter.api.BeforeEach;
3433
import org.junit.jupiter.api.Test;
3534
import org.junit.jupiter.api.extension.ExtendWith;
@@ -48,6 +47,7 @@
4847
import org.springframework.data.projection.SpelAwareProxyProjectionFactory;
4948
import org.springframework.data.repository.Repository;
5049
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
50+
import org.springframework.data.repository.query.ParametersSource;
5151

5252
/**
5353
* Unit test for {@link JpaQueryExecution}.
@@ -177,7 +177,8 @@ void modifyingExecutionRejectsNonIntegerOrVoidReturnType() {
177177
@Test // DATAJPA-124, DATAJPA-912
178178
void pagedExecutionRetrievesObjectsForPageableOutOfRange() throws Exception {
179179

180-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
180+
JpaParameters parameters = new JpaParameters(
181+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
181182
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(countQuery);
182183
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
183184
when(countQuery.getResultList()).thenReturn(Arrays.asList(20L));
@@ -193,7 +194,8 @@ void pagedExecutionRetrievesObjectsForPageableOutOfRange() throws Exception {
193194
@Test // DATAJPA-477, DATAJPA-912
194195
void pagedExecutionShouldNotGenerateCountQueryIfQueryReportedNoResults() throws Exception {
195196

196-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
197+
JpaParameters parameters = new JpaParameters(
198+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
197199
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
198200
when(query.getResultList()).thenReturn(Arrays.asList(0L));
199201

@@ -208,7 +210,8 @@ void pagedExecutionShouldNotGenerateCountQueryIfQueryReportedNoResults() throws
208210
@Test // DATAJPA-912
209211
void pagedExecutionShouldUseCountFromResultIfOffsetIsZeroAndResultsWithinPageSize() throws Exception {
210212

211-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
213+
JpaParameters parameters = new JpaParameters(
214+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
212215
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
213216
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
214217

@@ -222,7 +225,8 @@ void pagedExecutionShouldUseCountFromResultIfOffsetIsZeroAndResultsWithinPageSiz
222225
@Test // DATAJPA-912
223226
void pagedExecutionShouldUseCountFromResultWithOffsetAndResultsWithinPageSize() throws Exception {
224227

225-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
228+
JpaParameters parameters = new JpaParameters(
229+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
226230
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
227231
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
228232

@@ -234,10 +238,10 @@ void pagedExecutionShouldUseCountFromResultWithOffsetAndResultsWithinPageSize()
234238
}
235239

236240
@Test // DATAJPA-912
237-
void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitLowerPageSizeBounds()
238-
throws Exception {
241+
void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitLowerPageSizeBounds() throws Exception {
239242

240-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
243+
JpaParameters parameters = new JpaParameters(
244+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
241245
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
242246
when(query.getResultList()).thenReturn(Collections.emptyList());
243247
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(query);
@@ -251,10 +255,10 @@ void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitLowerPa
251255
}
252256

253257
@Test // DATAJPA-912
254-
void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitUpperPageSizeBounds()
255-
throws Exception {
258+
void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitUpperPageSizeBounds() throws Exception {
256259

257-
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
260+
JpaParameters parameters = new JpaParameters(
261+
ParametersSource.of(getClass().getMethod("sampleMethod", Pageable.class)));
258262
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
259263
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
260264
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(query);

0 commit comments

Comments
 (0)