1
16 package org.springframework.data.jpa.repository.query;
17
18 import java.lang.reflect.Method;
19
20 import javax.persistence.EntityManager;
21
22 import org.springframework.data.jpa.repository.Query;
23 import org.springframework.data.projection.ProjectionFactory;
24 import org.springframework.data.repository.core.NamedQueries;
25 import org.springframework.data.repository.core.RepositoryMetadata;
26 import org.springframework.data.repository.query.QueryLookupStrategy;
27 import org.springframework.data.repository.query.QueryLookupStrategy.Key;
28 import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
29 import org.springframework.data.repository.query.RepositoryQuery;
30 import org.springframework.lang.Nullable;
31 import org.springframework.util.Assert;
32
33
41 public final class JpaQueryLookupStrategy {
42
43
46 private JpaQueryLookupStrategy() {}
47
48
54 private abstract static class AbstractQueryLookupStrategy implements QueryLookupStrategy {
55
56 private final EntityManager em;
57 private final JpaQueryMethodFactory queryMethodFactory;
58
59
65 public AbstractQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory) {
66
67 Assert.notNull(em, "EntityManager must not be null!");
68 Assert.notNull(queryMethodFactory, "JpaQueryMethodFactory must not be null!");
69
70 this.em = em;
71 this.queryMethodFactory = queryMethodFactory;
72 }
73
74
78 @Override
79 public final RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, ProjectionFactory factory,
80 NamedQueries namedQueries) {
81 return resolveQuery(queryMethodFactory.build(method, metadata, factory), em, namedQueries);
82 }
83
84 protected abstract RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries);
85 }
86
87
93 private static class CreateQueryLookupStrategy extends AbstractQueryLookupStrategy {
94
95 private final EscapeCharacter escape;
96
97 public CreateQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
98 EscapeCharacter escape) {
99
100 super(em, queryMethodFactory);
101
102 this.escape = escape;
103 }
104
105 @Override
106 protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
107 return new PartTreeJpaQuery(method, em, escape);
108 }
109 }
110
111
119 private static class DeclaredQueryLookupStrategy extends AbstractQueryLookupStrategy {
120
121 private final QueryMethodEvaluationContextProvider evaluationContextProvider;
122
123
131 public DeclaredQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
132 QueryMethodEvaluationContextProvider evaluationContextProvider) {
133
134 super(em, queryMethodFactory);
135
136 this.evaluationContextProvider = evaluationContextProvider;
137 }
138
139
143 @Override
144 protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
145
146 RepositoryQuery query = JpaQueryFactory.INSTANCE.fromQueryAnnotation(method, em, evaluationContextProvider);
147
148 if (null != query) {
149 return query;
150 }
151
152 query = JpaQueryFactory.INSTANCE.fromProcedureAnnotation(method, em);
153
154 if (null != query) {
155 return query;
156 }
157
158 String name = method.getNamedQueryName();
159 if (namedQueries.hasQuery(name)) {
160 return JpaQueryFactory.INSTANCE.fromMethodWithQueryString(method, em, namedQueries.getQuery(name),
161 evaluationContextProvider);
162 }
163
164 query = NamedQuery.lookupFrom(method, em);
165
166 if (null != query) {
167 return query;
168 }
169
170 throw new IllegalStateException(
171 String.format("Did neither find a NamedQuery nor an annotated query for method %s!", method));
172 }
173 }
174
175
183 private static class CreateIfNotFoundQueryLookupStrategy extends AbstractQueryLookupStrategy {
184
185 private final DeclaredQueryLookupStrategy lookupStrategy;
186 private final CreateQueryLookupStrategy createStrategy;
187
188
196 public CreateIfNotFoundQueryLookupStrategy(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
197 CreateQueryLookupStrategy createStrategy, DeclaredQueryLookupStrategy lookupStrategy) {
198
199 super(em, queryMethodFactory);
200
201 Assert.notNull(createStrategy, "CreateQueryLookupStrategy must not be null!");
202 Assert.notNull(lookupStrategy, "DeclaredQueryLookupStrategy must not be null!");
203
204 this.createStrategy = createStrategy;
205 this.lookupStrategy = lookupStrategy;
206 }
207
208
212 @Override
213 protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em, NamedQueries namedQueries) {
214
215 try {
216 return lookupStrategy.resolveQuery(method, em, namedQueries);
217 } catch (IllegalStateException e) {
218 return createStrategy.resolveQuery(method, em, namedQueries);
219 }
220 }
221 }
222
223
234 public static QueryLookupStrategy create(EntityManager em, JpaQueryMethodFactory queryMethodFactory,
235 @Nullable Key key, QueryMethodEvaluationContextProvider evaluationContextProvider, EscapeCharacter escape) {
236
237 Assert.notNull(em, "EntityManager must not be null!");
238 Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");
239
240 switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) {
241 case CREATE:
242 return new CreateQueryLookupStrategy(em, queryMethodFactory, escape);
243 case USE_DECLARED_QUERY:
244 return new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider);
245 case CREATE_IF_NOT_FOUND:
246 return new CreateIfNotFoundQueryLookupStrategy(em, queryMethodFactory,
247 new CreateQueryLookupStrategy(em, queryMethodFactory, escape),
248 new DeclaredQueryLookupStrategy(em, queryMethodFactory, evaluationContextProvider));
249 default:
250 throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
251 }
252 }
253 }
254