AddressbookDO.ktAddressbookDO represents a named collection of addresses — a user- or group-owned address book. It extends BaseUserGroupRightsDO to inherit an ownership and group-permission model, implements DisplayNameCapable for consistent UI labels, and carries Hibernate Search annotations (@Indexed, @FullTextField) so that address books can be located via the application's full-text search engine. Fields are annotated with @PropertyInfo to drive automatic UI form generation.
BaseDO
└─ DefaultBaseDO
└─ BaseUserGroupRightsDO ← provides owner, user-rights, group-rights fields
└─ AddressbookDO ← this class
also implements DisplayNameCapable
BaseUserGroupRightsDO is the critical parent: it adds columns for owner (a PFUserDO reference), along with the rights-assignment fields that let an address book be shared with individual users or entire groups. This parent-class design means every address book automatically participates in ProjectForge's multi-tenant visibility model.
| Annotation | Effect |
|---|---|
@Entity | Marks this as a Hibernate-managed persistent class. |
@Table(name = "T_ADDRESSBOOK") | Maps to the T_ADDRESSBOOK database table. The T_ prefix is a ProjectForge convention for all table names. |
@Indexed | Registers this entity with Hibernate Search (Lucene backend). Enables full-text queries. |
| Field | Type | DB Column | Annotations | Notes |
|---|---|---|---|---|
title |
String? |
(mapped) | @PropertyInfo(i18nKey="addressbook.title", required=true), @FullTextField, @Column(length=LENGTH_TITLE) |
The required display name. Full-text indexed. Length capped at Constants.LENGTH_TITLE (likely 255). |
owner |
PFUserDO? |
owner_fk |
@ManyToOne(fetch=EAGER), @JoinColumn(name="owner_fk"), @IndexedEmbedded(includeDepth=1), @JsonSerialize(using=IdOnlySerializer) |
Eagerly loaded to avoid LazyInitializationException in UI rendering. Embedded one level deep in the Hibernate Search index. Serialized to JSON as only the numeric ID to prevent circular references. |
description |
String? |
(mapped) | @FullTextField, @Column(length=LENGTH_TEXT) |
Optional free-text description. Full-text indexed. Length capped at Constants.LENGTH_TEXT (likely 4000). |
BaseUserGroupRightsDO)These fields are defined in the parent class and inherited automatically; they are not redeclared in AddressbookDO but are present in the database table:
owner — actually overridden here (see above)BaseDO fields: id, created, lastUpdate, deletedThe @Indexed marker, combined with @FullTextField on title and description, makes this entity discoverable through Hibernate Search. The HibernateSearchUsersGroupsTypeBinder (referenced in the source but not shown in the abridged content) bridges the user/group rights into the Lucene index so that search results respect the same visibility constraints as database queries — a user searching for address books will only see results they have permission to access.
DisplayNameCapable & UI IntegrationThe displayName property returns "$title", providing a consistent label for drop-downs, breadcrumbs, and history entries. The @PropertyInfo annotations feed into ProjectForge's automatic form-rendering system, which generates input fields, validation messages (e.g. "Title is required"), and column headers from the i18nKey lookups.
The class defines custom hashCode() and equals() methods. When the entity has been persisted (ID is non-null), equality is based on the database ID — two AddressbookDO instances with the same ID are considered equal. When the ID is null (a transient, not-yet-saved object), equality falls back to object identity (===). This is the standard Hibernate-recommended pattern that avoids problems with proxy objects and collections.
| Commit | Description |
|---|---|
868d6abb7 | Copyright year bump: 2025 → 2026 |
63081666f | Source file headers: 2024 → 2025 |
4c04cfd65 | MAJOR: Migration of integer IDs to Long (changed Integer ID fields to Long throughout) |
b6092df09 | Copyright 2023 → 2024 |
ab45d51fa | Copyright 2001-2022 → 2001-2023 |
b131193e7 | Member variables refactored using by lazy {} (deferred initialisation for collections and heavy dependencies) |
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 |
9ebb88522 | Initial commit — present from the project's origin |
BaseUserGroupRightsDO?Address books are shared resources — a user creates one and may grant read or write access to other users or groups. The BaseUserGroupRightsDO superclass provides a uniform rights model (owner + per-user grants + per-group grants) that is reused across many ProjectForge entity types (address books, calendars, task lists, etc.). This avoids duplicating the same access-control schema in every entity and ensures consistent behaviour in the DAO and UI layers.
owner?Address books are almost always displayed with their owner's name. If owner were lazily loaded, every list page would trigger N+1 additional queries. Eager fetching is a deliberate performance trade-off: it adds a JOIN to every address-book query but eliminates the N+1 problem in the common case. The @JsonSerialize(using = IdOnlySerializer::class) annotation ensures that when the entity is serialised to JSON (e.g. for REST APIs), only the owner's numeric ID is emitted, preventing deep object-graph serialisation and circular references.
ProjectForge provides a global search feature that spans multiple entity types. By annotating AddressbookDO with @Indexed and @FullTextField, the Lucene index is kept in sync with the database via Hibernate Search's automatic indexing on save/update/delete. The HibernateSearchUsersGroupsTypeBinder further ensures that access-control metadata is embedded in the search index, so the same user who cannot see an address book in a list view cannot find it via full-text search either — a critical security property.
DisplayNameCapable?This interface (providing displayName: String) is a ProjectForge convention used by history/audit logging, UI breadcrumbs, and selection drop-downs. By implementing it, AddressbookDO plugs into these subsystems without every consumer needing to know that the display name is simply the title field.
Constants.LENGTH_TITLE instead of hard-coded lengths?ProjectForge uses a shared Constants class to define standard column lengths. This ensures that all entities using "title" or "description" fields have consistent database column sizes, simplifying schema management and avoiding subtle bugs where one entity's title is 255 characters but another's is 1000.