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