Sensei Feature Highlight。ライブラリースコープ

2021年06月09日掲載
by ニック・ヴァン・ヘイバー
ケーススタディ

Sensei Feature Highlight。ライブラリースコープ

2021年06月09日掲載
by ニック・ヴァン・ヘイバー
リソースを見る
リソースを見る

依存関係を柔軟に管理

Sensei のスコープ機能は、常に開発者に愛されてきました。レシピの適用範囲を広げたり、制限したりすることができるので、開発チームは個々のプロジェクトや組織内の業種に合わせて使い方をカスタマイズすることができ、開発者は自分の経験をカスタマイズすることができます。

そして当然のことながら、それはSensei's の継続的なイノベーションプロセスの中心にあります。スコープ」の範囲拡大をテーマにしたイノベーションのブレーンストーミングで、ある質問が出てきました(はい、ダジャレです)。 

"I was trying to create a recipe for ..." しかし、バージョンx以降、フレームワークはこの機能を非推奨としています。もうレシピを作るのが便利なのかどうかわかりません。あなたはどう思いますか?"

もちろん、私たちがレシピの作成を躊躇したのは、これが初めてではありません。レシピは冗長な情報を提供していると思われるかもしれませんが、私たちは、関係する依存関係の限られたバージョンに適用できるものを作ることに価値があると考えています。そのため、Libraryスコープを作成しました。

ライブラリスコープでは、プロジェクト内に依存関係が存在するかどうかをチェックし、条件付きでSensei レシピを適用することができます。これにより、チームがレガシーコードや依存関係をナビゲートする際に、非常に柔軟に対応することができます。

一般設定」の中に「ライブラリ」という範囲があることをご存知の方も多いと思います。では、これは何なのでしょうか?私たちはライブラリスコープを検索と同じようにYAMLで表示できるようにしました。これにより、ユーザーエクスペリエンスが向上し、レシピを作成する際に一般設定に移動してからメタデータを更新するという流れを断ち切ることができます。これらのスコープはさらにYAMLに追加される予定ですが、ここではLibrary Scopeから始めました。

それでは、例を挙げてその仕組みをもう少し詳しく説明しましょう。

hibernate-jpamodelgen に適用されるライブラリスコープ

次のようなケースを想像してみてください。 

データを照会できるSpring Web REST APIを作成したいと考えています。ベストプラクティスにしたがって、問い合わせたいエンティティのモデルを作成します。次に、Hibernate ORMへの依存関係を追加して、データベース構造をいじらなくても済むようにします。ORMがそれを代行してくれます。また、データアクセス層(CRUDリポジトリなど)からコントローラにデータを提供するサービスを作成する必要があります。最後に、API用のコントローラクラスを作成し、許可されたクエリをエンドポイントとして公開します。

問い合わせ可能なフィールドごとに異なるエンドポイントを公開する必要がないように、代わりにJPA 2仕様を使用することにしました。そのためには、リクエストURLからコントローラ内に仕様を作成します。この仕様書には、探しているエンティティがどのようなものであるかを記述します。Specification`クラスでは、`toPredicate`メソッドを実装して、仕様を検証する方法を示しています。

しかし、`toPredicate`メソッドで問題に直面しています。述語を作成するためには、比較するデータベースの列の名前を知る必要があります。しかし、ORMを使用しているため、これらのカラムは個別のモデルには存在しません。そこで、HibernateのJPA 2 Metamodel Generator()が助けてくれます。これにより、処理を依頼したエンティティのメタモデルが生成されます。これらのメタモデルでは、カラム名をハードコーディングする代わりに、プロパティとして参照することができます。

Sensei レシピの作成

Sensei は、プロジェクトに携わる人にメタモデルの使用を思い出させ、カラム名がどこにもハードコードされていないことを確認することで、その人を助けることができます。それでは、実際に使ってみましょう。

まず始めに、`toPredicate`メソッドを見てみましょう

述語法へ

この基本的な述語は、エンティティの名前を比較するだけです。これを `and` 節を使って拡張することもできますが、このレシピの目的では、この「単純な」チェックで十分です。

レシピの検索コンポーネントでは、ルートパラメータのメソッド `get()` を呼び出したいので、ドロップダウンから `methodcall` オプションを選択します。次に、`javax.persistence.criteria`パッケージの`Path`インターフェイスでシグネチャが宣言されている、`get`という名前のメソッドコールに検索を限定したいとします。このメソッドはオーバーロードされているので、レシピは単一の文字列を引数に取るバリアントにのみ適用されることを検索に伝える必要があります。コード内にカラム名があるという問題を解決するために、代わりにメタモデルジェネレータが提供するのと同じタイプの `SingularAttribute` 型の引数を使用したいと思います。

レシピの検索条件を設定する

これまでに作成したレシピは、コードベースがHibernate Model Generatorを使用するように設定されているかどうかに関わらず、JPA 2の`Path`インターフェースを使用するコードベースで起動します。プロジェクト内にこのライブラリが存在する場合は、それを使用すべきであることをユーザーに示したいので、レシピにライブラリスコープを追加します。

本レシピの検索範囲の限定

そしてついに、レシピが完成しました。

テストレシピの作成方法call

このレシピでは、文字列を引数として使用する`Path#get`の出現にフラグが立てられます。上のスクリーンショットのハイライトされたサンプルコードを見ればわかるように、このレシピはカラム名のリテラル名が中間変数に格納されている場合にも機能します。

注 - ライブラリが利用できない場合には、スコープの前に `not` 節を付けることで、ライブラリのスコープを反転させることもできます。

結論

上の例で見たように、この新機能を使えば、プロジェクト内の依存関係の存在に基づいてレシピを適用することで、より便利なレシピを作成することができます。さらにパワーアップするために、依存関係が存在するかどうかをチェックするだけでなく、依存関係の特定のバージョンに条件を適用するなど、例で示した以外のオプションも含まれています。 

この機能の主な使用例としては、レシピが重複した情報を提供するのを防ぐこと、特定のバージョンの依存関係に関連する問題を検出すること、また、ある依存関係のバージョンから次のバージョンへの移行を実行することなどが挙げられます。この機能をどのようにお使いになるか、皆様からのご意見をお待ちしております。

Sensei のすべての機能と同様に、ライブラリの範囲に関する詳細な情報は、リファレンスドキュメントに記載されています。

リソースを見る
リソースを見る

著者

ニック・バン・ヘイバー

もっと知りたい?

セキュアコーディングに関する最新の知見をブログでご紹介しています。

当社の豊富なリソースライブラリは、安全なコーディングアップスキルに対する人間的なアプローチを強化することを目的としています。

ブログを見る
もっと知りたい?

開発者主導のセキュリティに関する最新の研究成果を入手する

ホワイトペーパーからウェビナーまで、開発者主導のセキュアコーディングを始めるために役立つリソースが満載のリソースライブラリです。今すぐご覧ください。

リソース・ハブ

Sensei Feature Highlight。ライブラリースコープ

2021年06月09日掲載
ニック・ヴァン・ヘイバー著

依存関係を柔軟に管理

Sensei のスコープ機能は、常に開発者に愛されてきました。レシピの適用範囲を広げたり、制限したりすることができるので、開発チームは個々のプロジェクトや組織内の業種に合わせて使い方をカスタマイズすることができ、開発者は自分の経験をカスタマイズすることができます。

そして当然のことながら、それはSensei's の継続的なイノベーションプロセスの中心にあります。スコープ」の範囲拡大をテーマにしたイノベーションのブレーンストーミングで、ある質問が出てきました(はい、ダジャレです)。 

"I was trying to create a recipe for ..." しかし、バージョンx以降、フレームワークはこの機能を非推奨としています。もうレシピを作るのが便利なのかどうかわかりません。あなたはどう思いますか?"

もちろん、私たちがレシピの作成を躊躇したのは、これが初めてではありません。レシピは冗長な情報を提供していると思われるかもしれませんが、私たちは、関係する依存関係の限られたバージョンに適用できるものを作ることに価値があると考えています。そのため、Libraryスコープを作成しました。

ライブラリスコープでは、プロジェクト内に依存関係が存在するかどうかをチェックし、条件付きでSensei レシピを適用することができます。これにより、チームがレガシーコードや依存関係をナビゲートする際に、非常に柔軟に対応することができます。

一般設定」の中に「ライブラリ」という範囲があることをご存知の方も多いと思います。では、これは何なのでしょうか?私たちはライブラリスコープを検索と同じようにYAMLで表示できるようにしました。これにより、ユーザーエクスペリエンスが向上し、レシピを作成する際に一般設定に移動してからメタデータを更新するという流れを断ち切ることができます。これらのスコープはさらにYAMLに追加される予定ですが、ここではLibrary Scopeから始めました。

それでは、例を挙げてその仕組みをもう少し詳しく説明しましょう。

hibernate-jpamodelgen に適用されるライブラリスコープ

次のようなケースを想像してみてください。 

データを照会できるSpring Web REST APIを作成したいと考えています。ベストプラクティスにしたがって、問い合わせたいエンティティのモデルを作成します。次に、Hibernate ORMへの依存関係を追加して、データベース構造をいじらなくても済むようにします。ORMがそれを代行してくれます。また、データアクセス層(CRUDリポジトリなど)からコントローラにデータを提供するサービスを作成する必要があります。最後に、API用のコントローラクラスを作成し、許可されたクエリをエンドポイントとして公開します。

問い合わせ可能なフィールドごとに異なるエンドポイントを公開する必要がないように、代わりにJPA 2仕様を使用することにしました。そのためには、リクエストURLからコントローラ内に仕様を作成します。この仕様書には、探しているエンティティがどのようなものであるかを記述します。Specification`クラスでは、`toPredicate`メソッドを実装して、仕様を検証する方法を示しています。

しかし、`toPredicate`メソッドで問題に直面しています。述語を作成するためには、比較するデータベースの列の名前を知る必要があります。しかし、ORMを使用しているため、これらのカラムは個別のモデルには存在しません。そこで、HibernateのJPA 2 Metamodel Generator()が助けてくれます。これにより、処理を依頼したエンティティのメタモデルが生成されます。これらのメタモデルでは、カラム名をハードコーディングする代わりに、プロパティとして参照することができます。

Sensei レシピの作成

Sensei は、プロジェクトに携わる人にメタモデルの使用を思い出させ、カラム名がどこにもハードコードされていないことを確認することで、その人を助けることができます。それでは、実際に使ってみましょう。

まず始めに、`toPredicate`メソッドを見てみましょう

述語法へ

この基本的な述語は、エンティティの名前を比較するだけです。これを `and` 節を使って拡張することもできますが、このレシピの目的では、この「単純な」チェックで十分です。

レシピの検索コンポーネントでは、ルートパラメータのメソッド `get()` を呼び出したいので、ドロップダウンから `methodcall` オプションを選択します。次に、`javax.persistence.criteria`パッケージの`Path`インターフェイスでシグネチャが宣言されている、`get`という名前のメソッドコールに検索を限定したいとします。このメソッドはオーバーロードされているので、レシピは単一の文字列を引数に取るバリアントにのみ適用されることを検索に伝える必要があります。コード内にカラム名があるという問題を解決するために、代わりにメタモデルジェネレータが提供するのと同じタイプの `SingularAttribute` 型の引数を使用したいと思います。

レシピの検索条件を設定する

これまでに作成したレシピは、コードベースがHibernate Model Generatorを使用するように設定されているかどうかに関わらず、JPA 2の`Path`インターフェースを使用するコードベースで起動します。プロジェクト内にこのライブラリが存在する場合は、それを使用すべきであることをユーザーに示したいので、レシピにライブラリスコープを追加します。

本レシピの検索範囲の限定

そしてついに、レシピが完成しました。

テストレシピの作成方法call

このレシピでは、文字列を引数として使用する`Path#get`の出現にフラグが立てられます。上のスクリーンショットのハイライトされたサンプルコードを見ればわかるように、このレシピはカラム名のリテラル名が中間変数に格納されている場合にも機能します。

注 - ライブラリが利用できない場合には、スコープの前に `not` 節を付けることで、ライブラリのスコープを反転させることもできます。

結論

上の例で見たように、この新機能を使えば、プロジェクト内の依存関係の存在に基づいてレシピを適用することで、より便利なレシピを作成することができます。さらにパワーアップするために、依存関係が存在するかどうかをチェックするだけでなく、依存関係の特定のバージョンに条件を適用するなど、例で示した以外のオプションも含まれています。 

この機能の主な使用例としては、レシピが重複した情報を提供するのを防ぐこと、特定のバージョンの依存関係に関連する問題を検出すること、また、ある依存関係のバージョンから次のバージョンへの移行を実行することなどが挙げられます。この機能をどのようにお使いになるか、皆様からのご意見をお待ちしております。

Sensei のすべての機能と同様に、ライブラリの範囲に関する詳細な情報は、リファレンスドキュメントに記載されています。

弊社製品や関連するセキュアコーディングのトピックに関する情報をお送りする許可をお願いします。当社は、お客様の個人情報を細心の注意を払って取り扱い、マーケティング目的で他社に販売することは決してありません。

フォームを送信するには、「Analytics」のCookieを有効にしてください。完了したら、再度無効にしてください。