diff --git a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DtoProjectionTransformerDelegate.java b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DtoProjectionTransformerDelegate.java index 0b624d7841..db1eacf5d4 100644 --- a/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DtoProjectionTransformerDelegate.java +++ b/spring-data-jpa/src/main/java/org/springframework/data/jpa/repository/query/DtoProjectionTransformerDelegate.java @@ -36,6 +36,7 @@ * * * @author Mark Paluch + * @author HeeHoon Hong * @since 3.5 */ class DtoProjectionTransformerDelegate { @@ -55,7 +56,20 @@ public boolean applyRewriting() { } public boolean canRewrite() { - return !selectItems.isEmpty() && applyRewriting(); + + if (selectItems.isEmpty() || !applyRewriting()) { + return false; + } + + // Avoid rewriting if the selection list is already expanded and the target type is a record + // to leverage JPA 4.0 implicit DTO mapping. + boolean expansion = selectItems.size() == 1 && selectItems.get(0).size() == 1; + + if (!expansion && returnedType.getReturnedType().isRecord()) { + return false; + } + + return true; } public void appendSelectItem(QueryTokenStream selectItem) { diff --git a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractDtoQueryTransformerUnitTests.java b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractDtoQueryTransformerUnitTests.java index f0c8486772..7f5153a7fa 100644 --- a/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractDtoQueryTransformerUnitTests.java +++ b/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/query/AbstractDtoQueryTransformerUnitTests.java @@ -32,6 +32,7 @@ * Support class for unit tests for {@link DtoProjectionTransformerDelegate}. * * @author Mark Paluch + * @author HeeHoon Hong */ abstract class AbstractDtoQueryTransformerUnitTests
> { @@ -56,7 +57,7 @@ void shouldRewriteSelectionToConstructorExpression() { QueryTokenStream visit = getTransformer(parser).visit(parser.getContext()); assertThat(QueryRenderer.TokenRenderer.render(visit)).isEqualTo( - "SELECT new org.springframework.data.jpa.repository.query.AbstractDtoQueryTransformerUnitTests$MyRecord(p.name) from Person p"); + "SELECT p.name from Person p"); } @Test // GH-3076 @@ -99,7 +100,7 @@ void shouldTranslatePropertySelectionToDto() { QueryTokenStream visit = getTransformer(parser).visit(parser.getContext()); assertThat(QueryRenderer.TokenRenderer.render(visit)).isEqualTo( - "SELECT new org.springframework.data.jpa.repository.query.AbstractDtoQueryTransformerUnitTests$MyRecord(p.foo, p.bar, sum(p.age)) from Person p"); + "SELECT p.foo, p.bar, sum(p.age) from Person p"); } @Test // GH-3895 @@ -110,7 +111,7 @@ void shouldStripAliasesFromDtoProjection() { QueryTokenStream visit = getTransformer(parser).visit(parser.getContext()); assertThat(QueryRenderer.TokenRenderer.render(visit)).isEqualTo( - "SELECT new org.springframework.data.jpa.repository.query.AbstractDtoQueryTransformerUnitTests$MyRecord(sum(p.age), p.foo, p.bar) from Person p"); + "SELECT sum(p.age) As age, p.foo as foo, p.bar AS bar from Person p"); } @Test // GH-3895 @@ -122,7 +123,7 @@ void shouldStripAliasesFromDtoProjectionWithSubquery() { QueryTokenStream visit = getTransformer(parser).visit(parser.getContext()); assertThat(QueryRenderer.TokenRenderer.render(visit)).isEqualTo( - "SELECT new org.springframework.data.jpa.repository.query.AbstractDtoQueryTransformerUnitTests$MyRecord(p.foo, p.bar, cast(p.age as INTEGER), (SELECT b.foo FROM Bar AS b)) from Person p"); + "SELECT p.foo as foo, p.bar AS bar, cast(p.age as INTEGER) As age, (SELECT b.foo FROM Bar AS b) from Person p"); } private JpaQueryMethod getMethod(String name, Class>... parameterTypes) {