1
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.ResultProcessor;
23 import org.springframework.data.repository.query.ReturnedType;
24 import org.springframework.expression.spel.standard.SpelExpressionParser;
25 import org.springframework.util.Assert;
26
27
37 abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
38
39 private final DeclaredQuery query;
40 private final DeclaredQuery countQuery;
41 private final QueryMethodEvaluationContextProvider evaluationContextProvider;
42 private final SpelExpressionParser parser;
43 private final QueryParameterSetter.QueryMetadataCache metadataCache = new QueryParameterSetter.QueryMetadataCache();
44
45
55 public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em, String queryString,
56 QueryMethodEvaluationContextProvider evaluationContextProvider, SpelExpressionParser parser) {
57
58 super(method, em);
59
60 Assert.hasText(queryString, "Query string must not be null or empty!");
61 Assert.notNull(evaluationContextProvider, "ExpressionEvaluationContextProvider must not be null!");
62 Assert.notNull(parser, "Parser must not be null!");
63
64 this.evaluationContextProvider = evaluationContextProvider;
65 this.query = new ExpressionBasedStringQuery(queryString, method.getEntityInformation(), parser);
66
67 DeclaredQuery countQuery = query.deriveCountQuery(method.getCountQuery(), method.getCountQueryProjection());
68 this.countQuery = ExpressionBasedStringQuery.from(countQuery, method.getEntityInformation(), parser);
69
70 this.parser = parser;
71
72 Assert.isTrue(method.isNativeQuery() || !query.usesJdbcStyleParameters(),
73 "JDBC style parameters (?) are not supported for JPA queries.");
74 }
75
76
80 @Override
81 public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
82
83 String sortedQueryString = QueryUtils.applySorting(query.getQueryString(), accessor.getSort(), query.getAlias());
84 ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
85
86 Query query = createJpaQuery(sortedQueryString, processor.getReturnedType());
87
88 QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata(sortedQueryString, query);
89
90
91
92 return parameterBinder.get().bindAndPrepare(query, metadata, accessor);
93 }
94
95
99 @Override
100 protected ParameterBinder createBinder() {
101
102 return ParameterBinderFactory.createQueryAwareBinder(getQueryMethod().getParameters(), query, parser,
103 evaluationContextProvider);
104 }
105
106
110 @Override
111 protected Query doCreateCountQuery(JpaParametersParameterAccessor accessor) {
112
113 String queryString = countQuery.getQueryString();
114 EntityManager em = getEntityManager();
115
116 Query query = getQueryMethod().isNativeQuery()
117 ? em.createNativeQuery(queryString)
118 : em.createQuery(queryString, Long.class);
119
120 QueryParameterSetter.QueryMetadata metadata = metadataCache.getMetadata(queryString, query);
121
122 parameterBinder.get().bind(metadata.withQuery(query), accessor, QueryParameterSetter.ErrorHandling.LENIENT);
123
124 return query;
125 }
126
127
130 public DeclaredQuery getQuery() {
131 return query;
132 }
133
134
137 public DeclaredQuery getCountQuery() {
138 return countQuery;
139 }
140
141
145 protected Query createJpaQuery(String queryString, ReturnedType returnedType) {
146
147 EntityManager em = getEntityManager();
148
149 if (this.query.hasConstructorExpression() || this.query.isDefaultProjection()) {
150 return em.createQuery(queryString);
151 }
152
153 Class<?> typeToRead = getTypeToRead(returnedType);
154
155 return typeToRead == null
156 ? em.createQuery(queryString)
157 : em.createQuery(queryString, typeToRead);
158 }
159 }
160