1. 概要

Apache DeltaSpike は、Javaプロジェクト用のCDI拡張機能のコレクションを提供するプロジェクトです。 実行時にCDI実装を使用できるようにする必要があります。

もちろん、CDI のさまざまな実装(JBoss WeldまたはOpenWebBeans)で動作します。 また、多くのアプリケーションサーバーでテストされています。

このチュートリアルでは、最もよく知られていて便利なデータモジュールに焦点を当てます。

2. DeltaSpikeデータモジュールのセットアップ

Apache DeltaSpike Dataモジュールは、リポジトリパターンの実装を簡素化するために使用されます。 クエリの作成と実行に一元化されたロジックを提供することで、ボイラープレートコードを削減できます

Spring Dataプロジェクトと非常によく似ています。 データベースをクエリするには、定義された命名規則に従うか、 @Query アノテーションを含むメソッド宣言(実装なし)を定義する必要があります。 実装はCDI拡張機能によって行われます。

次のサブセクションでは、アプリケーションでApacheDeltaSpikeDataモジュールをセットアップする方法について説明します。

2.1. 必要な依存関係

アプリケーションでApacheDeltaSpikeDataモジュールを使用するには、必要な依存関係を設定する必要があります。

Mavenがビルドツールである場合、以下を使用する必要があります。

<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-api</artifactId>
    <version>1.8.2</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>org.apache.deltaspike.modules</groupId>
    <artifactId>deltaspike-data-module-impl</artifactId>
    <version>1.8.2</version>
    <scope>runtime</scope>
</dependency>

Gradleを使用している場合:

runtime 'org.apache.deltaspike.modules:deltaspike-data-module-impl'
compile 'org.apache.deltaspike.modules:deltaspike-data-module-api'

Apache DeltaSpikeデータモジュールアーティファクトは、MavenCentralで入手できます。

データモジュールを使用してアプリケーションを実行するには、実行時に利用可能なJPAおよびCDI実装も必要です

JavaSEアプリケーションでApacheDeltaSpikeを実行することは可能ですが、ほとんどの場合、アプリケーションサーバー(WildflyやWebSphereなど)にデプロイされます。

アプリケーションサーバーはJakartaEEを完全にサポートしているため、これ以上何もする必要はありません。 Java SEアプリケーションの場合、これらの実装を提供する必要があります(たとえば、HibernateとJBoss Weldに依存関係を追加することによって)。

次に、EntityManagerに必要な構成についても説明します。

2.2. エンティティマネージャの構成

Dataモジュールでは、EntityManagerをCDIに挿入する必要があります。

これは、CDIプロデューサーを使用して実現できます。

public class EntityManagerProducer {

    @PersistenceContext(unitName = "primary")
    private EntityManager entityManager;

    @ApplicationScoped
    @Produces
    public EntityManager getEntityManager() {
        return entityManager;
    }
}

上記のコードは、persistence.xmlファイルで定義されたprimaryという名前の永続性ユニットがあることを前提としています。

定義の例として以下を見てみましょう。

<persistence-unit name="primary" transaction-type="JTA">
   <jta-data-source>java:jboss/datasources/baeldung-jee7-seedDS</jta-data-source>
   <properties>
      <property name="hibernate.hbm2ddl.auto" value="create-drop" />
      <property name="hibernate.show_sql" value="false" />
   </properties>
</persistence-unit>

この例の永続性ユニットはJTAトランザクションタイプを使用します。これは、使用するトランザクション戦略を提供する必要があることを意味します。

2.3. 取引戦略

データソースにJTAトランザクションタイプを使用している場合は、ApacheDeltaSpikeリポジトリで使用されるトランザクション戦略を定義する必要があります apache-deltaspike.properties ファイル内( META-INF ディレクトリの下)で実行できます。

globalAlternatives.org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy=org.apache.deltaspike.jpa.impl.transaction.ContainerManagedTransactionStrategy

定義できるトランザクション戦略には、次の4つのタイプがあります。

  • BeanManagedUserTransactionStrategy
  • ResourceLocalTransactionStrategy
  • ContainerManagedTransactionStrategy
  • EnvironmentAwareTransactionStrategy

それらはすべてorg.apache.deltaspike.jpa.spi.transaction.TransactionStrategyを実装しています。

これは、データモジュールに必要な構成の最後の部分でした。

次に、リポジトリパターンクラスを実装する方法を示します。

3. リポジトリクラス

Apache DeltaSpikeデータモジュールを使用している場合、任意の抽象クラスまたはインターフェイスをリポジトリクラスにすることができます。

必要なのは、リポジトリが処理するJPAエンティティを定義するforEntity属性を持つ@Repositoryアノテーション追加することだけです。

@Entity
public class User {
    // ...
}  

@Repository(forEntity = User.class) 
public interface SimpleUserRepository { 
    // ... 
}

または抽象クラスを使用する場合:

@Repository(forEntity = User.class)
public abstract class SimpleUserRepository { 
    // ... 
}

データモジュールは、そのようなアノテーションを持つクラス(またはインターフェイス)を検出し、内部にあるメソッドを処理します。

実行するクエリを定義する可能性はほとんどありません。 次のセクションでは、1つずつ説明します。

4. メソッド名からのクエリ

クエリを定義する最初の可能性は、定義された命名規則に従うメソッド名を使用することです。

以下のようになります。

(Entity|Optional<Entity>|List<Entity>|Stream<Entity>) (prefix)(Property[Comparator]){Operator Property [Comparator]}

次に、この定義の各部分に焦点を当てます。

4.1. 返品タイプ

returnタイプは、主に、クエリが返す可能性のあるオブジェクトの数を定義します。 クエリが複数の結果を返す可能性がある場合に備えて、単一のエンティティタイプを戻り値として定義することはできません。

次のメソッドは、指定された名前の User が複数ある場合に、例外をスローします。

public abstract User findByFirstName(String firstName);

逆は当てはまりません。結果が単一のエンティティであっても、戻り値をCollectionとして定義できます。

public abstract Collection<User> findAnyByFirstName(String firstName);

戻り値をCollectionとして定義する場合、戻りタイプとして1つの値を提案するメソッド名プレフィックス( findAny など)は抑制されます。

上記のクエリは、メソッド名のプレフィックスが何か別のものを示唆している場合でも、名が一致するすべてのUsersを返します。

このような組み合わせ( Collection の戻りタイプと単一の値の戻りを示唆するプレフィックス)は、コードが直感的で理解しにくいため、避ける必要があります。

次のセクションでは、メソッド名プレフィックスの詳細を示します。

4.2. クエリメソッドのプレフィックス

プレフィックスは、リポジトリで実行するアクションを定義します。 最も便利なのは、特定の検索条件に一致するエンティティを見つけることです。

このアクションには、次のような多くのプレフィックスがあります findBy findAny findAll。 詳細なリストについては、公式のApacheDeltaSpikeを確認してください。 ドキュメンテーション

public abstract User findAnyByLastName(String lastName);

ただし、エンティティのカウントと削除に使用される他のメソッドテンプレートもあります。 テーブル内のすべての行をカウントできます。

public abstract int count();

また、 remove メソッドテンプレートが存在し、リポジトリに追加できます。

public abstract void remove(User user);

countByおよびremoveByメソッドプレフィックスのサポートは、ApacheDeltaSpike1.9.0の次のバージョンで追加される予定です。

次のセクションでは、クエリに属性を追加する方法を示します。

4.3. 多くのプロパティを持つクエリ

クエリでは、多くのプロパティを演算子と組み合わせて使用できます。

public abstract Collection<User> findByFirstNameAndLastName(
  String firstName, String lastName);
public abstract Collection<User> findByFirstNameOrLastName(
  String firstName, String lastName);

必要な数のプロパティを組み合わせることができます。 ネストされたプロパティの検索も利用できます。これについては次に説明します。

4.4. ネストされたプロパティを使用したクエリ

クエリはネストされたプロパティを使用することもできます。

次の例では、 UserエンティティにタイプAddressのアドレスプロパティがあり、Addressエンティティにcityプロパティがあります。

@Entity
public class Address {
private String city;
    // ...
}
@Entity
public class User {
    @OneToOne 
    private Address address;
    // ...
}
public abstract Collection<User> findByAddress_city(String city);

4.5. クエリでの順序

DeltaSpikeを使用すると、結果が返される順序を定義できます。 昇順と降順の両方を定義できます。

public abstract List<User> findAllOrderByFirstNameAsc();

上に示したように、すべてのは、並べ替えるプロパティ名と注文方向の短縮名を含むパーツをメソッド名に追加する必要があります。

多くの注文を簡単に組み合わせることができます。

public abstract List<User> findAllOrderByFirstNameAscLastNameDesc();

次に、クエリ結果のサイズを制限する方法を示します。

4.6. クエリ結果のサイズとページネーションを制限する

結果全体から最初の行をいくつか取得したい場合があります。 これはいわゆるクエリ制限です。 データモジュールでも簡単です。

public abstract Collection<User> findTop2OrderByFirstNameAsc();
public abstract Collection<User> findFirst2OrderByFirstNameAsc();

Firsttopは同じように使用できます。

次に、@FirstResultと@MaxResultの2つの追加パラメーターを指定することにより、クエリのページ分割を有効にすることができます。

public abstract Collection<User> findAllOrderByFirstNameAsc(@FirstResult int start, @MaxResults int size);

リポジトリにはすでに多くのメソッドが定義されています。 それらのいくつかは一般的であり、一度定義して各リポジトリで使用する必要があります。

Apache DeltaSpikeは、多くのメソッドをすぐに使用できるようにするために使用できるいくつかの基本的なタイプを提供します。

次のセクションでは、これを行う方法に焦点を当てます。

5. 基本的なリポジトリタイプ

いくつかの基本的なリポジトリメソッドを取得するには、リポジトリはApacheDeltaSpikeによって提供される基本タイプを拡張する必要があります。 EntityRepository FullEntityRepository、などのようなものがあります。

@Repository
public interface UserRepository 
  extends FullEntityRepository<User, Long> {
    // ...
}

または、抽象クラスを使用します。

@Repository
public abstract class UserRepository extends AbstractEntityRepository<User, Long> {
    // ...
}

上記の実装では、追加のコード行を記述せずに多くのメソッドが提供されるため、必要なものが得られました。ボイラープレートコードを大幅に削減します。

基本リポジトリタイプを使用している場合、追加のforEntity属性値を@Repositoryアノテーションに渡す必要はありません。

リポジトリのインターフェースの代わりに抽象クラスを使用している場合、カスタムクエリを作成する追加の可能性があります。

抽象ベースリポジトリクラス。たとえば、AbstractEntityRepositoryは、クエリの作成に使用できるフィールド(ゲッター経由)またはユーティリティメソッドへのアクセスを提供します

public List<User> findByFirstName(String firstName) {
    return typedQuery("select u from User u where u.firstName = ?1")
      .setParameter(1, firstName)
      .getResultList();
}

上記の例では、typedQueryユーティリティメソッドを使用してカスタム実装を作成しました。

クエリを作成する最後の可能性は、次に示す@Queryアノテーションを使用することです。

6. @Queryアノテーション

実行するSQLクエリは、@Queryアノテーションを使用して定義することもできます。 Springソリューションと非常によく似ています。 SQLクエリを値としてメソッドにアノテーションを追加する必要があります。

デフォルトでは、これはJPQLクエリです。

@Query("select u from User u where u.firstName = ?1")
public abstract Collection<User> findUsersWithFirstName(String firstName);

上記の例のように、インデックスを介してパラメータをクエリに簡単に渡すことができます。

JPQLではなくネイティブSQLを介してクエリを渡したい場合は、追加のクエリ属性を定義する必要があります– isNative真の値:

@Query(value = "select * from User where firstName = ?1", isNative = true)
public abstract Collection<User> findUsersWithFirstNameNative(String firstName);

7. 結論

この記事では、Apache DeltaSpikeの基本的な定義について説明し、エキサイティングな部分であるデータモジュールに焦点を当てました。 Spring Dataプロジェクトと非常によく似ています。

リポジトリパターンを実装する方法を検討しました。 また、実行するクエリを定義する3つの可能性を紹介しました。

いつものように、この記事で使用されている完全なコード例は、Githubから入手できます。