From 23e27f3332f50623bb810a9c96d90672b4264bb1 Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Thu, 7 Nov 2013 11:39:10 +0100 Subject: [PATCH] DATAJPA-424 - Fixed alias detection in manually defined queries using SpEL. ExpressionBasedStringQuery now resolves and evaluates SpEL expressions of the actual query in the constructor and passes the resolved query to the StringQuery constructor. This enables the alias detection mechanism to work properly. Original pull request: #51 --- .../query/ExpressionBasedStringQuery.java | 29 +++++-------------- .../MappedTypeRepositoryIntegrationTests.java | 18 ++++++++++++ .../ExpressionBasedStringQueryUnitTests.java | 14 +++++++++ .../sample/MappedTypeRepository.java | 6 ++++ 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java index 5f272a967..230fa87db 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQuery.java @@ -37,9 +37,6 @@ import org.springframework.util.Assert; class ExpressionBasedStringQuery extends StringQuery { private static final String ENTITY_NAME = "entityName"; - private final JpaEntityMetadata metadata; - - private String parsedQuery; /** * Creates a new {@link ExpressionBasedStringQuery} for the given query and {@link EntityMetadata}. @@ -48,28 +45,18 @@ class ExpressionBasedStringQuery extends StringQuery { * @param metadata must not be {@literal null}. */ public ExpressionBasedStringQuery(String query, JpaEntityMetadata metadata) { - - super(query); - Assert.notNull(metadata, "JpaEntityMetadata must not be null!"); - this.metadata = metadata; + super(renderQueryIfExpressionOrReturnQuery(query, metadata)); } - /* - * (non-Javadoc) - * @see org.springframework.data.jpa.repository.query.StringQuery#getQueryString() + /** + * @param query, the query expression potentially containing a SpEL expression. Must not be {@literal null}.} + * @param metadata the {@link JpaEntityMetadata} for the given entity. Must not be {@literal null}. + * @return */ - @Override - public String getQueryString() { + private static String renderQueryIfExpressionOrReturnQuery(String query, JpaEntityMetadata metadata) { - if (parsedQuery == null) { - String rawQuery = super.getQueryString(); - this.parsedQuery = renderQueryIfExpressionOrReturnQuery(rawQuery); - } - - return this.parsedQuery; - } - - private String renderQueryIfExpressionOrReturnQuery(String query) { + Assert.notNull(query, "query must not be null!"); + Assert.notNull(metadata, "metadata must not be null!"); if (!containsExpression(query)) { return query; diff --git a/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java index 7b0f2f0ae..3889b0882 100644 --- a/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/MappedTypeRepositoryIntegrationTests.java @@ -23,6 +23,9 @@ import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.sample.ConcreteType1; import org.springframework.data.jpa.domain.sample.ConcreteType2; import org.springframework.data.jpa.repository.sample.ConcreteRepository1; @@ -61,4 +64,19 @@ public class MappedTypeRepositoryIntegrationTests { assertThat(concretes1.size(), is(1)); assertThat(concretes2.size(), is(1)); } + + /** + * @see DATAJPA-424 + */ + @Test + public void supportForPaginationCustomQueryMethodsWithEntityExpression() { + + concreteRepository1.save(new ConcreteType1("foo")); + concreteRepository2.save(new ConcreteType2("foo")); + + Page page = concreteRepository2.findByAttribute1Custom("foo", new PageRequest(0, 10, + Sort.Direction.DESC, "attribute1")); + + assertThat(page.getNumberOfElements(), is(1)); + } } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java index 4a8bde9aa..6c05718bf 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ExpressionBasedStringQueryUnitTests.java @@ -48,4 +48,18 @@ public class ExpressionBasedStringQueryUnitTests { StringQuery query = new ExpressionBasedStringQuery(source, metadata); assertThat(query.getQueryString(), is("select from User u where u.firstname like :firstname")); } + + /** + * @DATAJPA-424 + */ + @Test + public void renderAliasInExpressionQueryCorrectly() { + + when(metadata.getEntityName()).thenReturn("User"); + + StringQuery query = new ExpressionBasedStringQuery("select u from #{#entityName} u", metadata); + assertThat(query.getAlias(), is("u")); + assertThat(query.getQueryString(), is("select u from User u")); + } + } diff --git a/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java b/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java index e387a653d..cb97b82e8 100644 --- a/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/sample/MappedTypeRepository.java @@ -18,9 +18,12 @@ package org.springframework.data.jpa.repository.sample; import java.util.List; import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.domain.sample.AbstractMappedType; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; /** * @author Thomas Darimont @@ -30,4 +33,7 @@ public interface MappedTypeRepository extends JpaR @Query("from #{#entityName} t where t.attribute1=?1") List findAllByAttribute1(String attribute1); + + @Query("SELECT o FROM #{#entityName} o where o.attribute1=:attribute1") + Page findByAttribute1Custom(@Param("attribute1") String attribute1, Pageable pageable); }