Skip to content

Commit 85e4ffa

Browse files
committed
DATAJPA-1497 - Polishing.
Improved naming and formatting. Made the `QueryExtractor` an argument of the `JpaQueryMethodFactory` constructor instead of its method. Original pull request: #305.
1 parent 8f5f3af commit 85e4ffa

File tree

7 files changed

+64
-44
lines changed

7 files changed

+64
-44
lines changed

src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public AbstractQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
8181
@Override
8282
public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
8383
NamedQueries namedQueries) {
84-
return resolveQuery(queryMethodFactory.build(method, metadata, factory, provider), em, namedQueries);
84+
return resolveQuery(queryMethodFactory.build(method, metadata, factory), em, namedQueries);
8585
}
8686

8787
protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries);
@@ -98,7 +98,8 @@ private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrate
9898
private final PersistenceProvider persistenceProvider;
9999
private final EscapeCharacter escape;
100100

101-
public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor, EscapeCharacter escape, JpaQueryMethodFactory queryMethodFactory) {
101+
public CreateQueryLookupStrategy(EntityManager em, QueryExtractor extractor, EscapeCharacter escape,
102+
JpaQueryMethodFactory queryMethodFactory) {
102103

103104
super(em, extractor, queryMethodFactory);
104105
this.persistenceProvider = PersistenceProvider.fromEntityManager(em);
@@ -134,6 +135,7 @@ public DeclaredQueryLookupStrategy(EntityManager em, QueryExtractor extractor,
134135
JpaQueryMethodFactory queryMethodFactory, QueryMethodEvaluationContextProvider evaluationContextProvider) {
135136

136137
super(em, extractor, queryMethodFactory);
138+
137139
this.evaluationContextProvider = evaluationContextProvider;
138140
}
139141

@@ -232,7 +234,8 @@ protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em,
232234
* @return
233235
*/
234236
public static QueryLookupStrategy create(EntityManager em, @Nullable Key key, QueryExtractor extractor,
235-
JpaQueryMethodFactory queryMethodFactory, QueryMethodEvaluationContextProvider evaluationContextProvider, EscapeCharacter escape) {
237+
JpaQueryMethodFactory queryMethodFactory, QueryMethodEvaluationContextProvider evaluationContextProvider,
238+
EscapeCharacter escape) {
236239

237240
Assert.notNull(em, "EntityManager must not be null!");
238241
Assert.notNull(extractor, "QueryExtractor must not be null!");
@@ -244,7 +247,7 @@ public static QueryLookupStrategy create(EntityManager em, @Nullable Key key, Qu
244247
case USE_DECLARED_QUERY:
245248
return new DeclaredQueryLookupStrategy(em, extractor, queryMethodFactory, evaluationContextProvider);
246249
case CREATE_IF_NOT_FOUND:
247-
return new CreateIfNotFoundQueryLookupStrategy(em, extractor,queryMethodFactory,
250+
return new CreateIfNotFoundQueryLookupStrategy(em, extractor, queryMethodFactory,
248251
new CreateQueryLookupStrategy(em, extractor, escape, queryMethodFactory),
249252
new DeclaredQueryLookupStrategy(em, extractor, queryMethodFactory, evaluationContextProvider));
250253
default:

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

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,20 @@ public class JpaQueryMethod extends QueryMethod {
9090
private final Lazy<Boolean> isProcedureQuery;
9191
private final Lazy<JpaEntityMetadata<?>> entityMetadata;
9292

93+
/**
94+
* Creates a {@link JpaQueryMethodFactory} which will create instances of this class.
95+
*
96+
* @param extractor must not be {@literal null}.
97+
* @return a {@link JpaQueryMethodFactory} guaranteed to be not {@literal null}.
98+
* @since 2.3
99+
*/
100+
public static JpaQueryMethodFactory createMethodFactory(QueryExtractor extractor) {
101+
102+
Assert.notNull(extractor, "QueryExtractor must not be null");
103+
104+
return (method, metadata, factory) -> new JpaQueryMethod(method, metadata, factory, extractor);
105+
}
106+
93107
/**
94108
* Creates a {@link JpaQueryMethod}.
95109
*
@@ -427,19 +441,4 @@ StoredProcedureAttributes getProcedureAttributes() {
427441

428442
return storedProcedureAttributes;
429443
}
430-
431-
public static class Factory implements JpaQueryMethodFactory {
432-
433-
public static final Factory INSTANCE = new Factory();
434-
435-
private Factory() {
436-
437-
}
438-
439-
@Override
440-
public JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
441-
QueryExtractor extractor) {
442-
return new JpaQueryMethod(method, metadata, factory, extractor);
443-
}
444-
}
445444
}

src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethodFactory.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@
2222
import org.springframework.data.repository.core.RepositoryMetadata;
2323

2424
/**
25+
* A factory interface for creating {@link JpaQueryMethodFactory} instances.
26+
*
27+
* This may be implemented by extensions to Spring Data JPA in order create instances of custom subclasses.
28+
*
2529
* @author Réda Housni Alaoui
30+
* @since 2.3
2631
*/
2732
public interface JpaQueryMethodFactory {
2833

@@ -32,8 +37,7 @@ public interface JpaQueryMethodFactory {
3237
* @param method must not be {@literal null}
3338
* @param metadata must not be {@literal null}
3439
* @param factory must not be {@literal null}
35-
* @param extractor must not be {@literal null}
3640
*/
37-
JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory, QueryExtractor extractor);
41+
JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory);
3842

3943
}

src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ public JpaRepositoryFactory(EntityManager entityManager) {
9191
this.extractor = PersistenceProvider.fromEntityManager(entityManager);
9292
this.crudMethodMetadataPostProcessor = new CrudMethodMetadataPostProcessor();
9393
this.entityPathResolver = SimpleEntityPathResolver.INSTANCE;
94-
this.queryMethodFactory = JpaQueryMethod.Factory.INSTANCE;
94+
this.queryMethodFactory = JpaQueryMethod.createMethodFactory(extractor);
9595

9696
addRepositoryProxyPostProcessor(crudMethodMetadataPostProcessor);
9797
addRepositoryProxyPostProcessor((factory, repositoryInformation) -> {
@@ -139,11 +139,12 @@ public void setEscapeCharacter(EscapeCharacter escapeCharacter) {
139139
}
140140

141141
/**
142-
* Configures the {@link JpaQueryMethodFactory} to be used. Defaults to {@link JpaQueryMethod.Factory#INSTANCE}.
142+
* Configures the {@link JpaQueryMethodFactory} to be used. Defaults to {@link JpaQueryMethod.DefaultJpaQueryMethodFactory#INSTANCE}.
143143
*
144144
* @param queryMethodFactory must not be {@literal null}.
145145
*/
146146
public void setQueryMethodFactory(JpaQueryMethodFactory queryMethodFactory) {
147+
147148
Assert.notNull(queryMethodFactory, "QueryMethodFactory must not be null!");
148149

149150
this.queryMethodFactory = queryMethodFactory;

src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import org.springframework.beans.factory.ObjectProvider;
2222
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.data.jpa.provider.QueryExtractor;
2324
import org.springframework.data.jpa.repository.query.EscapeCharacter;
2425
import org.springframework.data.jpa.repository.query.JpaQueryMethod;
2526
import org.springframework.data.jpa.repository.query.JpaQueryMethodFactory;
@@ -91,14 +92,14 @@ public void setEntityPathResolver(ObjectProvider<EntityPathResolver> resolver) {
9192
}
9293

9394
/**
94-
* Configures the {@link JpaQueryMethodFactory} to be used. Will expect a canonical bean to be present but fallback to
95-
* {@link JpaQueryMethod.Factory#INSTANCE} in case none is available.
95+
* Configures the {@link JpaQueryMethodFactory} to be used. Will expect a canonical bean to be present but will fallback to
96+
* {@link JpaQueryMethod#createMethodFactory(QueryExtractor)} in case none is available.
9697
*
9798
* @param resolver must not be {@literal null}.
9899
*/
99100
@Autowired
100101
public void setQueryMethodFactory(ObjectProvider<JpaQueryMethodFactory> resolver) {
101-
this.queryMethodFactory = resolver.getIfAvailable(() -> JpaQueryMethod.Factory.INSTANCE);
102+
this.queryMethodFactory = resolver.getIfAvailable(() -> null);
102103
}
103104

104105
/*
@@ -121,7 +122,10 @@ protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityM
121122
JpaRepositoryFactory jpaRepositoryFactory = new JpaRepositoryFactory(entityManager);
122123
jpaRepositoryFactory.setEntityPathResolver(entityPathResolver);
123124
jpaRepositoryFactory.setEscapeCharacter(escapeCharacter);
124-
jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);
125+
126+
if (queryMethodFactory != null) {
127+
jpaRepositoryFactory.setQueryMethodFactory(queryMethodFactory);
128+
}
125129

126130
return jpaRepositoryFactory;
127131
}

src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersTests.java renamed to src/test/java/org/springframework/data/jpa/repository/query/CustomNonBindableJpaParametersIntegrationTests.java

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2019 the original author or authors.
2+
* Copyright 2019-2020 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.
@@ -15,7 +15,7 @@
1515
*/
1616
package org.springframework.data.jpa.repository.query;
1717

18-
import static org.assertj.core.api.Assertions.assertThat;
18+
import static org.assertj.core.api.Assertions.*;
1919

2020
import java.lang.reflect.Method;
2121
import java.util.Optional;
@@ -30,6 +30,7 @@
3030
import org.springframework.context.annotation.ImportResource;
3131
import org.springframework.core.MethodParameter;
3232
import org.springframework.data.jpa.domain.sample.Product;
33+
import org.springframework.data.jpa.provider.PersistenceProvider;
3334
import org.springframework.data.jpa.provider.QueryExtractor;
3435
import org.springframework.data.jpa.repository.JpaRepository;
3536
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@@ -39,25 +40,28 @@
3940
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
4041

4142
/**
43+
* Tests that the requirement of binding an argument to a query can get controlled by a module extending Spring Data
44+
* JPA.
45+
*
4246
* @author Réda Housni Alaoui
4347
*/
4448
@RunWith(SpringJUnit4ClassRunner.class)
4549
@ContextConfiguration
46-
public class CustomNonBindableJpaParametersTests {
50+
public class CustomNonBindableJpaParametersIntegrationTests {
4751

4852
@Autowired ProductRepository products;
4953

50-
@Test
51-
public void test() {
54+
@Test // DATAJPA-1497
55+
public void methodWithNonBindableParameterCanBeCalled() {
56+
5257
Product product = products.save(new Product());
58+
5359
assertThat(products.findById(product.getId(), new NonBindable())).isNotEmpty();
5460
}
5561

56-
private static class NonBindable {
62+
private static class NonBindable {}
5763

58-
}
59-
60-
public interface ProductRepository extends JpaRepository<Product, Long> {
64+
interface ProductRepository extends JpaRepository<Product, Long> {
6165
Optional<Product> findById(long id, NonBindable nonBindable);
6266
}
6367

@@ -103,9 +107,14 @@ protected JpaParameters createParameters(Method method) {
103107

104108
private static class NonBindableAwareJpaQueryMethodFactory implements JpaQueryMethodFactory {
105109

110+
private final QueryExtractor extractor;
111+
112+
private NonBindableAwareJpaQueryMethodFactory(QueryExtractor extractor) {
113+
this.extractor = extractor;
114+
}
115+
106116
@Override
107-
public JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
108-
QueryExtractor extractor) {
117+
public JpaQueryMethod build(Method method, RepositoryMetadata metadata, ProjectionFactory factory) {
109118
return new NonBindableAwareJpaQueryMethod(method, metadata, factory, extractor);
110119
}
111120
}
@@ -118,9 +127,7 @@ static class Config {
118127

119128
@Bean
120129
JpaQueryMethodFactory jpaQueryMethodFactory() {
121-
return new NonBindableAwareJpaQueryMethodFactory();
130+
return new NonBindableAwareJpaQueryMethodFactory(PersistenceProvider.HIBERNATE);
122131
}
123-
124132
}
125-
126133
}

src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
public class JpaQueryLookupStrategyUnitTests {
5757

5858
private static final QueryMethodEvaluationContextProvider EVALUATION_CONTEXT_PROVIDER = QueryMethodEvaluationContextProvider.DEFAULT;
59-
private static final JpaQueryMethodFactory QUERY_METHOD_FACTORY = JpaQueryMethod.Factory.INSTANCE;
6059

6160
@Mock EntityManager em;
6261
@Mock EntityManagerFactory emf;
@@ -65,20 +64,23 @@ public class JpaQueryLookupStrategyUnitTests {
6564
@Mock Metamodel metamodel;
6665
@Mock ProjectionFactory projectionFactory;
6766

67+
JpaQueryMethodFactory queryMethodFactory;
68+
6869
@Before
6970
public void setUp() {
7071

7172
when(em.getMetamodel()).thenReturn(metamodel);
7273
when(em.getEntityManagerFactory()).thenReturn(emf);
7374
when(emf.createEntityManager()).thenReturn(em);
7475
when(em.getDelegate()).thenReturn(em);
76+
queryMethodFactory = JpaQueryMethod.createMethodFactory(extractor);
7577
}
7678

7779
@Test // DATAJPA-226
7880
public void invalidAnnotatedQueryCausesException() throws Exception {
7981

8082
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor,
81-
QUERY_METHOD_FACTORY, EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT);
83+
queryMethodFactory, EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT);
8284
Method method = UserRepository.class.getMethod("findByFoo", String.class);
8385
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
8486

@@ -94,7 +96,7 @@ public void invalidAnnotatedQueryCausesException() throws Exception {
9496
public void sholdThrowMorePreciseExceptionIfTryingToUsePaginationInNativeQueries() throws Exception {
9597

9698
QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor,
97-
QUERY_METHOD_FACTORY, EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT);
99+
queryMethodFactory, EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT);
98100
Method method = UserRepository.class.getMethod("findByInvalidNativeQuery", String.class, Sort.class);
99101
RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class);
100102

0 commit comments

Comments
 (0)