Panduan untuk Modul Data DeltaSpike

1. Ikhtisar

Apache DeltaSpike adalah sebuah proyek yang menyediakan kumpulan ekstensi CDI untuk proyek Java; itu membutuhkan implementasi CDI agar tersedia pada waktu proses.

Tentu saja, ini dapat bekerja dengan implementasi CDI yang berbeda - JBoss Weld atau OpenWebBeans. Ini juga diuji di banyak server aplikasi.

Dalam tutorial ini, kita akan fokus pada salah satu modul Data yang paling terkenal dan berguna .

2. Pengaturan Modul Data DeltaSpike

Modul Apache DeltaSpike Data digunakan untuk menyederhanakan implementasi pola repositori . Ini memungkinkan pengurangan kode boilerplate dengan menyediakan logika terpusat untuk pembuatan dan eksekusi kueri .

Ini sangat mirip dengan proyek Data Musim Semi. Untuk mengkueri database, kita perlu mendefinisikan deklarasi metode (tanpa implementasi) yang mengikuti konvensi penamaan yang ditentukan atau yang berisi anotasi @Query . Implementasinya akan dilakukan untuk kami oleh ekstensi CDI.

Di subbagian berikutnya, kita akan membahas cara mengatur modul Data Apache DeltaSpike di aplikasi kita.

2.1. Dependensi yang Diperlukan

Untuk menggunakan modul Apache DeltaSpike Data dalam aplikasi, kita perlu mengatur dependensi yang diperlukan.

Ketika Maven adalah alat pembuatan kami, kami harus menggunakan:

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

Saat kami menggunakan Gradle:

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

Artefak modul Apache DeltaSpike Data tersedia di Maven Central:

  • deltaspike-data-module-impl
  • deltaspike-data-module-api

Untuk menjalankan aplikasi dengan modul Data, kita juga membutuhkan implementasi JPA dan CDI yang tersedia saat runtime .

Meskipun Apache DeltaSpike dapat dijalankan di aplikasi Java SE, dalam banyak kasus, Apache akan diterapkan di Server Aplikasi (misalnya, Wildfly atau WebSphere).

Server Aplikasi memiliki dukungan penuh Jakarta EE, jadi kami tidak perlu melakukan apa-apa lagi. Dalam kasus aplikasi Java SE, kami harus menyediakan implementasi ini (misalnya, dengan menambahkan dependensi ke Hibernate dan JBoss Weld).

Selanjutnya, kami juga akan membahas konfigurasi yang diperlukan untuk EntityManager .

2.2. Konfigurasi Pengelola Entitas

The Modul data membutuhkan EntityManager untuk disuntikkan lebih CDI .

Kami dapat mencapai ini dengan menggunakan produser CDI:

public class EntityManagerProducer { @PersistenceContext(unitName = "primary") private EntityManager entityManager; @ApplicationScoped @Produces public EntityManager getEntityManager() { return entityManager; } }

Kode di atas mengasumsikan bahwa kita memiliki unit persistensi dengan nama primer yang ditentukan dalam file persistence.xml .

Mari kita lihat di bawah sebagai contoh definisi:

 java:jboss/datasources/baeldung-jee7-seedDS     

Unit persistensi dalam contoh kami menggunakan jenis transaksi JTA yang berarti kami harus menyediakan Strategi Transaksi yang akan kami gunakan.

2.3. Strategi Transaksi

Jika kita menggunakan jenis transaksi JTA untuk sumber data kita, maka kita harus menentukan Strategi Transaksi yang akan digunakan di repositori Apache DeltaSpike . Kita dapat melakukannya di dalam file apache-deltaspike.properties (di bawah direktori META-INF ):

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

Ada empat jenis strategi transaksi yang dapat kami tentukan:

  • BeanManagedUserTransactionStrategy
  • ResourceLocalTransactionStrategy
  • ContainerManagedTransactionStrategy
  • EnvironmentAwareTransactionStrategy

Semuanya mengimplementasikan org.apache.deltaspike.jpa.spi.transaction.TransactionStrategy .

Ini adalah bagian terakhir dari konfigurasi yang diperlukan untuk modul data kami.

Selanjutnya, kami akan menunjukkan cara mengimplementasikan kelas pola repositori.

3. Kelas Repositori

Saat kita menggunakan modul data Apache DeltaSpike, kelas atau antarmuka abstrak apa pun bisa menjadi kelas repositori .

Yang harus kita lakukan adalah menambahkan anotasi @Repositori dengan atribut forEntity yang mendefinisikan entitas JPA yang harus ditangani repositori kita:

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

atau dengan kelas abstrak:

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

Modul data menemukan kelas (atau antarmuka) dengan anotasi semacam itu dan itu akan memproses metode yang ada di dalamnya.

Ada beberapa kemungkinan untuk menentukan kueri yang akan dieksekusi. Kami akan membahas satu per satu segera di bagian berikut.

4. Query Dari Nama Metode

Kemungkinan pertama untuk mendefinisikan kueri adalah dengan menggunakan nama metode yang mengikuti konvensi penamaan yang ditentukan .

Ini terlihat seperti di bawah ini:

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

Selanjutnya, kita akan fokus pada setiap bagian dari definisi ini.

4.1. Jenis Pengembalian

The tipe kembali terutama mendefinisikan seberapa banyak objek query kita akan kembali . Kami tidak dapat mendefinisikan tipe entitas tunggal sebagai nilai pengembalian jika kueri kami mungkin mengembalikan lebih dari satu hasil.

Metode berikut akan memunculkan pengecualian jika ada lebih dari satu Pengguna dengan nama tertentu:

public abstract User findByFirstName(String firstName);

The opposite isn't true – we can define a return value as a Collection even though the result will be just a single entity.

public abstract Collection findAnyByFirstName(String firstName);

The method name prefix which suggests one value as a return type (e.g., findAny) is suppressed in case we define return value as Collection.

The above query will return all Users with a first name matching even the method name prefix suggests something different.

Such combinations (Collection return type and a prefix which suggests one single value return) should be avoided because the code becomes not intuitive and hard to understand.

The next section shows more details about method name prefix.

4.2. Prefix for Query Method

Prefix defines the action we want to execute on the repository. The most useful one is to find entities which match given search criteria.

There are many prefixes for this action like findBy, findAny, findAll. For the detailed list, please check official Apache DeltaSpike documentation:

public abstract User findAnyByLastName(String lastName);

However, there are also other method templates which are used for counting and removing entities. We can count all rows in a table:

public abstract int count();

Also, remove method template exists which we can add in our repository:

public abstract void remove(User user);

Support for countBy and removeBy method prefixes will be added in the next version of Apache DeltaSpike 1.9.0.

The next section shows how we can add more attributes to the queries.

4.3. Query With Many Properties

In the query, we can use many properties combined with and operators.

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

We can combine as many properties as we want. Search for nested properties is also available which we'll show next.

4.4. Query With Nested Properties

The query can also use nested properties.

In the following example User entity has an address property of type Address and Address entity has a city property:

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

4.5. Order in the Query

DeltaSpike allows us to define an order in which result should be returned. We can define both – ascending and descending order:

public abstract List findAllOrderByFirstNameAsc();

As shown above all we have to do is to add a part to the method name which contains property name we want to sort by and the short name for the order direction.

We can combine many orders easily:

public abstract List findAllOrderByFirstNameAscLastNameDesc(); 

Next, we'll show how to limit the query result size.

4.6. Limit Query Result Size and Pagination

There are use cases when we want to retrieve few first rows from the whole result. It's so-called query limit. It's also straightforward with Data module:

public abstract Collection findTop2OrderByFirstNameAsc(); public abstract Collection findFirst2OrderByFirstNameAsc();

First and top can be used interchangeably.

We can then enable query pagination by providing two additional parameters: @FirstResult and @MaxResult:

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

We defined already a lot of methods in the repository. Some of them are generic and should be defined once and use by each repository.

Apache DeltaSpike provides few basic types which we can use to have a lot of methods out of the box.

In the next section, we'll focus on how to do this.

5. Basic Repository Types

To get some basic repository methods, our repository should extend basic type provided by Apache DeltaSpike. There are some of them like EntityRepository, FullEntityRepository, etc.:

@Repository public interface UserRepository extends FullEntityRepository { // ... }

Or using an abstract class:

@Repository public abstract class UserRepository extends AbstractEntityRepository { // ... } 

The above implementation gives us a lot of methods without writing additional lines of code, so we gained what we wanted – we reduce boilerplate code massively.

In case we're using base repository type there's no need to pass an additional forEntity attribute value to our @Repository annotation.

When we're using abstract classes instead of interfaces for our repositories we get an additional possibility to create a custom query.

Abstract base repository classes, e.g., AbstractEntityRepository gives us an access to fields (via getters) or utility methods which we can use to create a query:

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

In the above example, we used a typedQuery utility method to create a custom implementation.

The last possibility to create a query is to use @Query annotation which we will show next.

6. @Query Annotation

The SQL query to execute can also be defined with the @Query annotation. It's very similar to the Spring solution. We have to add an annotation to the method with SQL query as a value.

By default this is a JPQL query:

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

As in the above example, we can easily pass parameters to the query via an index.

In case we want to pass query via native SQL instead of JPQL we need to define additional query attribute – isNative with true value:

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

7. Conclusion

In this article, we covered the basic definition of Apache DeltaSpike, and we focused on the exciting part – Data module. It's very similar to the Spring Data Project.

We explored how to implement the repository pattern. We also introduced three possibilities how to define a query to execute.

Seperti biasa, contoh kode lengkap yang digunakan dalam artikel ini tersedia di Github.