Hibernate Advisor checks
The Hibernate panel runs a fixed, on-demand ruleset against the host application's mapped JPA entities. It reads the JPA EntityManagerFactory metamodel, selected persistence properties, and Spring Data repository metadata when available; it does not intercept runtime queries, invoke repositories, execute SQL, or modify mappings.
The checks are heuristic review prompts. They highlight common Hibernate/JPA performance and maintainability risks, but the right remediation still depends on the application's query patterns and data model.
Availability and bounds
The panel is available only when Hibernate ORM and an EntityManagerFactory bean are present. If either is missing, or if the metamodel cannot be read, BootUI returns a stable empty report with an explanatory status.
The scan is bounded to mapped entities reported by the application's own JPA metamodel. This also covers entities added through @EntityScan or custom persistence-unit configuration without scanning the entire classpath.
Severity scale
- CRITICAL - a configuration choice that can immediately damage production data. Currently emitted by HIB-CONFIG-002 for
ddl-auto=createorcreate-dropunder a production-like profile. - HIGH - a mapping choice that commonly causes large performance surprises.
- MEDIUM - a mapping or configuration issue that usually warrants review before production use.
- LOW - reserved for lower-impact hygiene findings.
- INFO - informational prompts where the fix depends heavily on project context.
The Rule results panel lists only checks that found findings, ordered by severity, finding count, and rule id. Each rule includes up to a handful of sample mapped members plus a remediation link.
Fetching
HIB-FETCH-001 - Eager fetching should stay explicit and bounded
- Severity: HIGH
- Inspects:
@ManyToOne,@OneToOne,@OneToMany,@ManyToMany, and@ElementCollectionmappings on metamodel attributes. - Fires when: a mapping resolves to
FetchType.EAGER, including default-eager to-one associations where nofetchattribute is declared and element collections that explicitly opt into eager fetching. - Why it matters: eager mappings are fetched whether or not the use case needs them, which can amplify query counts, payload size, and accidental object graph or collection-table loading.
- Recommendation: prefer
LAZYmappings and fetch required data explicitly with joins, entity graphs, DTO projections, or targeted collection-value queries.
HIB-FETCH-003 - Collection fetch joins should not be paged directly
- Severity: HIGH
- Inspects: Spring Data JPA
@Querymethods with aPageableparameter and resolvable JPQLJOIN FETCHpaths. - Fires when: Hibernate is older than 7.4 (or the runtime version cannot be detected), Spring Data repository metadata is available, and a paged repository query fetch-joins a mapped collection on the repository domain entity.
- Why it matters (Hibernate < 7.4): collection fetch joins duplicate root rows, and versions before 7.4 applied the
Pageablelimit in memory after loading the full, duplicated result set instead of at the SQL level. - Recommendation: page root identifiers first, then fetch the required collection graph in a second query inside the same transaction.
- Hibernate 7.4+: the "Limits and fetch joins" migration-guide entry documents that the limit for a paged query with a collection
JOIN FETCHis now applied in the generated SQL itself; theorg.hibernate.limitInMemoryquery hint restores the pre-7.4 in-memory behavior. The check is skipped (not silently dropped) on 7.4+ runtimes, and the skip reason explains why.
HIB-FETCH-004 - Review entities with multiple bag collections
- Severity: INFO
- Inspects:
@OneToManyand@ManyToManycollection attributes. - Fires when: an entity declares two or more unordered
List/Collectionassociations (bags) without@OrderColumn. - Why it matters: declaring multiple bags is common and safe on its own - the risk is only realized if two of them are ever join-fetched in the same query, which throws
MultipleBagFetchException. HIB-QUERY-007 already flags that specific case (JOIN FETCHof 2+ collections in the same query); this rule is downgraded to an informational reminder to keep it that way rather than standing as a violation on ordinary, safe aggregate-root entities that never fetch both bags together. - Recommendation: no action is required unless you plan to fetch these together: never
JOIN FETCHmore than one of these collections in the same query. Add@OrderColumnwhen list order is persistent, or useSet<>if you do need to fetch two of them eagerly in one query.
HIB-FETCH-002 - Batch fetching should cover lazy secondary-select associations
- Severity: INFO
- Inspects: lazy to-one and collection mappings,
hibernate.default_batch_fetch_size/ Spring'sspring.jpa.properties.hibernate.default_batch_fetch_size, association-level@org.hibernate.annotations.BatchSize, and target-entity@BatchSizefor lazy to-one associations. - Fires when: a lazy association can initialize through secondary selects and no global or applicable local batch fetch size is detected.
- Why it matters: lazy associations without batch fetching can produce N+1 select patterns when the same association is traversed across multiple owner rows.
- Recommendation: set a bounded global batch-fetch size or targeted
@BatchSizefor associations traversed across multiple owners; use explicit fetch plans or paged/filtered queries for a single oversized collection. - Quarkus:
hibernate.default_batch_fetch_sizemaps toquarkus.hibernate-orm.fetch.batch-sizeviaQuarkusHibernatePropertyLookup, so a global batch-fetch size configured with the native Quarkus property name is read back correctly and this rule does not false-positive.
HIB-FETCH-005 - Enhanced @Lob attributes should be loaded lazily
- Severity: MEDIUM
- Inspects: persistent attributes annotated with
@Lobon bytecode-enhanced entities. - Fires when: enhancement is available and a
@Lobattribute does not declare@Basic(fetch = FetchType.LAZY). - Why it matters: large CLOB/BLOB payloads are read for every entity hydration unless lazy loading is requested.
- Recommendation: on enhanced entities, annotate infrequently accessed
@Lobfields with@Basic(fetch = FetchType.LAZY). - Enhancement requirement: Hibernate ORM 7 requires bytecode enhancement to honor lazy basic attributes. This rule deliberately does not recommend
@Basic(fetch = LAZY)when enhancement is unavailable; HIB-FETCH-007 instead reports existing ineffective lazy-basic declarations. Quarkus enhances entities at build time, while Spring applications must configure enhancement explicitly.
HIB-FETCH-006 - Collection associations should not declare @Fetch(JOIN)
- Severity: MEDIUM
- Inspects: collection associations annotated with Hibernate's
@Fetch. - Fires when: a
@OneToManyor@ManyToManydeclares@Fetch(FetchMode.JOIN). - Why it matters: this forces every fetch path through a SQL JOIN, undermines pagination, and risks cartesian products.
- Recommendation: prefer
@Fetch(FetchMode.SELECT)orSUBSELECTfor collections, and requestJOIN FETCHonly in the specific queries that need the graph.
HIB-FETCH-007 - Lazy basic attributes require bytecode enhancement
- Severity: MEDIUM
- Inspects: attributes declaring
@Basic(fetch = FetchType.LAZY)and the owning entity's enhancement state. - Fires when: a lazy basic attribute belongs to an entity that is not bytecode enhanced.
- Why it matters: without enhancement, Hibernate cannot intercept access to a basic field and the requested lazy column loading is ineffective.
- Recommendation: enable Hibernate bytecode enhancement, or remove the misleading
LAZYdeclaration.
Identifiers
HIB-ID-001 - Generated identifiers should avoid GenerationType.IDENTITY
- Severity: MEDIUM
- Inspects: mapped attributes annotated with
@GeneratedValue. - Fires when: the generator strategy is
GenerationType.IDENTITY. - Why it matters: identity columns require the insert to execute immediately so Hibernate can read the generated key, which disables JDBC batch inserts for those entities.
- Recommendation: prefer
SEQUENCEwith an allocation size and Hibernate pooled optimizer when the database supports sequences.
HIB-ID-002 - Generated identifiers should avoid GenerationType.TABLE
- Severity: HIGH
- Inspects: mapped attributes annotated with
@GeneratedValue. - Fires when: the generator strategy is
GenerationType.TABLE. - Why it matters: table generators emulate sequences through row updates, which can serialize identifier allocation under concurrent inserts.
- Recommendation: prefer
SEQUENCEwith pooled allocation, orIDENTITYonly when the database has no sequence support.
HIB-ID-003 - @SequenceGenerator should use pooled allocation
- Severity: MEDIUM
- Inspects: field-level and class-level
@SequenceGeneratordeclarations. - Fires when:
allocationSize=1. - Why it matters: allocation size 1 requires a sequence round-trip for every inserted row.
- Recommendation: use an allocation size greater than 1 and keep it aligned with the database sequence increment.
HIB-ID-004 - @GeneratedValue should declare an explicit strategy
- Severity: MEDIUM
- Inspects: identifier attributes annotated with
@GeneratedValue, excludingUUID-typed identifiers. - Fires when:
strategyis omitted (or set toAUTO). - Why it matters: for numeric identifiers,
AUTOnever resolves to the database's nativeIDENTITY/auto-increment column. Hibernate'sGeneratorBinderalways maps the JPAAUTOstrategy to its ownSequenceStyleGenerator, which uses a real databaseSEQUENCEwhere the dialect supports one (PostgreSQL, Oracle, H2, SQL Server, ...) and falls back to a slower, row-locking table-based emulation otherwise (e.g. MySQL, which has no native sequence object) - verified directly against the current Hibernate ORM source (correspondingGeneratorName(GenerationType)inGeneratorBinder, whosedefaultcase - coveringAUTO- always returnsSequenceStyleGenerator, neverIDENTITY) and the ORM user guide's "Interpreting AUTO" section. Leaving the strategy onAUTOmeans silently accepting whichever of those two Hibernate picks for the current database, instead of a strategy the team has actually reviewed. - Recommendation: pick the strategy that fits the target database (for example
SEQUENCEwithallocationSizeon Postgres/Oracle,IDENTITYonly when truly required) and set it explicitly instead of relying onAUTO's dialect-dependent sequence-or-table fallback. - UUID identifiers: skipped entirely - for a
UUID-typed identifier, Hibernate 6 interpretsAUTOas theUuidGenerator, not a sequence, so this rule's "sequence-or-table fallback" rationale does not apply. HIB-ID-005 owns the UUID case exclusively, so aUUID @Id @GeneratedValuewith no explicit strategy is flagged only once, by HIB-ID-005, with UUID-specific guidance instead of a misleading sequence/table warning. - Quarkus/Panache: skipped for the
idfield inherited as-is from Panache's ownPanacheEntity(ORM or Reactive), which declares@Id @GeneratedValue public Long id;with no explicit strategy and cannot be annotated by the application. A custom identifier the application declares itself (including on aPanacheEntityBasesubclass) is still checked normally.
HIB-ID-005 - UUID identifiers should use @UuidGenerator
- Severity: LOW
- Inspects:
UUIDidentifier attributes annotated with@GeneratedValue, and the runtime Hibernate ORM version. - Fires when: the attribute is not also annotated with
@UuidGenerator. - Why it matters: the JPA default generates random UUIDs (v4), which fragment B-tree indexes.
- Recommendation (Hibernate 7.0+): annotate the identifier with
@UuidGenerator(style = VERSION_7)(VERSION_6is also acceptable). Both styles are monotonic, index-friendly UUID variants and only exist starting in Hibernate 7.0 (both@Incubating) - confirmed by diffingUuidGenerator.javabetween the 6.6 branch (onlyAUTO/RANDOM/TIME) and the 7.0 branch (addsVERSION_6/VERSION_7). - Recommendation (before Hibernate 7.0):
style = TIMEis the only style available. It produces an RFC 4122 version 1 UUID (per@UuidGenerator's own Javadoc: "time-based generation strategy consistent with RFC 4122 version 1, but with IP address instead of MAC address"), which places the fast-changingtime_lowfield first and is not materially more index-friendly than a random (v4) UUID - it does not yield the monotonic ordering that makesVERSION_6/VERSION_7genuinely index-friendly. The recommendation is annotated with this caveat rather than presentingTIMEas a real fix. - Version detection: the runtime Hibernate ORM version is read from
HibernateContext/HibernateEntityModelthe same way HIB-FETCH-003/HIB-CONFIG-016 gate their Hibernate-7.4 pagination behavior.
HIB-ID-006 - GenerationType.IDENTITY disables JDBC batch inserts
- Severity: HIGH
- Inspects:
spring.jpa.properties.hibernate.jdbc.batch_size,hibernate.jdbc.batch_size, and identifier attributes annotated with@GeneratedValue. - Fires when: a positive JDBC batch size is configured and an identifier uses
GenerationType.IDENTITY. - Why it matters: Hibernate must execute each identity insert immediately so it can read back the generated key, preventing JDBC insert batching for those entities despite the configured batch size.
- Recommendation: switch IDENTITY identifiers to
SEQUENCEwith a pooledallocationSizeso Hibernate can batch inserts, or drop the JDBC batch-size expectation for these entities.
HIB-ID-007 - Composite identifier classes must satisfy the JPA contract
- Severity: HIGH
- Inspects:
@EmbeddedIdattribute types and@IdClassvalues (including inherited from a superclass). - Fires when: the composite identifier class is not
Serializable, has no public no-arg constructor, or does not override bothequalsandhashCode. - Why it matters: JPA and Hibernate require all four for a composite identifier class to work correctly - this is a pure, deterministic contract check with essentially zero false-positive risk. Violating any of these can silently break entity equality, second-level caching, and collection lookups.
- Recommendation: make the composite identifier class implement
Serializable, declare a public no-arg constructor, and override bothequalsandhashCodeover every identifier field. - Quarkus/Panache: applies identically - this check inspects only the identifier class via reflection, with no framework-specific behavior.
Mapping
HIB-MAP-001 - One-to-many associations should be bidirectional or join-column based
- Severity: MEDIUM
- Inspects:
@OneToManymappings. - Fires when: a one-to-many association has neither
mappedBynor@JoinColumn/@JoinColumns. - Why it matters: Hibernate models that shape through a join table by default, which often produces extra DML and a less obvious schema.
- Recommendation: prefer a bidirectional association with
@ManyToOneon the child and@OneToMany(mappedBy=...)on the parent so the child's foreign key owns the relationship. If a unidirectional mapping is intentional, add@JoinColumnto drop the join table and review the extra update statements flagged by HIB-MAP-020.
HIB-MAP-002 - Many-to-many associations should use Set semantics
- Severity: MEDIUM
- Inspects:
@ManyToManymappings and their Java collection type. - Fires when: a many-to-many association is declared as
List. - Why it matters: list-backed many-to-many mappings can force delete-and-reinsert behavior for join-table rows.
- Recommendation: use
Set, or model the join table as an entity when it has attributes or business meaning.
HIB-MAP-003 - Enum attributes should declare an explicit storage strategy
- Severity: MEDIUM
- Inspects: enum-valued mapped attributes.
- Fires when: an enum attribute omits
@Enumeratedand therefore relies on JPA's default ordinal storage. - Why it matters: default ordinal persistence is easy to enable accidentally, and reordering enum constants changes the stored meaning unless the ordinal values are treated as a stable schema contract.
- Recommendation: use
@Enumerated(EnumType.STRING), a database-native enum type, or an explicit converter with stable database codes.
HIB-MAP-004 - Many-to-many associations should not cascade remove
- Severity: HIGH
- Inspects:
@ManyToManycascade settings. - Fires when: the cascade list contains
REMOVEorALL. - Why it matters: many-to-many targets usually have independent lifecycles, so delete cascades can remove shared rows instead of only join-table links.
- Recommendation: remove
REMOVE/ALL; usePERSIST/MERGEonly when needed, or model the join table as an entity.
HIB-MAP-005 - Many-to-one associations should not cascade remove
- Severity: HIGH
- Inspects:
@ManyToOnecascade settings. - Fires when: the cascade list contains
REMOVEorALL. - Why it matters: child-to-parent delete cascade can remove a parent shared by other children.
- Recommendation: cascade lifecycle operations from aggregate roots to owned children, not from children to parents.
HIB-MAP-006 - One-to-one associations should prefer shared primary keys
- Severity: MEDIUM (LOW when no lifecycle-dependency signal is detected)
- Inspects: owning-side
@OneToOnemappings. - Fires when: the association has no
mappedBy, no@MapsId, and the association itself is not the identifier. The finding is MEDIUM when the mapping looks lifecycle-dependent (optional=falseor cascadeREMOVE/ALL) and LOW otherwise. - Why it matters: dependent one-to-one rows often share the parent lifecycle and can avoid an extra foreign-key/index pair by sharing the primary key.
- Recommendation: use
@MapsIdwhen the child row is lifecycle-dependent on the parent; keep a separate foreign key only when the model requires independent identity.
HIB-MAP-007 - Entity inheritance should avoid TABLE_PER_CLASS
- Severity: MEDIUM
- Inspects: class-level
@Inheritance. - Fires when: the strategy is
InheritanceType.TABLE_PER_CLASS. - Why it matters: polymorphic queries over the base type require a
UNIONacross concrete subtype tables. - Recommendation: prefer
SINGLE_TABLEorJOINEDunless each subtype is always queried independently.
HIB-MAP-008 - @NotFound(IGNORE) should be reviewed
- Severity: MEDIUM
- Inspects: Hibernate
@NotFoundannotations. - Fires when:
action=IGNORE. - Why it matters: missing target rows are silently treated as null and the association must be resolved eagerly to know whether the target exists.
- Recommendation: repair referential integrity or model optional data explicitly instead of suppressing missing targets.
HIB-MAP-009 - Persistent attributes should not be Optional
- Severity: MEDIUM
- Inspects: mapped attributes whose raw Java type is
java.util.Optional. - Fires when: an
Optionalfield or property is part of the mapped model. - Why it matters:
Optionalis a return-type convenience, not a stable persistent attribute type. - Recommendation: map the underlying nullable type and expose
Optionalfrom a non-persistent getter if desired.
HIB-MAP-010 - @ElementCollection List should persist order with @OrderColumn
- Severity: MEDIUM
- Inspects:
@ElementCollectionattributes typed asList. - Fires when: the list does not declare
@OrderColumn- regardless of whether it declares@OrderBy. - Why it matters: without
@OrderColumn, Hibernate cannot compute a minimal diff on mutation and instead deletes and reinserts the entire collection table.@OrderByis not an equivalent fix: it only adds a query-time SQLORDER BYand is never persisted, so it does nothing to change this mutation behavior. The sibling rule HIB-MAP-004'sisBagAttribute()helper already treats only@OrderColumnas removing bag semantics and deliberately ignores@OrderBy, so this rule now matches that same standard instead of presenting@OrderByas an alternative. - Recommendation: add
@OrderColumnto persist the list's index so Hibernate can update rows in place.@OrderBydoes not solve the mutation cost - keep it only if you also want read-time ordering, alongside@OrderColumn, not instead of it. Otherwise preferSet<>if insertion order does not matter.
HIB-MAP-011 - Entity classes should not be final
- Severity: HIGH
- Inspects:
@Entityclasses for thefinalmodifier. - Fires when: an entity is declared
final. - Why it matters: Hibernate cannot create runtime proxies for lazy associations or bytecode-enhanced state when the class is final.
- Recommendation: remove the
finalmodifier from entities (and avoid Kotlin classes withoutopen).
HIB-MAP-012 - SINGLE_TABLE inheritance should declare @DiscriminatorColumn
- Severity: INFO
- Inspects:
@Inheritance(strategy = SINGLE_TABLE)roots. - Fires when: the root entity does not declare
@DiscriminatorColumn. - Why it matters: the default discriminator name, type, and length are implicit, which makes generated schemas and cross-team reviews harder to reason about.
- Recommendation: declare
@DiscriminatorColumnexplicitly so the chosen contract is visible.
HIB-MAP-013 - String columns should declare explicit length
- Severity: INFO
- Inspects: persistent
Stringattributes (excluding identifiers and@Lobfields). - Fires when: there is no
@Column(length=...)and nocolumnDefinition. - Why it matters: generated DDL defaults to 255 characters, which can clash with domain expectations or database constraints.
- Recommendation: set
@Column(length=...)to match the domain, or use@Lob/columnDefinitionfor free-text payloads.
HIB-MAP-014 - BigDecimal columns should declare precision and scale
- Severity: MEDIUM
- Inspects: persistent
BigDecimalattributes. - Fires when:
@Column(precision=..., scale=...)is missing or precision is zero. - Why it matters: provider defaults vary by database, which can silently round monetary or scientific values.
- Recommendation: always set precision and scale on
BigDecimalmappings so DDL and Bean Validation agree.
HIB-MAP-015 - Date/time attributes should use java.time
- Severity: LOW
- Inspects: persistent attributes typed as
java.util.Date,java.util.Calendar, orjava.sqltemporal types. - Fires when: any of those legacy types is detected on a mapped attribute.
- Why it matters: legacy temporal types are mutable, not time-zone aware, and require
@Temporalplumbing. - Recommendation: migrate to
java.time(Instant,LocalDate,LocalDateTime,OffsetDateTime,ZonedDateTime) so JDBC binding is immutable and explicit about zones.
HIB-MAP-016 - @ManyToOne should set optional=false when the join column is non-nullable
- Severity: LOW
- Inspects:
@ManyToOneassociations and their@JoinColumn. - Fires when:
@JoinColumn(nullable=false)is set butoptional=falseis not. - Why it matters: when the foreign key is mandatory, Hibernate can skip the secondary SELECT it would otherwise issue to discriminate between null and a real proxy.
- Recommendation: set
@ManyToOne(optional=false)whenever the join column is non-nullable.
HIB-MAP-017 - Lazy owning @OneToOne requires bytecode enhancement
- Severity: INFO
- Inspects: optional owning
@OneToOneassociations. - Fires when: the association is
FetchType.LAZY,optionalis notfalse, no@MapsIdis declared, and Hibernate bytecode enhancement is not enabled. - Why it matters: Hibernate cannot proxy the missing-or-present discriminator on the owning side without the enhancer, so it silently fetches the association eagerly.
- Recommendation: enable
hibernate.bytecode.enhancer.enableLazyInitialization(and configure the enhancement plugin), or switch to@MapsIdso the existing foreign key drives loading. - Quarkus: bytecode enhancement is always considered enabled. Quarkus enhances every Hibernate ORM entity's bytecode unconditionally at build time (there is no
quarkus.hibernate-orm.enhancement.*opt-out), so this check never fires there.
HIB-MAP-018 - Non-owning @OneToOne triggers N+1 queries
- Severity: HIGH
- Inspects: non-owning (
mappedBy)@OneToOneassociations and whether Hibernate bytecode enhancement is enabled. - Fires when: bytecode enhancement is disabled and an entity declares a non-owning
@OneToOneassociation. - Why it matters: without bytecode enhancement Hibernate cannot create a lazy proxy for a non-owning
@OneToOne, so it loads the association eagerly with an extra query per parent row — the classic N+1 pattern. - Recommendation: enable bytecode enhancement, or replace the bidirectional
@OneToOnewith a shared primary key (@MapsId) and a unidirectional mapping. - Quarkus: bytecode enhancement is always considered enabled (see HIB-MAP-017), so this check never fires there.
HIB-MAP-019 - Missing foreign key indexes
- Severity: INFO
- Inspects:
@ManyToOneand owning@OneToOnejoin columns against the leading columns of@Indexdeclarations in the entity's@Tablemapping. - Fires when: Hibernate/Jakarta schema management is set to a schema-creating mode (
create,create-only,create-drop,drop-and-create, orupdate), an association declares an explicit join-column name, and that column is not the leading column of any JPA-declared@Index. - Why it matters: databases do not always index foreign keys automatically. An unindexed foreign key forces full table scans when joining the association or when deleting parent rows for constraint and cascade checks, which can lead to lock contention and deadlocks.
- Recommendation: declare an
@Indexin@Tablewith the foreign-key column as the leading column. If you manage the schema with Flyway/Liquibase, ensure the index exists in your migrations. - Noise controls: inferred join-column names are skipped because a physical naming strategy can rewrite them, and migration-managed schemas are skipped because JPA annotations cannot prove whether the migration created an index.
HIB-MAP-020 - Unidirectional @OneToMany with @JoinColumn issues extra UPDATE statements
- Severity: MEDIUM
- Inspects: unidirectional
@OneToManyassociations and their join-column annotations. - Fires when: a
@OneToManyhas nomappedBy, declares a join column, and that join column is not read-only (insertable=false, updatable=false). - Why it matters: Hibernate inserts the child rows first and then issues separate
UPDATEstatements to set the foreign key. - Recommendation: make the association bidirectional with
@ManyToOneon the child and@OneToMany(mappedBy=...)on the parent so the child's foreign key is written in theINSERT. A read-only@JoinColumn(insertable=false, updatable=false)is exempt.
HIB-MAP-021 - Legacy @Where restrictions should be migrated
- Severity: MEDIUM
- Inspects: entity and persistent-attribute annotations by name, without linking the optional Hibernate 6 type.
- Fires when:
org.hibernate.annotations.WhereorWhereJoinTableis present. - Why it matters: Hibernate deprecated these annotations in ORM 6.3 and removed them in ORM 7, so mappings must be migrated before or during an ORM 7 upgrade.
- Recommendation: use
@SQLRestriction/@SQLJoinTableRestriction, or Hibernate's@SoftDeletefor supported soft-delete mappings.
HIB-MAP-022 - Explicit ordinal enum mappings should be reviewed
- Severity: INFO
- Inspects: enum attributes declaring
@Enumerated(EnumType.ORDINAL). - Fires when: ordinal storage is explicit, so the mapping is intentional but still carries a schema-evolution risk.
- Why it matters: inserting or reordering enum constants changes the meaning of existing numeric values.
- Recommendation: prefer
STRING, a database-native enum, or a stable-code converter. KeepORDINALonly when append-only ordering is an explicit schema contract.
Entity design
HIB-ENTITY-001 - Entities should override equals and hashCode consistently
- Severity: INFO
- Inspects: entity classes for detectable
equals(Object)andhashCode()overrides. - Fires when: an entity overrides one method but not the other.
- Why it matters: inconsistent equality contracts break sets, maps, and Hibernate collection semantics.
- Recommendation: implement
equalsandhashCodeas a pair, and review generated identifier semantics before using entities in hash-based collections.
HIB-ENTITY-002 - Versionless optimistic locking should use dynamic updates
- Severity: MEDIUM
- Inspects: Hibernate
@OptimisticLocking. - Fires when:
type=DIRTYortype=ALLis used without@DynamicUpdate. - Why it matters: versionless optimistic locking relies on update predicates that match the chosen locking strategy.
- Recommendation: add
@DynamicUpdatewhen using versionless optimistic locking, or use a regular@Versioncolumn for simpler optimistic locking.
HIB-ENTITY-003 - equals/hashCode should not include lazy associations
- Severity: INFO
- Inspects: entities that override both
equalsandhashCodeand declare JPA associations. - Fires when: such an entity is detected. Generated implementations (Lombok
@Data/@EqualsAndHashCodewithout exclusions, IDE templates) typically include those associations. - Why it matters: comparing entities that participate in collections then triggers lazy loading or proxy/initialized mismatches.
- Recommendation: base
equalsandhashCodeon a stable business key or natural id only; exclude lazy associations explicitly when generated tooling is used.
HIB-ENTITY-004 - toString should not include lazy associations
- Severity: INFO
- Inspects: entities that override
toStringand declare JPA associations. - Fires when: such an entity is detected. Generated implementations (Lombok
@Data/@ToStringwithout exclusions, IDE templates) typically traverse associations. - Why it matters: logging or debugging the entity then pulls the object graph, triggering N+1 lazy loads or
LazyInitializationExceptionoutside an open session. - Recommendation: base
toStringon the identifier and a few stable scalar fields; exclude associations explicitly (for example with@ToString(exclude = ...)).
HIB-ENTITY-005 - Persistent fields should not be public
- Severity: LOW
- Inspects: entity attributes backed by a
java.lang.reflect.Fieldthat ispublic. - Fires when: a field-access persistent field is
public. A field annotated@Transientis never flagged - it is not written to the database, so it carries none of the accessor-bypass risk this check targets (for example a public@Transientflag field used by a hand-writtenisNew()/Persistableimplementation). Property-access (getter-mapped) attributes are never flagged either, even when the underlying getter method ispublic- the metamodel resolves those attributes from aMethod, not aField, and public getters are the normal, fully JPA/Hibernate-instrumented way to expose a property-access attribute. - Why it matters: public fields let callers bypass Hibernate's instrumentation for lazy loading and dirty tracking.
- Recommendation: keep persistent fields private (or package-private) and expose mutators when needed; this preserves proxy substitution and bytecode-enhancer guarantees.
- Quarkus/Panache: skipped app-wide when a Panache extension (
quarkus-hibernate-orm-panacheorquarkus-hibernate-reactive-panache) is on the runtime classpath. Panache's active-record entities are meant to be used with public fields; once a Panache extension is present, its build-time bytecode transformation rewrites every public field access on any Hibernate-managed class (not justPanacheEntityBasesubclasses) into the matching getter/setter call, so the accessor-bypass concern this check targets does not apply.
HIB-ENTITY-006 - Avoid primitive @Id or @Version types
- Severity: HIGH
- Inspects: the Java type of attributes annotated with
@Id,@EmbeddedId, or@Version. - Fires when: an identifier or version attribute uses a primitive type.
- Why it matters: primitives have default values (for example
0forlong), so Hibernate/JPA can no longer treatnullas the signal for "not yet persisted." Frameworks and code paths that rely on that signal - Spring Data's defaultisNew()strategy, Hibernate's own transient/detached detection for cascading and merging - can then misidentify a genuinely new entity as already existing, triggering an unnecessary pre-INSERTSELECTor a wrong merge decision. - Recommendation: use wrapper classes (
Long,Integer) so the default value isnull, enabling both Hibernate and Spring Data to cleanly detect new entities and skip the pre-insertSELECT. - Quarkus/Panache: applies identically. This check inspects only the mapped Java type, so it fires the same way on a Panache active-record entity's
id/versionfields as on a plain getter/setter entity.
HIB-ENTITY-007 - Assigned IDs should implement Persistable
- Severity: MEDIUM
- Inspects: entities with assigned identifiers (lacking
@GeneratedValue) and no@Versionattribute. - Fires when: the entity does not implement
org.springframework.data.domain.Persistable. - Why it matters: when using assigned identifiers such as a natural key or application-created UUID, Spring Data cannot determine whether the entity is new or detached because the ID is already populated. It assumes the entity might exist and issues a
SELECTbeforeINSERT. - Recommendation: implement
Persistable<ID>and manage theisNew()flag manually, for example via a@Transientflag set after loading or defaulting to true, so Spring Data avoids the unnecessarySELECTbefore every insert. - Quarkus: skipped entirely (whole-rule) when
spring-data-commonsis not on the classpath. The concern is specific to Spring Data's repositorysave()merge-vs-persist decision; Panache's ownpersist()/persistAndFlush()always issues anINSERTand never probes existence first, so there is nothing to recommend on a Quarkus/Panache app.
HIB-ENTITY-008 - Mutable entities should declare @Version for optimistic locking
- Severity: INFO
- Inspects: mapped entities that carry non-identifier persistent state (at least one attribute that is not an
@Id,@EmbeddedId,@Version, association, or@Transient). - Fires when: the entity declares no
@Versionattribute and has not opted into versionless optimistic locking (@OptimisticLocking(DIRTY|ALL)) or@org.hibernate.annotations.Immutable. - Why it matters: without a version column, two concurrent transactions that read and then update the same row will silently overwrite each other's changes (a lost update) because nothing detects the stale snapshot.
- Recommendation: add a
@Versionattribute (for example aLongorInstant) so concurrent updates fail fast with an optimistic-lock exception; skip this only for append-only, read-only, or reference data where lost updates cannot occur.
HIB-ENTITY-009 - Unique business-key columns should consider @NaturalId
- Severity: INFO
- Inspects:
@Column(unique = true)attributes and entity-level@Table(uniqueConstraints = @UniqueConstraint(...))declarations. - Fires when: a unique column exists and no attribute on the entity is annotated
org.hibernate.annotations.NaturalId. - Why it matters: a unique business key (email, ISBN, order number) is frequently queried by value.
@NaturalIdlets Hibernate resolve the entity from the natural-id cache/lookup without needing a full JPQL query - a well-documented performance pattern. This is advisory, not a defect: a unique column is not always a natural lookup key, so the finding is INFO severity. - Recommendation: consider annotating the business-key attribute(s) with
@NaturalIdso lookups by that value can use Hibernate's natural-id resolution instead of a full query. - Quarkus/Panache: applies identically - this check inspects only annotation metadata via reflection.
Query
All HIB-QUERY rules currently inspect Spring Data repository metadata. Quarkus/Panache does not expose equivalent runtime repository/query metadata with enough fidelity to evaluate these rules reliably, so they remain unavailable on Quarkus rather than guessing from Panache method names or generated bytecode. Mapping, identifier, fetching, configuration, and caching rules still run on Quarkus against the live JPA metamodel.
HIB-QUERY-001 - @Modifying queries should clear or flush the persistence context
- Severity: HIGH
- Inspects: Spring Data JPA
@Modifyingannotations on repository methods. - Fires when: a
@Modifyingmethod does not setclearAutomaticallyorflushAutomatically. - Why it matters: the persistence context can hold stale entities after a bulk update or delete, leading to hard-to-diagnose data inconsistencies.
- Recommendation: set
@Modifying(clearAutomatically=true)(andflushAutomatically=truewhen pending changes must be applied first), or evict affected entities explicitly before issuing the bulk statement.
HIB-QUERY-002 - Streaming repository methods need a transactional, read-only scope
- Severity: MEDIUM
- Inspects: Spring Data repository methods returning
java.util.stream.Stream. - Fires when: a repository method returns
Stream<>. - Why it matters: streaming methods keep the underlying JDBC cursor open and only behave correctly inside an open transaction with the caller closing the stream.
- Recommendation: annotate the caller with
@Transactional(readOnly = true), consume the stream inside a try-with-resources block, and close it before the transaction ends; otherwise preferPage<>or a boundedList<>.
HIB-QUERY-003 - Native paged @Query must declare countQuery
- Severity: HIGH
- Inspects: Spring Data
@Query(nativeQuery=true)methods withPageableor returningPage<>. - Fires when:
countQueryis missing. - Why it matters: Spring Data cannot derive a correct COUNT statement from a native query, so paging either fails to start or executes the wrong COUNT.
- Recommendation: add
countQuery = "..."to the@Queryso paging can compute totals reliably.
HIB-QUERY-004 - Derived deleteBy methods load entities before deletion
- Severity: MEDIUM
- Inspects: Spring Data derived query methods named
deleteBy...orremoveBy.... - Fires when: a derived delete method has no explicit
@Query. - Why it matters: Spring Data implements derived deletes by selecting matching entities first and deleting them one by one, which is expensive on large result sets.
- Recommendation: for bulk removals prefer an explicit
@Modifying @Query("delete from ... where ...")withclearAutomatically=true; reserve deriveddeleteBymethods for small or cascading deletes.
HIB-QUERY-005 - Eager to-one associations should be JOIN FETCHed in entity-returning queries
- Severity: INFO
- Inspects: Spring Data JPQL
@Querymethods that return multiple whole entities (List/Set/Collection,Stream,Page,Slice, or arrays) on a repository whose domain entity declares an eager@ManyToOne/@OneToOneassociation (explicitFetchType.EAGERor the to-one default) without@Fetch(JOIN)/@Fetch(SUBSELECT). - Fires when: such a query selects the whole root entity (for example
select o from Entity o) but does notJOIN FETCHthe eager to-one association. - Why it matters: JPQL does not automatically add joins for eager to-one mappings, so Hibernate issues an extra secondary
SELECTfor the association on every returned row, producing an N+1 query pattern. - Recommendation:
JOIN FETCHthe eager association in the query, or map itFetchType.LAZY(see HIB-FETCH-001) and fetch it explicitly only where the use case needs it. Complements HIB-FETCH-001 by pinpointing the specific finders affected.
HIB-QUERY-006 - Paged or streamed reads should prefer DTO projections over whole entities
- Severity: INFO
- Inspects: Spring Data JPQL
@Querymethods that are paged or streamed (aPageableparameter, or aPage,Slice, orStreamreturn type). - Fires when: the query selects the whole root entity (for example
select o from Entity o) rather than a constructor expression (select new ...(...)) or an interface/DTO projection. - Why it matters: hydrating whole managed entities for read-mostly, paged, or streamed endpoints loads every mapped column and tracks each row in the persistence context, which is wasteful when the caller only needs a few fields.
- Recommendation: return a DTO/interface projection so Hibernate selects only the columns the caller needs; reserve whole-entity reads for cases that mutate the loaded entities.
HIB-QUERY-007 - Queries should not JOIN FETCH more than one collection
- Severity: HIGH (MEDIUM for multi-collection fetches without multiple bags)
- Inspects: Spring Data repository
@Querymethods, resolvable JPQLJOIN FETCHpaths, and collection/bag metadata on the repository domain entity. - Fires when: a non-native JPQL query
JOIN FETCHes two or more collection associations from the same root entity. Two or more bag collections are reported as HIGH; other multi-collection fetch joins are reported as MEDIUM. - Why it matters: fetching multiple bags throws
MultipleBagFetchException, and fetching multiple collections multiplies the result set into a cartesian product. - Recommendation: fetch at most one collection per query. Initialize the remaining collections with separate queries,
@EntityGraphattribute nodes, or@BatchSize/default_batch_fetch_size, and useSetcollections to avoidMultipleBagFetchException.
Configuration
HIB-CONFIG-001 - Open Session in View should be disabled
- Severity: INFO when inferred from Spring Boot's absent-property default; MEDIUM for explicit
true; HIGH for explicittrueunder a production-like profile - Inspects: adapter-provided servlet applicability,
spring.jpa.open-in-view, and active Spring profiles. - Fires when: the application is a Spring servlet web application and the property is
trueor absent, matching Spring Boot's servlet default. - Why it matters: lazy loading after the service transaction has completed can hide missing fetch plans and move data access into the web layer.
- Recommendation: set
spring.jpa.open-in-view=falseand fetch data inside transactional service boundaries. - Applicability: the Spring adapter supplies the servlet-context signal to the framework-neutral engine. Reactive, non-web, and Quarkus applications skip this rule; Quarkus has no Open Session in View mechanism.
HIB-CONFIG-003 - Lazy loading outside transactions should stay disabled
- Severity: HIGH
- Inspects:
hibernate.enable_lazy_load_no_transand Spring'sspring.jpa.properties.*variant. - Fires when: the property is
true. - Why it matters: it hides missing fetch plans by opening temporary sessions outside the intended transaction boundary.
- Recommendation: remove the setting and fetch required data inside transactions with explicit fetch plans or DTO queries.
HIB-CONFIG-004 - JDBC batching should be configured for writes
- Severity: INFO
- Inspects:
hibernate.jdbc.batch_sizeand Spring'sspring.jpa.properties.*variant. - Fires when: the property is absent or non-positive.
- Why it matters: write-heavy code otherwise sends insert/update/delete statements one at a time.
- Recommendation: set a bounded batch size, such as 25, and tune it with representative workloads.
HIB-CONFIG-005 - JDBC batching should order inserts and updates
- Severity: INFO
- Inspects:
hibernate.order_insertsandhibernate.order_updateswhen JDBC batching is enabled. - Fires when: a positive batch size is configured but either ordering property is not
true. - Why it matters: batches are grouped by SQL/table shape; interleaved entity types reduce batch efficiency.
- Recommendation: enable both ordering properties when batching writes across multiple entity types.
- Quarkus:
hibernate.order_inserts/hibernate.order_updateshave no first-classquarkus.hibernate-orm.*equivalent, butQuarkusHibernatePropertyLookupfalls back to Quarkus' genericquarkus.hibernate-orm.unsupported-properties."hibernate.order_inserts"(and"hibernate.order_updates") escape hatch. A live-boot spike againstbootui-quarkus-integration-testsconfirmed this end to end: withquarkus.hibernate-orm.jdbc.statement-batch-sizeand bothunsupported-propertiesentries set, Hibernate's ownSessionFactoryOptions.isOrderInsertsEnabled()/isOrderUpdatesEnabled()both reporttrueat runtime, and this rule correctly does not fire.
HIB-CONFIG-006 - Slow query logging should be available in development
- Severity: INFO
- Inspects: Hibernate slow-query threshold properties.
- Fires when: no positive threshold is configured.
- Why it matters: a local slow-query threshold helps spot expensive SQL before it reaches shared environments.
- Recommendation: configure a bounded threshold in development and staging profiles.
HIB-CONFIG-007 - Hibernate statistics should be enabled when tuning
- Severity: INFO
- Inspects:
hibernate.generate_statisticsand Spring'sspring.jpa.properties.*variant. - Fires when: the property is not
true. - Why it matters: statistics expose query counts, fetch counts, and cache hit ratios useful during performance tuning.
- Recommendation: enable statistics in development or performance-test profiles when investigating data-access behavior.
- Quarkus:
hibernate.generate_statisticsmaps toquarkus.hibernate-orm.statisticsviaQuarkusHibernatePropertyLookup, so this rule no longer false-positives when statistics are enabled with the native Quarkus property name.
HIB-CONFIG-008 - Connection providers should disable auto-commit explicitly
- Severity: INFO
- Inspects:
hibernate.connection.provider_disables_autocommit, JTA transaction settings, andspring.datasource.hikari.auto-commit. - Fires when: JTA is not detected,
hibernate.connection.provider_disables_autocommitis not enabled, and Hikari is explicitly configured withspring.datasource.hikari.auto-commit=false. If the pool's auto-commit behavior cannot be confirmed, the check is skipped with guidance. - Why it matters: when the pool already disables auto-commit, this setting lets Hibernate delay connection acquisition.
- Recommendation: configure the pool with auto-commit disabled and set
hibernate.connection.provider_disables_autocommit=true.
HIB-CONFIG-009 - Collection-parameter queries should use IN-clause padding
- Severity: INFO
- Inspects: Spring Data JPQL query methods with collection parameters and
INpredicates. - Fires when: such a query exists and
hibernate.query.in_clause_parameter_paddingis not enabled. - Why it matters: variable-length
INpredicates can produce many SQL shapes and reduce plan-cache reuse. - Recommendation: enable IN-clause parameter padding when the database benefits from statement plan reuse.
- Quarkus:
hibernate.query.in_clause_parameter_paddingmaps toquarkus.hibernate-orm.query.in-clause-parameter-paddingviaQuarkusHibernatePropertyLookup, so the property is read correctly. The repository-scanning half of this rule only inspects Spring Data JPQL query methods, so it has nothing to flag on a Panache-based Quarkus app regardless of the property value.
HIB-CONFIG-010 - Query cache requires a second-level cache provider
- Severity: HIGH
- Inspects: Hibernate query-cache, second-level-cache, and region-factory properties.
- Fires when: query cache is enabled without a configured second-level cache provider, or when second-level cache is explicitly disabled.
- Why it matters: query caching depends on the second-level cache infrastructure and proper entity caching.
- Recommendation: disable query caching or configure a region factory and cache entities returned by cacheable entity queries.
- Quarkus:
hibernate.cache.use_query_cachemaps toquarkus.hibernate-orm.second-level-caching-enabledviaQuarkusHibernatePropertyLookup— Quarkus exposes a single unified toggle for second-level/query caching, not a separate query-cache property, so both the query-cache and second-level-cache reads resolve to the same Quarkus setting.hibernate.cache.region.factory_classhas no first-class Quarkus equivalent but is still reachable via theunsupported-propertiesfallback if explicitly configured.
HIB-CONFIG-011 - Cacheable entities should declare an explicit cache strategy
- Severity: MEDIUM
- Inspects: entity-level
@Cacheableand Hibernate@Cachewhen second-level caching appears configured. - Fires when: an entity is JPA-cacheable but does not declare an explicit Hibernate cache strategy.
- Why it matters: cache concurrency behavior should be explicit for cached entities.
- Recommendation: add a Hibernate cache concurrency strategy, or remove
@Cacheablewhen the entity should not use the second-level cache. - Quarkus:
hibernate.cache.use_second_level_cachemaps to the samequarkus.hibernate-orm.second-level-caching-enabledtoggle as HIB-CONFIG-010, so the precondition check for "second-level caching appears configured" is read correctly on Quarkus too.
HIB-CONFIG-002 - Schema generation should not mutate non-test databases
- Severity: INFO (can emit MEDIUM, HIGH, or CRITICAL based on profile and value)
- Inspects:
spring.jpa.hibernate.ddl-auto,spring.jpa.properties.hibernate.hbm2ddl.auto,hibernate.hbm2ddl.auto, and active Spring profiles. - Fires when: the configured value is
update,create, orcreate-dropoutside a test profile. A production-like profile wins over any other active profile:create/create-dropemits CRITICAL, andupdateemits HIGH. Dev/local disposable profiles emit INFO; unpinned non-test profiles emit MEDIUM. - Why it matters: automatic schema mutation is convenient locally but risky against shared or persistent databases, and
create/create-dropcan drop and recreate live schemas at application startup. - Recommendation: use versioned migrations for shared databases and reserve mutating
ddl-autovalues for disposable test environments.
HIB-CONFIG-012 - SQL logging should be off when a production profile is active
- Severity: MEDIUM
- Inspects:
spring.jpa.show-sql,hibernate.show_sql, and DEBUG/TRACE log levels fororg.hibernate.SQL/org.hibernate.orm.jdbc.bind/org.hibernate.type.descriptor.sql.BasicBinder. - Fires when: any of those are enabled while a profile named
prod,production,staging, or*-prod/*-productionis active. - Why it matters: logging every statement degrades throughput dramatically and can leak parameter values in application logs.
- Recommendation: keep SQL logging off in production-like environments and rely on structured slow-query logging or the database's statement audit.
HIB-CONFIG-013 - Configure hibernate.jdbc.time_zone
- Severity: LOW
- Inspects:
spring.jpa.properties.hibernate.jdbc.time_zoneandhibernate.jdbc.time_zone. - Fires when: neither property is set.
- Why it matters: without a fixed zone, JDBC binds and reads use the JVM default zone, so results vary across hosts.
- Recommendation: pin
hibernate.jdbc.time_zone=UTC(or another fixed zone) for deterministic timestamp handling. - Quarkus:
hibernate.jdbc.time_zonemaps toquarkus.hibernate-orm.jdbc.timezoneviaQuarkusHibernatePropertyLookup, so this rule no longer false-positives when the zone is pinned with the native Quarkus property name.
HIB-CONFIG-014 - Hibernate's built-in connection pool should not be used
- Severity: HIGH
- Inspects:
hibernate.connection.pool_size. - Fires when: the property is set.
- Why it matters: the property activates Hibernate's internal connection pool, which is intended for testing only and lacks the resilience and monitoring of a production pool.
- Recommendation: remove the property and rely on Spring Boot's managed
DataSource(HikariCP by default).
HIB-CONFIG-015 - spring.jpa.defer-datasource-initialization is only safe with embedded DDL flows
- Severity: MEDIUM
- Inspects:
spring.jpa.defer-datasource-initializationandspring.jpa.hibernate.ddl-auto. - Fires when: deferred initialization is enabled while
ddl-autois explicitly set to a value other thancreate,create-drop, orupdate. Ifddl-autois unset, the check is skipped because embedded-database defaults can still make deferred initialization meaningful. - Why it matters: the property is meaningful only when Hibernate creates or updates the schema; otherwise
data.sqlis never executed by that flow and the configuration is misleading. - Recommendation: combine deferred initialization with
ddl-auto=create/create-drop, or remove it and load seed data through your migration tool (Flyway, Liquibase).
HIB-CONFIG-016 - Fail on pagination over collection fetch
- Severity: HIGH (INFO when only the safety-net setting is missing)
- Inspects: the
hibernate.query.fail_on_pagination_over_collection_fetchproperty and paginated collectionJOIN FETCHrepository queries. - Fires when: Hibernate is older than 7.4 (or the runtime version cannot be detected) and the property is absent, false, or unparseable. If matching paginated collection fetch queries exist, the finding is HIGH; otherwise it is INFO hardening guidance for future queries.
- Why it matters (Hibernate < 7.4): without this guard, affected runtimes can allow a paginated collection fetch join to fetch the whole result set into memory instead of failing fast.
- Recommendation: set
spring.jpa.properties.hibernate.query.fail_on_pagination_over_collection_fetch=trueto throw an exception instead of risking a full-table fetch and memory exhaustion. - Hibernate 7.4+: as described under HIB-FETCH-003, the limit for a paged collection fetch join is now applied in the generated SQL by default, so the in-memory blowup this safety net guards against no longer happens without opting back in via
org.hibernate.limitInMemory. The check is skipped (not silently dropped) on 7.4+ runtimes, and the skip reason explains why. - Quarkus:
hibernate.query.fail_on_pagination_over_collection_fetchmaps toquarkus.hibernate-orm.query.fail-on-pagination-over-collection-fetchviaQuarkusHibernatePropertyLookup, so this rule no longer false-positives when the safety net is enabled with the native Quarkus property name.
HIB-CONFIG-017 - Disable SQL formatting in production
- Severity: LOW
- Inspects: the
hibernate.format_sqlproperty and the active Spring profiles. - Fires when: a production profile is active and
hibernate.format_sqlistrue. - Why it matters: pretty-printing SQL adds CPU and memory overhead, and Hibernate formats the statements even when SQL logging is disabled, so it is wasted work in production.
- Recommendation: disable
hibernate.format_sqlin production profiles and keep it enabled only for local development where readable SQL helps.
HIB-CONFIG-018 - Bind-parameter logging should be off in production
- Severity: HIGH
- Inspects: TRACE-level logging for
org.hibernate.orm.jdbc.bind(and the legacyorg.hibernate.type.descriptor.sql.BasicBinderbinder logger), plus the active Spring/Quarkus profile. - Fires when: a production-like profile is active and bind-parameter logging is enabled at TRACE.
- Why it matters: at TRACE, Hibernate logs every bound parameter value - this can leak PII, credentials, or tokens passed as query parameters into application logs.
- Recommendation: keep bind-parameter logging off in production; only enable it temporarily, in a non-production environment, while diagnosing a specific issue.
- Quarkus: also detects the Quarkus-native
quarkus.hibernate-orm.log.bind-parametersconvenience flag (and its deprecated.bind-paramalias), whichQuarkusHibernatePropertyLookupreports as the neutral TRACE logger state - Quarkus's own guide explicitly warns against enabling this in production.
Caching
HIB-CACHE-001 - Cached entities should also cache their associations
- Severity: MEDIUM
- Inspects: entities annotated with
@Cacheableor Hibernate@Cacheand the entities they associate with. - Fires when: an association on a cached entity targets another entity that is itself uncached.
- Why it matters: loading the aggregate from the cache still hits the database for every uncached association, defeating much of the cache's value.
- Recommendation: annotate the associated entities (or the association attributes) with
@org.hibernate.annotations.Cacheso the second-level cache covers the whole graph.
HIB-CACHE-002 - READ_ONLY cache strategy on writable entities is unsafe
- Severity: MEDIUM
- Inspects: entities annotated with
@Cache(usage = READ_ONLY). - Fires when: the entity also has
@Versionor@DynamicUpdate, both signals that the entity is mutable. - Why it matters:
READ_ONLYthrows when Hibernate detects state changes and silently misses updates from other transactions on the same entity. - Recommendation: switch to
READ_WRITEorNONSTRICT_READ_WRITEfor mutable entities.
HIB-CACHE-003 - Immutable cached entities should use READ_ONLY
- Severity: INFO
- Inspects: entity-level Hibernate
@Immutableand@Cache(usage=...). - Fires when: an immutable cached entity uses
READ_WRITE,NONSTRICT_READ_WRITE, orTRANSACTIONAL. - Why it matters: Hibernate documents
READ_ONLYas the simplest, safest, and best-performing strategy for immutable entities; mutable strategies add coordination overhead for updates the mapping forbids. - Recommendation: use
@Cache(usage = READ_ONLY), or remove@Immutableif the entity is expected to change.