Memfilter Koleksi Java melalui Anotasi
Memfilter Koleksi Java melalui Anotasi
[ad_1]
Sejak Java 8, beban kerja pemrograman untuk mengulangi koleksi dan memilih subkoleksi (pemfilteran) berdasarkan batasan yang ditentukan (predikat) telah disederhanakan berkat yang baru API Umpan. Terlepas dari fungsi baru ini, beberapa skenario masih dapat membebani pengembang karena mengharuskan mereka menerapkan sejumlah besar kode yang sangat spesifik untuk memenuhi kondisi filter. Contoh umum dalam sistem bisnis adalah kebutuhan untuk memfilter:
“…koleksi yang setiap objeknya merupakan elemen grafik besar dan atribut yang dipertimbangkan dalam filter adalah milik objek yang berbeda.”
Untuk mengilustrasikan skenario ini, pertimbangkan diagram kelas kecil di bawah ini. Hal ini diperlukan untuk menyaring koleksi Post
objek dengan mempertimbangkan berbagai atribut grafik objek. Pada titik ini, abaikan saja @Filterable
anotasi pada atribut tertentu; ini akan dibahas nanti.
Menampilkan kode Java tradisional untuk pemfilteran Post
koleksi, mari kita membuat beberapa asumsi:
- A
List
telah dipakai dan dimuat. - Tipe primitif
textFilter
Variabel telah ditetapkan sebagai nilai yang akan dicari. - ITU Bahasa Apache Commons
StringUtils
Kelas ini digunakan untuk menghilangkan diakritik dari string.
Cara untuk memfilter a postsCollection
berbicara text
atribut dari Publication
kelasnya adalah:
postsCollection
.stream()
.filter(p -> Objects.isNull(p.getText()) || StringUtils.stripAccents(p.getText().trim().toLowerCase())
.contains(textFilter.trim().toLowerCase()))
.toList();
Jika perlu memfilter koleksi berdasarkan review
atribut dari Comment
kelas, kodenya mungkin terlihat seperti ini:
postsCollection
.stream()
.filter(p -> Objects.isNull(p.getComments()) || p.getComments().isEmpty() ||
p.getComments().stream().anyMatch(c -> StringUtils.stripAccents(c.getReview().trim().toLowerCase())
.contains(textFilter.trim().toLowerCase())))
.toList();
Perhatikan itu untuk setiap perubahan persyaratan pemfilteran, kode harus disesuaikan. Dan yang lebih buruk lagi: kebutuhan untuk menggabungkan beberapa atribut dari kelas grafik yang berbeda dapat menyebabkan kode menjadi sulit untuk dipelihara.
Mengatasi skenario seperti itu, artikel ini menyajikan pendekatan umum untuk memfilter koleksi dengan menggabungkan anotasi dan API Refleksi Java.
Algoritma Filter Introspektor
Pendekatan yang diusulkan disebut Filter Introspektor dan algoritma utamanya didasarkan pada tiga dasar:
- Jelajahi semua hubungan untuk setiap objek menggunakan strategi pencarian yang mengutamakan luas.
- Jelajahi hierarki setiap objek.
- Periksa apakah suatu atribut dianotasi dengan
@Filterable
setiap objek berisi pola yang diberikan.
Perlu dijelaskan hal ini semua operasi traversal didukung oleh Reflection API. Hal lain yang relevan adalah bahwa atribut yang akan diperhitungkan dalam operasi pemfilteran harus diberi anotasi @Filterable
.
Kode di bawah ini menunjukkan implementasi algoritma Introspector Filter. Kode sumber lengkapnya tersedia di GitHub deposito.
public IntrospectorFilter() {
public Boolean filter(Object value, Object filter) {
if (Objects.isNull(filter)) {
return true;
}
String textFilter = StringUtils.stripAccents(filter.toString().trim().toLowerCase());
var nodesList = new ArrayList();
nodesList.add(new Node(0, 0, value));
while (!nodesList.isEmpty()) { // BFS for relationships
var node = nodesList.removeFirst();
if (node.height() > this.heightBound || node.breadth() > this.breadthBound) {
continue;
}
var fieldValue = node.value();
var fieldValueClass = fieldValue.getClass();
int heightHop = node.height();
do { // Hierarchical traversing
if (Objects.nonNull(
this.searchInRelationships(node, fieldValueClass, heightHop, textFilter, nodesList))) {
return true;
}
fieldValueClass = fieldValueClass.getSuperclass();
heightHop++;
} while (isValidParentClass(fieldValueClass) && heightHop <= this.heightBound);
if (isStringOrWrapper(fieldValue) && containsTextFilter(fieldValue.toString(), textFilter)) {
return true;
}
}
return false;
}
}
Tiga metode telah diekstraksi dari kode ini untuk tetap fokus pada algoritma utama:
isValidParentClass
: Periksa apakah kelas induk valid, dengan mempertimbangkan anotasi tambahan yang diberikan untuk mengidentifikasi kelas. Jika tidak ada anotasi tambahan yang diberikan, semua kelas induk dianggap valid.isStringOrWrapper
: Periksa apakah nilai atribut diberi keterangan@Filterable
adalah aString
atau pembungkus tipe primitif. Jika hal ini benar, maka hubungan yang terus-menerus seperti itu akan terputus, karena tidak ada lagi jalan ke depan.containsTextFilter
: Periksa apakah atribut dianotasi dengan@Filterable
berisi template yang disediakan.
Mari kita kembali ke diagram kelas kecil sebelumnya. Kedua kode disajikan untuk menyaring a postsCollection
dapat diganti dengan kode berikut menggunakan algoritma filter Introspector.
postsCollection.stream().filter(p -> filter.filter(p, textFilter)).toList();
Proyek Filter Introspektor
Implementasi algoritma filter Introspector telah dienkapsulasi dalam sebuah perpustakaan (jar). Ini dapat dimasukkan ke dalam proyek Maven hanya dengan menambahkan ketergantungan berikut ke pom.xml
deposito. Implementasi ini memerlukan setidaknya Java versi 21 agar dapat berfungsi. Namun ada versi yang kompatibel dengan Java 8 — ubah ketergantungan versi menjadi 0.1.0.
io.github.tnas
introspectorfilter
1.0.0
Proyek ini juga memiliki modul contoh yang merinci cara menggunakan filter Introspector sebagai filter global dalam komponen data JSF.
Kesimpulan
Memilih subset objek dari koleksi Java adalah tugas umum dalam pengembangan perangkat lunak. Memiliki strategi yang fleksibel (Algoritma Filter Introspektor) atau alat (Perpustakaan Filter Introspektor) untuk membuat filter untuk digunakan dalam pilihan ini dapat membantu pengembang menulis kode yang lebih ringkas dan mudah dipelihara. Ini adalah usulan Proyek Filter Instrospector yang tersedia lengkap di a Repositori GitHub.
[ad_2]