DATAJPA-885 - Make sure manually defined queries returning domain type don't use tuples.
We now check manually defined queries for whether the projection is equal to the used alias and don't use a Tuple query in this case. This allows the manually defined queries to still define the projections manually but also the returned objects be wrapped with projection interfaces easily.
This commit is contained in:
@@ -131,7 +131,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
|
||||
EntityManager em = getEntityManager();
|
||||
|
||||
if (this.query.hasConstructorExpression()) {
|
||||
if (this.query.hasConstructorExpression() || this.query.isDefaultProjection()) {
|
||||
return em.createQuery(queryString);
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ public abstract class QueryUtils {
|
||||
|
||||
private static final Pattern ALIAS_MATCH;
|
||||
private static final Pattern COUNT_MATCH;
|
||||
private static final Pattern PROJECTION_CLAUSE = Pattern.compile("select\\s+(.+)\\s+from");
|
||||
|
||||
private static final Pattern NO_DIGITS = Pattern.compile("\\D+");
|
||||
private static final String IDENTIFIER = "[\\p{Lu}\\P{InBASIC_LATIN}\\p{Alnum}._$]+";
|
||||
@@ -464,6 +465,21 @@ public abstract class QueryUtils {
|
||||
return CONSTRUCTOR_EXPRESSION.matcher(query).find();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the projection part of the query, i.e. everything between {@code select} and {@code from}.
|
||||
*
|
||||
* @param query must not be {@literal null} or empty.
|
||||
* @return
|
||||
* @since 1.10.2
|
||||
*/
|
||||
public static String getProjection(String query) {
|
||||
|
||||
Assert.hasText(query, "Query must not be null or empty!");
|
||||
|
||||
Matcher matcher = PROJECTION_CLAUSE.matcher(query);
|
||||
return matcher.find() ? matcher.group(1) : "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a criteria API {@link javax.persistence.criteria.Order} from the given {@link Order}.
|
||||
*
|
||||
|
||||
@@ -145,6 +145,15 @@ class StringQuery {
|
||||
return hasConstructorExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the query uses the default projection, i.e. returns the main alias defined for the query.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public boolean isDefaultProjection() {
|
||||
return QueryUtils.getProjection(query).equals(alias);
|
||||
}
|
||||
|
||||
/**
|
||||
* A parser that extracts the parameter bindings from a given query string.
|
||||
*
|
||||
|
||||
@@ -21,10 +21,12 @@ import static org.mockito.Matchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -223,7 +225,23 @@ public class SimpleJpaQueryUnitTests {
|
||||
|
||||
jpaQuery.doCreateCountQuery(new Object[] { new PageRequest(0, 10) });
|
||||
|
||||
verify(em, times(1)).createNativeQuery(anyString());
|
||||
verify(em).createNativeQuery(anyString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-885
|
||||
*/
|
||||
@Test
|
||||
public void projectsWithManuallyDeclaredQuery() throws Exception {
|
||||
|
||||
AbstractJpaQuery jpaQuery = createJpaQuery(SampleRepository.class.getMethod("projectWithExplicitQuery"));
|
||||
|
||||
jpaQuery.createQuery(new Object[0]);
|
||||
|
||||
verify(em, times(0)).createQuery(anyString(), eq(Tuple.class));
|
||||
|
||||
// Two times, first one is from the query validation
|
||||
verify(em, times(2)).createQuery(anyString());
|
||||
}
|
||||
|
||||
private AbstractJpaQuery createJpaQuery(Method method) {
|
||||
@@ -248,5 +266,10 @@ public class SimpleJpaQueryUnitTests {
|
||||
|
||||
@Query(USER_QUERY)
|
||||
Page<User> pageByAnnotatedQuery(Pageable pageable);
|
||||
|
||||
@Query("select u from User u")
|
||||
Collection<UserProjection> projectWithExplicitQuery();
|
||||
}
|
||||
|
||||
interface UserProjection {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user