AddressbookDao.ktAddressbookDao is the primary data-access object for AddressbookDO entities. It extends BaseDao to inherit standard CRUD operations (save, update, delete, find, getList, markAsDeleted, undelete) and overrides select() to enforce per-user access-control filtering via AddressbookRight. It is annotated as a Spring @Service singleton and is one of the oldest files in the codebase, present since the initial commit.
AddressbookDao extends BaseDao<AddressbookDO>, which itself is a generic Hibernate DAO providing:
save(obj) / update(obj) — persist or merge an entitydelete(obj) / markAsDeleted(obj) — hard or soft-deleteselect(filter) — filtered list queries (overridden here)find(id) / getList(filter) — single-retrieval and paginated listsundelete(obj) — restore a soft-deleted entityThe DAO participates in ProjectForge's rights-management system in two ways:
| Mechanism | Description |
|---|---|
UserRightId.MISC_ADDRESSBOOK |
Set in the init block. This right is checked by BaseDao before any mutating operation (save, update, delete, etc.) to ensure the caller holds the MISC_ADDRESSBOOK permission. |
AddressbookRight |
Used inside the overridden select() method. Builds an HQL query that joins onto the user/group rights tables and restricts results to address books the current user can read, based on the ownership and group-access rules inherited from BaseUserGroupRightsDO. |
| Dependency | Role |
|---|---|
UserDao | Autowired; used by setOwner() to resolve a PFUserDO by its numeric ID before assigning it as the owner of an address book. |
HistoryFormatUtils | Autowired; provides formatting helpers for audit-log (history) entries, likely used via BaseDao when recording changes. |
setOwner(ab: AddressbookDO, userId: Long)Resolves a PFUserDO via UserDao and assigns it to the address book's owner field. This is a convenience method that centralises the owner-lookup pattern used by UI controllers.
override fun select(filter: BaseSearchFilter): List<AddressbookDO>Overrides the base implementation to cast the generic filter into an AddressbookFilter and incorporate AddressbookRight-based filtering. The generated HQL adds JOIN clauses on the rights tables so that only address books visible to the current user (by ownership, group membership, or explicit access grants) are returned. Users without MISC_ADDRESSBOOK may see an empty list.
override fun newInstance(): AddressbookDOFactory method required by the generic DAO infrastructure; returns a plain new AddressbookDO().
override val additionalSearchFields: Array<String>Returns ADDITIONAL_SEARCH_FIELDS, a constant array listing the entity properties that should be included in full-text / Hibernate Search queries beyond the default fields inherited from BaseDO.
| Commit | Description |
|---|---|
868d6abb7 | Copyright year bump: 2025 → 2026 |
63081666f | Source file headers: 2024 → 2025 |
4c04cfd65 | MAJOR: Migration of integer IDs to Long IDs (changed all Integer-based keys to Long) |
b6092df09 | Copyright 2023 → 2024 |
ab45d51fa | Copyright 2001-2022 → 2001-2023 |
5f7ef41b8 | Copyright 2021 → 2022 |
ceb63e8a1 | Source code header: (C) 2001-2021 |
7c79f1922 | Copyright of source header → 2020 |
dd5ca38ac | CopyRight of all java file-headers updated or created |
2d86a8cd6 | PROJECTFORGE-2306: Refactorings for keeping access check at update time (ensured UserRightId checks are honoured on every write path) |
9ebb88522 | Initial commit — one of the original files from the project's founding import |
ProjectForge follows the standard DAO-per-entity pattern. Each business entity gets its own DAO so that cross-cutting concerns (access control, auditing, full-text indexing) can be customised per entity. The generic BaseDao handles boilerplate CRUD and the per-entity subclass injects entity-specific rules — here the address-book access logic.
select() rather than use Spring Security annotations?ProjectForge predates Spring Security's widespread adoption and uses its own rights-management layer built on HQL JOINs. Overriding select() allows the access checks to be compiled directly into the database query, avoiding the N+1 problem that would arise from loading all rows and then filtering in application code. This approach also lets the filter combine access-control predicates with user-supplied search criteria in a single HQL statement.
AddressbookRight class used instead of inline HQL?The AddressbookRight class encapsulates the user/group permission model defined by BaseUserGroupRightsDO. By delegating to a separate class, the same access logic can be reused in reporting, export, and REST endpoints without duplicating the multi-JOIN pattern. It also makes the access model easier to test in isolation.
@Service instead of @Repository?While Spring's @Repository stereotype is typical for DAOs, ProjectForge uses @Service throughout its DAO layer. This likely reflects a convention established before @Repository's exception-translation feature was widely adopted, or a deliberate choice to treat DAOs as transactional service components. The functional difference is negligible since both are Spring-managed singletons.
This file has been in the codebase since the initial commit (9ebb88522) and has survived every major refactoring — the integer-to-Long migration, multiple copyright updates, and the access-check refactoring of PROJECTFORGE-2306 — attesting to the stability of the DAO abstraction.