このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring Data Commons 4.0.3 を使用してください!

プロパティパス

この章では、プロパティパスの概念について説明します。プロパティパスは、モデルとのやり取りのコンテキストにおいて特定の側面を適用するための、ドメインクラス間のナビゲーション形式です。アプリケーションコードは、クエリ内でのプロパティの選択、述語の形成、並べ替えの適用といったインテントを表現するために、データアクセスコンポーネントにプロパティパスを提供します。プロパティパスは、その所有型から生成され、1 つから複数のセグメントで構成できます。

ドメイン駆動設計 [Amazon] の原則に従い、永続ドメインモデルのバックボーンを形成し、Spring Data を介してアクセスされるクラスはエンティティと呼ばれます。オブジェクトグラフへのエントリポイントは集約ルートと呼ばれます。

これらのプロパティをナビゲートして参照する方法を理解することは、リポジトリとクエリ操作を操作するために不可欠です。

プロパティパスの概要

プロパティパスは、ドメインモデルのプロパティをナビゲートするためのシンプルなテキストベースのメカニズムを提供します。このセクションでは、プロパティパスナビゲーションの基礎を紹介し、文字列ベースのアプローチと型安全なアプローチのトレードオフを示します。

ドメインモデルの例
  • Java

  • Kotlin

class Person {
  String firstname, lastname;
  int age;
  Address address;
  List<Address> previousAddresses;

  String getFirstname() { … } // other property accessors omitted for brevity

}

class Address {
  String city, street;

  // accessors omitted for brevity

}
class Person {
  var firstname: String? = null
  var lastname: String? = null
  var age: Int = 0
  var address: Address? = null
  var previousAddresses: List<Address> = emptyList()
}

class Address {
  var city: String? = null
  var street: String? = null
}

プロパティパスでは、並べ替えやフィルタリングなどの Spring Data 操作全体でプロパティ参照を表現するためにドット表記を使用します。

ドット表記プロパティ参照
Sort.by("firstname", "address.city")

プロパティパスは、ドット(.)で区切られた 1 つ以上のセグメントで構成されます。プロパティパスを受け入れるメソッドは、特に明記されていない限り、単一セグメント参照(最上位プロパティ)と複数セグメントナビゲーションをサポートします。

コレクションプロパティと配列プロパティは、コンポーネント型への透過的なトラバーサルをサポートし、ネストされたプロパティへの直接参照を可能にします。

Sort.by("address.city")             (1)

Sort.by("previousAddresses")        (2)

Sort.by("previousAddresses.city")   (3)
1 最上位の address プロパティから city フィールドに移動します。
2previousAddresses コレクション全体を参照します (コレクションベースのソート用の特定のテクノロジによってサポートされています)。
3 コレクション内を移動して、各アドレスの city フィールドで並べ替えます。

文字列ベースのプロパティパスはシンプルで、幅広く適用できますが、考慮すべきトレードオフがあります。

  • 柔軟性 : プロパティパスは柔軟性があり、定数文字列、構成、ユーザー入力の結果として構築できます。

  • 未入力 : 文字列パスはコンパイル時の型情報を保持しません。テキストコンテンツとして型指定されるため、基になるドメイン型に依存しません。

  • リファクタリングリスク : ドメインプロパティの名前を変更するには、多くの場合、文字列リテラルを手動で更新する必要があります。IDE ではこれらの参照を確実に追跡できません。

リファクタリングの安全性と型の一貫性を向上させるには、メソッド参照を用いた型安全なプロパティ参照を推奨します。このアプローチは、プロパティパスをコンパイル時の型情報と関連付け、コンパイラーによる検証と IDE 主導のリファクタリングを可能にします。詳細は型安全なプロパティ参照を参照してください。

実装の詳細については、プロパティパスの内部を参照してください。

プロパティパスの内部

org.springframework.data.core (Javadoc) パッケージは、Spring Data のドメインクラス間ナビゲーションの基盤となります。TypeInformation (Javadoc) インターフェースは、プロパティの型を解決できる型イントロスペクションを提供します。PropertyPath (Javadoc) は、ドメインクラス内のテキストによるナビゲーションパスを表します。

これらを組み合わせると、次のことが実現します。

  • ジェネリクス型の解決とイントロスペクション

  • プロパティパスの作成と検証

  • コレクションやマップなどの複雑なプロパティの実際の型解決

型安全なプロパティ参照

型安全なプロパティ参照は、データアクセスコードにおける一般的なエラーの原因である、脆弱な文字列ベースのプロパティ参照を排除します。このセクションでは、メソッド参照を用いてリファクタリング安全なプロパティパスを表現する方法について説明します。

プロパティパスはオブジェクトナビゲーションのシンプルな表現ですが、文字列ベースのプロパティパスは、プロパティ定義とその使用箇所の距離が長くなると見落とされやすく、リファクタリング時に本質的に脆弱です。TypedPropertyPath (Javadoc) による型安全な代替手段は、メソッド参照からプロパティパスを導出します。これにより、コンパイラーはプロパティ名を検証し、IDE はリファクタリング操作をサポートできます。

  • Java

  • Kotlin

// Inline usage with Sort
Sort.by(Person::getFirstName, Person::getLastName);

// Composed navigation
Sort.by(TypedPropertyPath.of(Person::getAddress).then(Address::getCity),
            Person::getLastName);
// Inline usage with Sort
Sort.by(Person::firstName, Person::lastName)

// Composed navigation
Sort.by(Person::address / Address::city, Person::lastName)

型安全なプロパティパスは、クエリ抽象化および条件ビルダーとシームレスに統合され、文字列ベースのプロパティ参照なしで宣言的なクエリ構築を可能にします。

型安全なプロパティ参照の採用は、現代の Spring 開発原則に合致しています。宣言型、型安全、かつ流れるような API を提供することで、データアクセスに関する推論が簡素化され、IDE リファクタリングのサポートとコンパイラーによる無効なプロパティの早期フィードバックを通じて、潜在的なバグのカテゴリ全体が排除されます。

ラムダイントロスペクションは効率性を高めるためにキャッシュされ、繰り返し利用を可能にします。JVM は静的ラムダインスタンスを再利用することで、1 回限りの解析によるオーバーヘッドを最小限に抑えます。

Spring Data API と直接統合されない場合にコンパイラー検証と IDE サポートの恩恵を受ける型安全なバリアントを探している場合は、TypedPropertyPath を単独で使用できます。

  • Java

  • Kotlin

import static org.springframework.data.core.TypedPropertyPath.path;

// Static import variant
path(Person::getAddress)
                 .then(Address::getCity);

// Fluent composition
TypedPropertyPath.of(Person::getAddress)
                 .then(Address::getCity);
// Kotlin API
TypedPropertyPath.of(Person::address / Address::city)

// as extension function
(Person::address / Address::city).toPath()

型安全なプロパティ参照 API の推奨事項

型安全なプロパティ参照を使用して API を使用 (または構築) する場合は、次の推奨事項を考慮してください。

  • メソッド参照を使用する : コンパイル時の検証と IDE リファクタリングサポートを活用するため、文字列ではなくメソッド参照(例: Person::getFirstName)を受け入れます。メソッド参照は、Java と Kotlin の両方で同様の表現を共有するため、推奨されます。さらに、メソッド参照は表現がシンプルなため、ラムダ式と比較して優れたパフォーマンスベースラインを提供します。

  • TypedPropertyPath の T 型を活用する : 型指定されたプロパティパスを受け入れる場合は、ジェネリクス型 T または TypedPropertyPath<T, P> の使用を検討してください。プロパティパスを、現在の操作内で使用される特定のドメイン型に限定することで、他の型の意図しないプロパティが使用される可能性を低減できます。

    複数のプロパティパスを受け入れるか提供する場合には、所有型のコンテキスト内でプロパティを許可する TypedPropertyPath<T, ?> と、プロパティパスを共通の所有型に制限する T の使用を検討してください。

Graal Native Image コンパイルを使用する場合、直列化可能な TypedPropertyPath ラムダの到達可能性メタデータを提供する必要があります。メソッド参照の代わりにラムダ式を使用する場合は、ラムダ式を含むクラスの Java ソースコードをネイティブイメージ設定に含める必要があります。