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.Query;
19
20 import org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling;
21 import org.springframework.util.Assert;
22
23 /**
24  * {@link ParameterBinder} is used to bind method parameters to a {@link Query}. This is usually done whenever an
25  * {@link AbstractJpaQuery} is executed.
26  *
27  * @author Oliver Gierke
28  * @author Thomas Darimont
29  * @author Mark Paluch
30  * @author Christoph Strobl
31  * @author Jens Schauder
32  */

33 public class ParameterBinder {
34
35     static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to use provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters.";
36
37     private final JpaParameters parameters;
38     private final Iterable<QueryParameterSetter> parameterSetters;
39     private final boolean useJpaForPaging;
40
41     /**
42      * Creates a new {@link ParameterBinder} for the given {@link JpaParameters} and {@link QueryParameterSetter}s.
43      * Defaults to use JPA API to apply pagination offsets.
44      *
45      * @param parameters must not be {@literal null}.
46      * @param parameterSetters must not be {@literal null}.
47      * @since 2.0.6
48      */

49     ParameterBinder(JpaParameters parameters, Iterable<QueryParameterSetter> parameterSetters) {
50         this(parameters, parameterSetters, true);
51     }
52
53     /**
54      * Creates a new {@link ParameterBinder} for the given {@link JpaParameters} and {@link QueryParameterSetter}s.
55      *
56      * @param parameters must not be {@literal null}.
57      * @param parameterSetters must not be {@literal null}.
58      * @param useJpaForPaging determines whether {@link Query#setFirstResult(int)} and {@link Query#setMaxResults(int)}
59      *          shall be used for paging.
60      */

61     public ParameterBinder(JpaParameters parameters, Iterable<QueryParameterSetter> parameterSetters,
62             boolean useJpaForPaging) {
63
64         Assert.notNull(parameters, "JpaParameters must not be null!");
65         Assert.notNull(parameterSetters, "Parameter setters must not be null!");
66
67         this.parameters = parameters;
68         this.parameterSetters = parameterSetters;
69         this.useJpaForPaging = useJpaForPaging;
70     }
71
72     public <T extends Query> T bind(T jpaQuery, QueryParameterSetter.QueryMetadata metadata,
73             JpaParametersParameterAccessor accessor) {
74         bind(metadata.withQuery(jpaQuery), accessor, ErrorHandling.STRICT);
75         return jpaQuery;
76     }
77
78     public void bind(QueryParameterSetter.BindableQuery query, JpaParametersParameterAccessor accessor,
79             ErrorHandling errorHandling) {
80
81         for (QueryParameterSetter setter : parameterSetters) {
82             setter.setParameter(query, accessor, errorHandling);
83         }
84     }
85
86     /**
87      * Binds the parameters to the given query and applies special parameter types (e.g. pagination).
88      *
89      * @param query must not be {@literal null}.
90      * @param values values of method parameters to be assigned to the query parameters.
91      */

92     Query bindAndPrepare(Query query, QueryParameterSetter.QueryMetadata metadata,
93             JpaParametersParameterAccessor accessor) {
94
95         bind(query, metadata, accessor);
96
97         if (!useJpaForPaging || !parameters.hasPageableParameter() || accessor.getPageable().isUnpaged()) {
98             return query;
99         }
100
101         query.setFirstResult((int) accessor.getPageable().getOffset());
102         query.setMaxResults(accessor.getPageable().getPageSize());
103
104         return query;
105     }
106 }
107