Spring DATA Repositoryの@Queryによる検索の戻り値を、DTOやインターフェースにする

Spring DATAのJPA Repositoryを使っているが、戻り値をJPA Entity全体ではなく、任意のフィールドだけにしたいという話があった。

単純にSQLのように SELECT フィールド, フィールド... すると Object の配列になるが、それは避けて任意のDTOやインターフェースにする方法を聞かれたのでメモ。

DTOの場合

必要なフィールドを引数に取る、コンストラクタをもったクラスを用意する。

package example;

@Getter
@AllArgsConstructor
class ResultDto {
    private String id;
    private String name;
}

@Query 内で、 new DTOの完全修飾クラス名(コンストラクタ引数...) を書くと、メソッドの戻り値をDTOにできる。

@Query("SELECT new example.ResultDto(e.id, e.name) FROM EntityClass e")
List<ResultDto> findResultDtoAll();

インターフェースの場合

Getterだけのインターフェースを用意。

interface ResultInterface {
    String getId();
    String getName();
}

@Query 内で、 SELECT エンティティクラス.フィールド... を書くと、メソッドの戻り値をインターフェースにできる。

@Query("SELECT e.id, e.name FROM EntityClass e")
List<ResultInterface> findResultInterfaceAll();

ちなみに実態としては、java.sql.ResultSet に動的プロキシでインターフェースをかぶせている模様。エンティティクラスのフィールドと型が合わない場合などは、Getterメソッド呼び出し時に例外が発生する。

参考

Stack Overflowに質問があり、DTOの場合とインターフェースの場合の両方が記載されている。

stackoverflow.com