Avoid DTO Constructor Expression rewriting for selection of nested properties.
We back off from rewriting String-based queries to use DTO Constructor expressions if the query selects a property that is assignable to the return type. Closes #3862
This commit is contained in:
@@ -161,7 +161,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
Class<?> returnedJavaType = processor.getReturnedType().getReturnedType();
|
||||
|
||||
if (query.isDefaultProjection() || !returnedType.isProjecting() || returnedJavaType.isInterface()
|
||||
|| query.isNativeQuery()) {
|
||||
|| query.isNative()) {
|
||||
return returnedType;
|
||||
}
|
||||
|
||||
@@ -178,23 +178,23 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
return new NonProjectingReturnedType(returnedType);
|
||||
}
|
||||
|
||||
String alias = query.getAlias();
|
||||
String projection = query.getProjection();
|
||||
String projectionToUse = query.<@Nullable String> doWithEnhancer(queryEnhancer -> {
|
||||
|
||||
// we can handle single-column and no function projections here only
|
||||
if (StringUtils.hasText(projection) && (projection.indexOf(',') != -1 || projection.indexOf('(') != -1)) {
|
||||
return returnedType;
|
||||
}
|
||||
String alias = queryEnhancer.detectAlias();
|
||||
String projection = queryEnhancer.getProjection();
|
||||
|
||||
if (StringUtils.hasText(alias) && StringUtils.hasText(projection)) {
|
||||
alias = alias.trim();
|
||||
projection = projection.trim();
|
||||
if (projection.startsWith(alias + ".")) {
|
||||
projection = projection.substring(alias.length() + 1);
|
||||
// we can handle single-column and no function projections here only
|
||||
if (StringUtils.hasText(projection) && (projection.indexOf(',') != -1 || projection.indexOf('(') != -1)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(projection)) {
|
||||
if (StringUtils.hasText(alias) && StringUtils.hasText(projection)) {
|
||||
alias = alias.trim();
|
||||
projection = projection.trim();
|
||||
if (projection.startsWith(alias + ".")) {
|
||||
projection = projection.substring(alias.length() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int space = projection.indexOf(' ');
|
||||
|
||||
@@ -202,10 +202,15 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
projection = projection.substring(0, space);
|
||||
}
|
||||
|
||||
return projection;
|
||||
});
|
||||
|
||||
if (StringUtils.hasText(projectionToUse)) {
|
||||
|
||||
Class<?> propertyType;
|
||||
|
||||
try {
|
||||
PropertyPath from = PropertyPath.from(projection, getQueryMethod().getEntityInformation().getJavaType());
|
||||
PropertyPath from = PropertyPath.from(projectionToUse, getQueryMethod().getEntityInformation().getJavaType());
|
||||
propertyType = from.getLeafType();
|
||||
} catch (PropertyReferenceException ignored) {
|
||||
propertyType = null;
|
||||
@@ -223,7 +228,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
|
||||
return returnedType;
|
||||
}
|
||||
|
||||
String getSortedQueryString(Sort sort, ReturnedType returnedType) {
|
||||
QueryProvider getSortedQuery(Sort sort, ReturnedType returnedType) {
|
||||
return querySortRewriter.getSorted(query, sort, returnedType);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -46,6 +47,11 @@ class DefaultEntityQuery implements EntityQuery, DeclaredQuery {
|
||||
this.queryEnhancer = queryEnhancerFactory.create(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithEnhancer(Function<QueryEnhancer, T> function) {
|
||||
return function.apply(queryEnhancer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNative() {
|
||||
return query.isNative();
|
||||
|
||||
@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -33,6 +34,8 @@ enum EmptyIntrospectedQuery implements EntityQuery {
|
||||
|
||||
EmptyIntrospectedQuery() {}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasParameterBindings() {
|
||||
return false;
|
||||
@@ -57,11 +60,21 @@ enum EmptyIntrospectedQuery implements EntityQuery {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithEnhancer(Function<QueryEnhancer, T> function) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstructorExpression() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNative() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaultProjection() {
|
||||
return false;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.jpa.repository.query;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
/**
|
||||
@@ -45,6 +47,15 @@ public interface EntityQuery extends ParametrizedQuery {
|
||||
return new DefaultEntityQuery(preparsed, enhancerFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a {@link Function} to the query enhancer used by this query.
|
||||
*
|
||||
* @param function the callback function.
|
||||
* @return
|
||||
* @param <T>
|
||||
*/
|
||||
<T extends @Nullable Object> T doWithEnhancer(Function<QueryEnhancer, T> function);
|
||||
|
||||
/**
|
||||
* Returns whether the query is using a constructor expression.
|
||||
*
|
||||
@@ -52,6 +63,11 @@ public interface EntityQuery extends ParametrizedQuery {
|
||||
*/
|
||||
boolean hasConstructorExpression();
|
||||
|
||||
/**
|
||||
* @return whether the underlying query has at least one named parameter.
|
||||
*/
|
||||
boolean isNative();
|
||||
|
||||
/**
|
||||
* Returns whether the query uses the default projection, i.e. returns the main alias defined for the query.
|
||||
*/
|
||||
|
||||
@@ -30,7 +30,7 @@ import java.util.List;
|
||||
* @see EntityQuery#create(DeclaredQuery, QueryEnhancerSelector)
|
||||
* @see TemplatedQuery#create(String, JpaQueryMethod, JpaQueryConfiguration)
|
||||
*/
|
||||
interface ParametrizedQuery extends QueryProvider {
|
||||
public interface ParametrizedQuery extends QueryProvider {
|
||||
|
||||
/**
|
||||
* @return whether the underlying query has at least one parameter.
|
||||
|
||||
Reference in New Issue
Block a user