跪拜 Guibai
← All articles
Spring Boot · GraphQL · Java

Bean Searcher: A Declarative Java Library That Kills Hand-Written List-Query Boilerplate

By 遇见代码 ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

List queries consume a disproportionate share of backend development time in admin panels, dashboards, and reporting features. A library that collapses that work into a declarative entity definition plus a single method call directly reduces maintenance surface and lets teams ship filtering changes without redeploying.

Summary

Every backend developer knows the grind: a product manager asks for a paginated, filterable, sortable admin table, and the next hour vanishes into writing dynamic SQL `<if>` blocks or JPA `Predicate` chains. The core problem is that declaration and execution are tangled together — you manually translate every HTTP parameter into a query condition.

Bean Searcher separates them. An entity class annotated with `@SearchBean` declares which tables and fields form the search boundary. A one-line `beanSearcher.search(UserVO.class)` call then lets URL parameters like `?name=张&name-op=sw&sort=age&order=desc` drive the full query, including joins, pagination, and aggregate statistics. Adding a new filter requires zero backend code changes.

The library is not an ORM replacement. It coexists with MyBatis or JPA — those handle writes and transactions, while Bean Searcher handles read-heavy list retrieval. Security defaults (injection prevention, page-size caps, offset limits) are built in, and single-table entities work with no annotations at all.

Takeaways
Dynamic list queries in MyBatis and JPA both require hand-written conditional logic that grows linearly with each new filter.
Bean Searcher treats the entity class as a search-boundary declaration and uses HTTP parameters to drive query generation at runtime.
A complete search endpoint — joins, multi-condition filtering, sorting, pagination, and aggregate statistics — fits in one controller method returning `beanSearcher.search(UserVO.class)`.
Adding a new filter condition requires no backend code changes; the frontend simply sends the new parameter name.
Single-table entities need zero annotations; field names map to database columns automatically via camelCase-to-snake_case conversion.
The library is complementary to MyBatis/JPA, not a replacement — use it for list retrieval while keeping existing ORMs for writes and transactions.
Built-in security defaults prevent SQL injection, excessive page sizes, and deep-offset attacks without extra configuration.
Conclusions

The framing of the problem as a confusion between declaration and execution is precise: developers spend time on mechanical translation that a framework could infer from the entity model and the request parameters.

Bean Searcher's design mirrors GraphQL's philosophy — the client specifies what it wants, and the server resolves it against a declared schema — but applies it to REST-style list retrieval with standard query strings, which lowers the adoption barrier significantly compared to introducing a GraphQL layer.

The claim that the library changes how developers think — from SQL assemblers to domain modelers — points to a genuine ergonomic shift: the entity becomes the single source of truth for what is searchable, rather than scattering that knowledge across XML files and service layers.

Concepts & terms
Bean Searcher
A Java framework that generates database list queries from annotated entity classes and HTTP parameters, handling filtering, joins, sorting, pagination, and aggregate statistics without hand-written SQL or Criteria code.
Search boundary
The set of database fields and tables declared in an entity class that defines what the frontend is allowed to filter, sort, and retrieve — analogous to a GraphQL schema for list queries.
Declarative vs. imperative query construction
Imperative query construction (MyBatis XML, JPA Criteria) requires the developer to write step-by-step conditional logic for each filter. Declarative construction (Bean Searcher) lets the developer state what can be queried, and the framework generates the logic from runtime parameters.
From the discussion

The exchange is light and promotional rather than substantive. A joke about backend hair loss gets a playful reply crediting Bean Searcher for preserving the developer's remaining hair. Another comment offers straightforward praise for the library's power and conciseness. The final comment doubles as a demo pitch, claiming a single line of Java can deliver a full-featured list endpoint.

See top comments, translated →
Source: juejin.cn ↗ Google Translate ↗ Backup ↗