Skip to content

Commit 7415950

Browse files
authored
[filter-list-by-any-field] full-text search (#17815)
* [filter-list-by-any-field] full-text search * [filter-list-by-any-field] reflection * [filter-list-by-any-field] review
1 parent 7df4e58 commit 7415950

File tree

2 files changed

+191
-1
lines changed

2 files changed

+191
-1
lines changed

core-java-modules/core-java-collections-list-7/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@
2323
<properties>
2424
<commons-lang3.version>3.17.0</commons-lang3.version>
2525
</properties>
26-
</project>
26+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
package com.baeldung.filterbyanyfield;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
5+
import java.lang.reflect.Field;
6+
import java.lang.reflect.InaccessibleObjectException;
7+
import java.util.Arrays;
8+
import java.util.List;
9+
10+
import org.junit.jupiter.api.Test;
11+
12+
public class FilterListByAnyMatchingFieldUnitTest {
13+
14+
// @formatter:off
15+
private static final Book JAVA = new Book(
16+
"The Art of Java Programming",
17+
List.of("Tech", "Java"),
18+
"Java is a powerful programming language.",
19+
400);
20+
private static final Book KOTLIN = new Book(
21+
"Let's Dive Into Kotlin Codes",
22+
List.of("Tech", "Java", "Kotlin"),
23+
"It is big fun learning how to write Kotlin codes.",
24+
300);
25+
private static final Book PYTHON = new Book(
26+
"Python Tricks You Should Know",
27+
List.of("Tech", "Python"),
28+
"The path of being a Python expert.",
29+
200);
30+
private static final Book GUITAR = new Book(
31+
"How to Play a Guitar",
32+
List.of("Art", "Music"),
33+
"Let's learn how to play a guitar.",
34+
100);
35+
36+
// @formatter:on
37+
private static final List<Book> BOOKS = List.of(JAVA, KOTLIN, PYTHON, GUITAR);
38+
39+
List<Book> fullTextSearchByLogicalOr(List<Book> books, String keyword) {
40+
return books.stream()
41+
.filter(book -> book.getTitle()
42+
.contains(keyword) || book.getIntro()
43+
.contains(keyword) || book.getTags()
44+
.stream()
45+
.anyMatch(tag -> tag.contains(keyword)))
46+
.toList();
47+
}
48+
49+
@Test
50+
void whenFilteringInAllFields_thenCorrect() {
51+
List<Book> byJava = fullTextSearchByLogicalOr(BOOKS, "Java");
52+
assertThat(byJava).containsExactlyInAnyOrder(JAVA, KOTLIN);
53+
54+
List<Book> byArt = fullTextSearchByLogicalOr(BOOKS, "Art");
55+
assertThat(byArt).containsExactlyInAnyOrder(JAVA, GUITAR);
56+
57+
List<Book> byLets = fullTextSearchByLogicalOr(BOOKS, "Let's");
58+
assertThat(byLets).containsExactlyInAnyOrder(KOTLIN, GUITAR);
59+
}
60+
61+
@Test
62+
void whenCallingBookStrForFiltering_thenCorrect() {
63+
String expected = """
64+
Let's Dive Into Kotlin Codes
65+
It is big fun learning how to write Kotlin codes.
66+
Tech
67+
Java
68+
Kotlin""";
69+
assertThat(KOTLIN.strForFiltering()).isEqualTo(expected);
70+
}
71+
72+
List<Book> fullTextSearchByStrForFiltering(List<Book> books, String keyword) {
73+
return books.stream()
74+
.filter(book -> book.strForFiltering()
75+
.contains(keyword))
76+
.toList();
77+
}
78+
79+
@Test
80+
void whenFilteringInAllFieldsUsingStrForFiltering_thenCorrect() {
81+
List<Book> byJava = fullTextSearchByStrForFiltering(BOOKS, "Java");
82+
assertThat(byJava).containsExactlyInAnyOrder(JAVA, KOTLIN);
83+
84+
List<Book> byArt = fullTextSearchByStrForFiltering(BOOKS, "Art");
85+
assertThat(byArt).containsExactlyInAnyOrder(JAVA, GUITAR);
86+
87+
List<Book> byLets = fullTextSearchByStrForFiltering(BOOKS, "Let's");
88+
assertThat(byLets).containsExactlyInAnyOrder(KOTLIN, GUITAR);
89+
}
90+
91+
boolean fullTextSearchOnObject(Object obj, String keyword, String... excludedFields) {
92+
Field[] fields = obj.getClass()
93+
.getDeclaredFields();
94+
for (Field field : fields) {
95+
if (Arrays.stream(excludedFields)
96+
.noneMatch(exceptName -> exceptName.equals(field.getName()))) {
97+
field.setAccessible(true);
98+
try {
99+
Object value = field.get(obj);
100+
if (value != null) {
101+
if (value.toString()
102+
.contains(keyword)) {
103+
return true;
104+
}
105+
if (!field.getType()
106+
.isPrimitive() && !(value instanceof String) && fullTextSearchOnObject(value, keyword, excludedFields)) {
107+
return true;
108+
}
109+
}
110+
} catch (InaccessibleObjectException | IllegalAccessException ignored) {
111+
//ignore
112+
}
113+
}
114+
}
115+
return false;
116+
}
117+
118+
List<Book> fullTextSearchByReflection(List<Book> books, String keyword, String... excludeFields) {
119+
return books.stream()
120+
.filter(book -> fullTextSearchOnObject(book, keyword, excludeFields))
121+
.toList();
122+
}
123+
124+
@Test
125+
void whenFilteringInAllFieldsUsingReflection_thenCorrect() {
126+
List<Book> byJava = fullTextSearchByReflection(BOOKS, "Java", "pages");
127+
assertThat(byJava).containsExactlyInAnyOrder(JAVA, KOTLIN);
128+
129+
List<Book> byArt = fullTextSearchByReflection(BOOKS, "Art", "pages");
130+
assertThat(byArt).containsExactlyInAnyOrder(JAVA, GUITAR);
131+
132+
List<Book> byLets = fullTextSearchByReflection(BOOKS, "Let's", "pages");
133+
assertThat(byLets).containsExactlyInAnyOrder(KOTLIN, GUITAR);
134+
135+
List<Book> byArtExcludeTag = fullTextSearchByReflection(BOOKS, "Art", "tags", "pages");
136+
assertThat(byArtExcludeTag).containsExactlyInAnyOrder(JAVA);
137+
}
138+
}
139+
140+
class Book {
141+
142+
private String title;
143+
private List<String> tags;
144+
private String intro;
145+
private int pages;
146+
147+
public Book(String title, List<String> tags, String intro, int pages) {
148+
this.title = title;
149+
this.tags = tags;
150+
this.intro = intro;
151+
this.pages = pages;
152+
}
153+
154+
public String getTitle() {
155+
return title;
156+
}
157+
158+
public void setTitle(String title) {
159+
this.title = title;
160+
}
161+
162+
public List<String> getTags() {
163+
return tags;
164+
}
165+
166+
public void setTags(List<String> tags) {
167+
this.tags = tags;
168+
}
169+
170+
public String getIntro() {
171+
return intro;
172+
}
173+
174+
public void setIntro(String intro) {
175+
this.intro = intro;
176+
}
177+
178+
public int getPages() {
179+
return pages;
180+
}
181+
182+
public void setPages(int pages) {
183+
this.pages = pages;
184+
}
185+
186+
public String strForFiltering() {
187+
String tagsStr = String.join("\n", tags);
188+
return String.join("\n", title, intro, tagsStr);
189+
}
190+
}

0 commit comments

Comments
 (0)