Spring Data DTO projection

Viewed 10903

We would like to use a DTO projection over the interface one, thus we created following DTO objects:

PersonDto

@Data
@Builder
@AllArgsConstructor
public class PersonDto {

    private String name;

    private String email;

    private AddressDto address;

}

AddressDto

@Data
@Builder
@AllArgsConstructor
public class AddressDto {

    private String address;

    private String streetNumber;

}

A repository

@Repository
public interface PersonRepository extends JpaRepository<PersonEntity, Long> {

    List<PersonDto> findAllDtoedBy();

}

However, when called we get the exception:

Caused by: org.hibernate.hql.internal.ast.QuerySyntaxException: Unable to locate appropriate constructor on class [com.example.projections.model.PersonDto]. Expected arguments are: java.lang.String, java.lang.String, com.example.projections.model.AddressEntity [select new com.example.projections.model.PersonDto(generatedAlias0.name, generatedAlias0.email, address) from com.example.projections.model.PersonEntity as generatedAlias0 left join generatedAlias0.address as address]
    at org.hibernate.hql.internal.ast.QuerySyntaxException.convert(QuerySyntaxException.java:74) ~[hibernate-core-5.2.11.Final.jar:5.2.11.Final]
    at org.hibernate.hql.internal.ast.ErrorCounter.throwQueryException(ErrorCounter.java:91) ~[hibernate-core-5.2.11.Final.jar:5.2.11.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.analyze(QueryTranslatorImpl.java:272) ~[hibernate-core-5.2.11.Final.jar:5.2.11.Final]
    at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:189) ~[hibernate-core-5.2.11.Final.jar:5.2.11.Final]

Note the line: "...Expected arguments are: java.lang.String, java.lang.String, com.example.projections.model.AddressEntity...".

Obviously it expects the model object AddressEntity, and gets confused when a DTO object (AddressDto) is found instead.

So the question is, since this works with the interface projection, we would expect this to be supported by a DTO projection as well? By looking at the samples on GitHub (https://github.com/spring-projects/spring-data-examples/blob/master/jpa/example/src/main/java/example/springdata/jpa/projections/CustomerRepository.java) and in the Spring Data JPA documentation, we didn't see an example for this case, but we also din't see an explicit statement that this isn't supported

2 Answers

From Spring Data JPA - Reference Documentation:

Another way of defining projections is using value type DTOs that hold properties for the fields that are supposed to be retrieved. These DTO types can be used exactly the same way projection interfaces are used, except that no proxying is going on here and no nested projections can be applied.

I think the reason is this...

You are using @AllArgsConstructor annotation.

@AllArgsConstructor generates a constructor with 1 parameter for each field in your class.

So there is no no-arg constructor present.

You could update your repo method:

List<PersonDto> findAllDtoedBy();

to contain some parameter or provide a no-arg constructor in your classes. (probably by using @NoArgsConstructor)

Related