1 /*
2 * Copyright 2008-2020 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.springframework.data.jpa.repository.query;
17
18 import javax.persistence.EntityManager;
19 import javax.persistence.Query;
20
21 import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
22 import org.springframework.data.repository.query.RepositoryQuery;
23 import org.springframework.expression.spel.standard.SpelExpressionParser;
24
25 /**
26 * {@link RepositoryQuery} implementation that inspects a {@link org.springframework.data.repository.query.QueryMethod}
27 * for the existence of an {@link org.springframework.data.jpa.repository.Query} annotation and creates a JPA
28 * {@link Query} from it.
29 *
30 * @author Oliver Gierke
31 * @author Thomas Darimont
32 * @author Mark Paluch
33 */
34 final class SimpleJpaQuery extends AbstractStringBasedJpaQuery {
35
36 /**
37 * Creates a new {@link SimpleJpaQuery} encapsulating the query annotated on the given {@link JpaQueryMethod}.
38 *
39 * @param method must not be {@literal null}
40 * @param em must not be {@literal null}
41 * @param evaluationContextProvider must not be {@literal null}
42 * @param parser must not be {@literal null}
43 */
44 public SimpleJpaQuery(JpaQueryMethod method, EntityManager em,
45 QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
46 this(method, em, method.getRequiredAnnotatedQuery(), evaluationContextProvider, parser);
47 }
48
49 /**
50 * Creates a new {@link SimpleJpaQuery} that encapsulates a simple query string.
51 *
52 * @param method must not be {@literal null}
53 * @param em must not be {@literal null}
54 * @param queryString must not be {@literal null} or empty
55 * @param evaluationContextProvider must not be {@literal null}
56 * @param parser must not be {@literal null}
57 */
58 public SimpleJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
59 QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
60
61 super(method, em, queryString, evaluationContextProvider, parser);
62
63 validateQuery(getQuery().getQueryString(), "Validation failed for query for method %s!", method);
64
65 if (method.isPageQuery()) {
66 validateQuery(getCountQuery().getQueryString(),
67 String.format("Count query validation failed for method %s!", method));
68 }
69 }
70
71 /**
72 * Validates the given query for syntactical correctness.
73 *
74 * @param query
75 * @param errorMessage
76 */
77 private void validateQuery(String query, String errorMessage, Object... arguments) {
78
79 if (getQueryMethod().isProcedureQuery()) {
80 return;
81 }
82
83 EntityManager validatingEm = null;
84
85 try {
86 validatingEm = getEntityManager().getEntityManagerFactory().createEntityManager();
87 validatingEm.createQuery(query);
88
89 } catch (RuntimeException e) {
90
91 // Needed as there's ambiguities in how an invalid query string shall be expressed by the persistence provider
92 // https://java.net/projects/jpa-spec/lists/jsr338-experts/archive/2012-07/message/17
93 throw new IllegalArgumentException(String.format(errorMessage, arguments), e);
94
95 } finally {
96
97 if (validatingEm != null) {
98 validatingEm.close();
99 }
100 }
101 }
102 }
103