spring-projects/spring-data-commons

Entity return type marked as projection

Closed this issue · 2 comments

Due to spring-projects/spring-data-jpa#3076 we've noticed a bug occurring in an old repository class of ours.
The setup is as follows:

@Entity
public class EntityA {
    // some fields, getters and setters...
}

@Entity
public class EntityB {
    // some fields, getters and setters...
}

@Repository
public interface RepositoryA extends JpaRepository<EntityA, Long> {

    @Query("SELECT b FROM EntityB b where b.field = :field")
    List<EntityB> getEntityBBySomeField(final @Param("field") String field)
}

This is the result of some legacy code, and likely someone being too lazy to create a separate repository class for just one method.
The QueryMethod object for this repository method now returns the class EntityA instead of EntityB when calling its getDomainClass method. The logic used to determine the correct domain class seems to always prioritize the repository type over the method domain type.

this.domainClass = Lazy.of(() -> {

Class<?> repositoryDomainClass = metadata.getDomainType();
Class<?> methodDomainClass = metadata.getReturnedDomainClass(method);

return repositoryDomainClass == null || repositoryDomainClass.isAssignableFrom(methodDomainClass)
		? methodDomainClass
		: repositoryDomainClass;
});

This then causes the ReturnedType object for the method to mark the return type as a projection since the return type doesn't match the domain type, which then triggers the query rewrite from the issue above.
All that then results in a runtime exception since the generated constructor query is incorrect as our EntityB class doesn't have a constructor and the query validation fails with an obscure syntax error.
For now I'll fix this by just moving the method in question to a new repository, but it still feels like this should work, and it has worked for a long time without any issues.

Thanks for reaching out and looking into the code. This is a known issue that was unintentionally introduced. It has been fixed via spring-projects/spring-data-jpa#3895 in the 3.5.1 snapshot builds.

Technically, the returned type is considered correctly a projection. With DTO query rewriting, we only introspect selection items but not their origin to verify what type is being returned. Therefore the fix checks whether the returned type is JPA-managed. If so, we refrain from rewriting the query.

Please check out the latest snapshots whether they bring back the previous behavior for you.

Yes, that seems to have fixed it. Thanks for your quick reply. And it's quite interesting I didn't know this was considered a projection too, I learned something new today, even if it doesn't seem to make any notable difference.