Skip to content

Document that simple base-repository method overrides cannot return projections #2473

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mereshow opened this issue Oct 4, 2021 · 2 comments
Assignees
Labels
type: documentation A documentation update

Comments

@mereshow
Copy link

mereshow commented Oct 4, 2021

Even if an interface projection (DTO) is used as the return type of the findAll() method of a repository, the method returns the entity associated with the repository, instead of the DTO.

I create an entity (reduced for compactness):

@Entity
@Table(name = "arpsi")
public class Arpsi {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String nombre;
    private String codigo;
    @JsonRawValue
    private String dph;
    // getters and setters not shown
}

I create a DTO with fewer fields:

public interface ArpsiDTO {
    public Long getId();
    public String getNombre();
}

I create a repository:

public interface ArpsiRepository extends Repository<Arpsi, Long> {
    Iterable<ArpsiDTO> findById();
    Iterable<ArpsiDTO> findAll();
    ...
}

I use a service that uses the repository to retrieve the data. I use ArpsiDTO as the return type in every step, but the service gets the Entity instead of the DTO (with errors due to lazy initialization of a collection).

I tested it with several repositories, and only methods that include any condition (findByX or similar) return the DTO.
Converting the ArpsiDTO to a class, and using a constructor based projection with a custom query for the findAll() method works as expected (returns the DTO):

@Query("SELECT new com.equixlab.api.model.augas.arpsi.ArpsiDTO(a.id, a.nombre, a.codigo) FROM Arpsi a")
	Iterable<ArpsiDTO> findAll();

It also works if we create a method with an always true condition, such as:

Iterable<ArpsiDTO> findAllByIdNotNull();

I suppose this happens with all the methods that exist in the CrudRepository interface and expose in a Repository interface (inspecting the CrudRepository interface, the methods use <T> or <S extends T>, so a DTO cannot be used/returned).

Is this by design? I could not find anything in the docs.

@mp911de
Copy link
Member

mp911de commented Oct 5, 2021

findAll is a method that is defined in CrudRepository and implemented in SimpleJpaRepository. Without @Query, findAll maps to SimpleJpaRepository.findAll() which is a regular Java method that isn't aware of the repository definition (and it can't ever be).

Therefore projections do not work with implementation methods.

Adding @Query turns the method into a query method using query derivation and because the query mechanism is different, the method gets enabled for projections. We should mention this in our documentation.

@mp911de mp911de changed the title Repository findAll() ignores interface projection and returns entity Document that simple base-repository method overrides cannot return projections Oct 5, 2021
@mp911de mp911de transferred this issue from spring-projects/spring-data-jpa Oct 5, 2021
mp911de added a commit that referenced this issue Oct 5, 2021
mp911de added a commit that referenced this issue Oct 5, 2021
@mp911de mp911de closed this as completed in 03de599 Oct 5, 2021
@mp911de mp911de added the type: documentation A documentation update label Oct 5, 2021
@mp911de mp911de added this to the 2.4.14 (2020.0.14) milestone Oct 5, 2021
@mereshow
Copy link
Author

mereshow commented Oct 5, 2021

findAll is a method that is defined in CrudRepository and implemented in SimpleJpaRepository. Without @Query, findAll maps to SimpleJpaRepository.findAll() which is a regular Java method that isn't aware of the repository definition (and it can't ever be).

Therefore projections do not work with implementation methods.

Adding @Query turns the method into a query method using query derivation and because the query mechanism is different, the method gets enabled for projections. We should mention this in our documentation.

This is what I deducted after reviewing the CrudRepository interface. Adding this explanation to the documentation would help newcomers like me.
Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

3 participants