/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java

https://github.com/max-dev/spring-data-jpa · Java · 150 lines · 79 code · 27 blank · 44 comment · 7 complexity · 2eb39294a11fa3f1c937e3c7c0d9d72a MD5 · raw file

  1. /*
  2. * Copyright 2008-2012 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. * http://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. import javax.persistence.EntityManager;
  18. import javax.persistence.Query;
  19. import javax.persistence.TypedQuery;
  20. import org.slf4j.Logger;
  21. import org.slf4j.LoggerFactory;
  22. import org.springframework.data.repository.query.Parameters;
  23. import org.springframework.data.repository.query.QueryCreationException;
  24. import org.springframework.data.repository.query.RepositoryQuery;
  25. /**
  26. * Implementation of {@link RepositoryQuery} based on {@link javax.persistence.NamedQuery}s.
  27. *
  28. * @author Oliver Gierke
  29. */
  30. final class NamedQuery extends AbstractJpaQuery {
  31. private static final String CANNOT_EXTRACT_QUERY = "Your persistence provider does not support extracting the JPQL query from a "
  32. + "named query thus you can't use Pageable inside your query method. Make sure you "
  33. + "have a JpaDialect configured at your EntityManagerFactoryBean as this affects "
  34. + "discovering the concrete persistence provider.";
  35. private static final Logger LOG = LoggerFactory.getLogger(NamedQuery.class);
  36. private final String queryName;
  37. private final String countQueryName;
  38. private final QueryExtractor extractor;
  39. /**
  40. * Creates a new {@link NamedQuery}.
  41. */
  42. private NamedQuery(JpaQueryMethod method, EntityManager em) {
  43. super(method, em);
  44. this.queryName = method.getNamedQueryName();
  45. this.countQueryName = method.getNamedCountQueryName();
  46. this.extractor = method.getQueryExtractor();
  47. Parameters parameters = method.getParameters();
  48. // Let's see if the referenced named query exists
  49. em.createNamedQuery(queryName);
  50. if (parameters.hasSortParameter()) {
  51. throw new IllegalStateException(String.format("Finder method %s is backed " + "by a NamedQuery and must "
  52. + "not contain a sort parameter as we cannot modify the query! Use @Query instead!", method));
  53. }
  54. boolean weNeedToCreateCountQuery = !hasNamedQuery(em, countQueryName)
  55. && method.getParameters().hasPageableParameter();
  56. boolean cantExtractQuery = !this.extractor.canExtractQuery();
  57. if (weNeedToCreateCountQuery && cantExtractQuery) {
  58. throw QueryCreationException.create(method, CANNOT_EXTRACT_QUERY);
  59. }
  60. if (parameters.hasPageableParameter()) {
  61. LOG.warn("Finder method {} is backed by a NamedQuery" + " but contains a Pageable parameter! Sorting delivered "
  62. + "via this Pageable will not be applied!", method);
  63. }
  64. }
  65. /**
  66. * Returns whether the named query with the given name exists.
  67. *
  68. * @param em
  69. * @return
  70. */
  71. private static boolean hasNamedQuery(EntityManager em, String queryName) {
  72. try {
  73. em.createNamedQuery(queryName);
  74. return true;
  75. } catch (IllegalArgumentException e) {
  76. LOG.debug("Did not find named query {}", queryName);
  77. return false;
  78. }
  79. }
  80. /**
  81. * Looks up a named query for the given {@link org.springframework.data.repository.query.QueryMethod}.
  82. *
  83. * @param method
  84. * @return
  85. */
  86. public static RepositoryQuery lookupFrom(JpaQueryMethod method, EntityManager em) {
  87. final String queryName = method.getNamedQueryName();
  88. LOG.debug("Looking up named query {}", queryName);
  89. try {
  90. RepositoryQuery query = new NamedQuery(method, em);
  91. LOG.debug("Found named query {}!", queryName);
  92. return query;
  93. } catch (IllegalArgumentException e) {
  94. return null;
  95. }
  96. }
  97. /*
  98. * (non-Javadoc)
  99. * @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(java.lang.Object[])
  100. */
  101. @Override
  102. protected Query doCreateQuery(Object[] values) {
  103. Query query = getEntityManager().createNamedQuery(queryName);
  104. return createBinder(values).bindAndPrepare(query);
  105. }
  106. /*
  107. * (non-Javadoc)
  108. * @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(java.lang.Object[])
  109. */
  110. @Override
  111. protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
  112. EntityManager em = getEntityManager();
  113. TypedQuery<Long> countQuery = null;
  114. if (hasNamedQuery(em, countQueryName)) {
  115. countQuery = em.createNamedQuery(countQueryName, Long.class);
  116. } else {
  117. Query query = createQuery(values);
  118. String queryString = extractor.extractQueryString(query);
  119. countQuery = em.createQuery(QueryUtils.createCountQueryFor(queryString), Long.class);
  120. }
  121. return createBinder(values).bind(countQuery);
  122. }
  123. }