Add Hibernate 7 batches 2-6, batch 7, and batch 8: mapping styles, JPA annotations, natural IDs, @Immutable, stored procedures, in-memory test databases, JNDI mocking, proxies, associations, temporal mapping, named queries, HQL, Criteria API, EntityManager bootstrapping, Ehcache 3 L2 cache configuration, HikariCP connection pooling, Hibernate Validator CDI integration, aggregate functions, sorting, pagination, interceptors, and Hibernate Search 8 (Hibernate 7.4.5.Final + Spring Boot 4.1.1 + JDK 25)
This commit is contained in:
Executable
+121
@@ -0,0 +1,121 @@
|
||||
# 04 — Annotations vs. XML mappings in Hibernate 7.4.5 — what actually still works
|
||||
|
||||
[← Previous: 03 — Inserting objects](03-inserting-objects.md) | [Next: 05 — JPA persistence annotations →](05-jpa-persistence-annotations.md)
|
||||
|
||||
Backs [ankurm.com: Hibernate 7 annotations vs. XML mappings](https://ankurm.com/hibernate-annotations-vs-xml-mappings-making-the-right-choice-in-hibernate-7/).
|
||||
|
||||
Post 4863 frames this as a two-way choice: annotations vs. `orm.xml`, with `hbm.xml` waved off
|
||||
as "deprecated." That framing undersells what actually happens when you boot Hibernate
|
||||
7.4.5.Final with each of these on the classpath, and it misses that there are really **three**
|
||||
XML dialects in play, not two. Everything below was booted, not read about — see
|
||||
[`docs/output/mappingstyle-xml-vs-annotations.txt`](output/mappingstyle-xml-vs-annotations.txt) for the verbatim run, and the test classes
|
||||
under [`src/test/java/com/ankurm/hibernatedemo/mappingstyle/`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/) for the exact setup of each case.
|
||||
|
||||
## `hbm.xml` is not dead — it is a live code path with a warning label
|
||||
|
||||
The Hibernate 6 story was: `hbm.xml` is deprecated, and `hibernate.transform_hbm_xml.enabled`
|
||||
is a shim that rewrites it into the modern model at boot. That shim setting still exists in
|
||||
7.4.5 (`org.hibernate.cfg.MappingSettings.TRANSFORM_HBM_XML`, and the whole
|
||||
`org.hibernate.boot.jaxb.hbm.*` package plus an `HbmXmlTransformer` are present in
|
||||
`hibernate-core-7.4.5.Final.jar`), but it is **not required** to use `hbm.xml`.
|
||||
|
||||
[`HbmXmlBootTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/HbmXmlBootTest.java) and [`HbmXmlRuntimeTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/HbmXmlRuntimeTest.java) put a real, annotation-free POJO
|
||||
([`HbmEmployee`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.java)) on the classpath with only an [`.hbm.xml` mapping](../src/test/resources/com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml), and boot a plain Hibernate
|
||||
`SessionFactory` three ways:
|
||||
|
||||
- default settings (no `transform_hbm_xml.enabled` at all) — **boots successfully**, logs one
|
||||
WARN: `HHH90000028: Support for <hibernate-mappings/> is deprecated ... migrate to orm.xml or
|
||||
mapping.xml, or enable hibernate.transform_hbm_xml.enabled for on the fly transformation`
|
||||
- `hibernate.transform_hbm_xml.enabled=true` — boots successfully, no observable behavior
|
||||
difference for a simple mapping
|
||||
- `hibernate.transform_hbm_xml.enabled=false` (explicit) — **also boots successfully**
|
||||
|
||||
`HbmXmlRuntimeTest` goes further: it actually persists and loads an `HbmEmployee` row through
|
||||
the hbm.xml-only mapping, with the transform setting deliberately unset, and it round-trips
|
||||
correctly. So the honest 7.4.5 status of `hbm.xml` is: **it still fully works, unmodified,
|
||||
with a WARN-level deprecation notice** — not a shim you must opt into, not a hard failure, and
|
||||
not silently broken. The "transform" setting appears to matter for hbm.xml features that no
|
||||
longer have a native binding path in 7.x and must be rewritten into the modern model to be
|
||||
understood at all; a plain `<class>`/`<id>`/`<property>` mapping like this one never needs it.
|
||||
Treat any blog claim that `hbm.xml` "requires" the transform flag, or throws without it, as
|
||||
wrong for 7.4.5 — it is a live code path. (Chapter 14 hits the same "orm.xml still works with
|
||||
zero registration effort" theme from the named-query angle — see
|
||||
[`14 — Named queries`](14-named-queries.md#named-queries-in-ormxml).)
|
||||
|
||||
## `orm.xml` really can define an entire entity, annotation-free
|
||||
|
||||
Post 4863's `orm.xml` example only *overrides* an already-annotated `Employee`. It never proves
|
||||
`orm.xml` can carry a mapping on its own. [`OrmXmlMappingResourcesTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/OrmXmlMappingResourcesTest.java) does: [`OrmXmlOnlyEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/OrmXmlOnlyEntity.java)
|
||||
carries **zero** JPA/Hibernate annotations — not even `@Entity` — and its entire mapping lives
|
||||
in [`orm-xml-only-mapping.xml`](../src/test/resources/orm-xml-only-mapping.xml). The Spring Boot wiring that makes this work is
|
||||
`spring.jpa.mapping-resources` (confirmed via `javap` on
|
||||
`org.springframework.boot.jpa.autoconfigure.JpaProperties` in `spring-boot-jpa-4.1.1.jar` —
|
||||
note the package: Boot 4's autoconfigure split moved this off the old
|
||||
`org.springframework.boot.autoconfigure.orm.jpa` path entirely). With that one property set,
|
||||
Hibernate creates `xml_only_widgets`, and a JPQL query (`select o from OrmXmlOnlyEntity o ...`)
|
||||
against it succeeds — the entity name resolves purely from the XML.
|
||||
|
||||
## XML wins on conflict — confirmed, not just documented
|
||||
|
||||
Post 4863's Q5 claims "XML always wins over annotations." [`AnnotationXmlOverrideTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/AnnotationXmlOverrideTest.java) proves it
|
||||
mechanically: [`OverrideEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/OverrideEntity.java)`.value` is annotated `@Column(name = "annotation_name")`, and a
|
||||
matching [`orm-xml-override-mapping.xml`](../src/test/resources/orm-xml-override-mapping.xml) entry maps the same field to `xml_name`. Reading the runtime metamodel
|
||||
(`SessionFactoryImplementor.getMappingMetamodel().getEntityDescriptor(...).getPropertyColumnNames(...)`)
|
||||
confirms the live column name is `xml_name`, and a native query against that literal column
|
||||
name returns the persisted value. The article's claim is correct.
|
||||
|
||||
## `<xml-mapping-metadata-complete/>` is not an override switch — it is an annotation kill switch
|
||||
|
||||
This is the sharpest correction. The natural assumption is that
|
||||
`<persistence-unit-metadata><xml-mapping-metadata-complete/></persistence-unit-metadata>` means
|
||||
"XML overrides annotations for the attributes XML mentions." [`XmlMappingMetadataCompleteTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/XmlMappingMetadataCompleteTest.java)
|
||||
shows it is stronger than that: with [metadata-complete set](../src/test/resources/orm-xml-metadata-complete.xml), `OverrideEntity`'s `@Id
|
||||
@GeneratedValue` on the `id` field is **entirely ignored**, even though the matching `orm.xml`
|
||||
entry never mentions `id` at all. Boot fails with
|
||||
`org.hibernate.AnnotationException: Entity '...OverrideEntity' has no identifier`. Metadata-complete
|
||||
does not selectively override — it switches off annotation processing for the whole persistence
|
||||
unit, and any attribute XML doesn't repeat is simply gone.
|
||||
|
||||
## The real "what XML can do that annotations can't" — a third XML dialect
|
||||
|
||||
Post 4863 never mentions this, and it changes the shape of the whole topic: Hibernate 7 ships a
|
||||
**third** XML mapping format, distinct from both legacy `hbm.xml` and JPA-standard `orm.xml`.
|
||||
It lives in `org/hibernate/xsd/mapping/mapping-7.0.xsd` inside `hibernate-core-7.4.5.Final.jar`,
|
||||
under namespace `http://www.hibernate.org/xsd/orm/mapping`, and its own XSD documentation calls
|
||||
it out explicitly: *"XSD which 'extends' the JPA orm.xml XSD adding support for Hibernate
|
||||
specific features."* This is exactly the second migration target the `HHH90000028` deprecation
|
||||
warning names ("migrate to orm.xml **or mapping.xml**").
|
||||
|
||||
The difference is not cosmetic. Grepping both schemas for Hibernate-only concepts:
|
||||
|
||||
| Element | `orm_3_2.xsd` (JPA-standard `orm.xml`) | `mapping-7.0.xsd` (Hibernate's native dialect) |
|
||||
|---|---|---|
|
||||
| `<natural-id>` | absent | present |
|
||||
| `<formula>` / `<discriminator-formula>` / `<join-formula>` | absent | present |
|
||||
| `<filter>`-related elements | absent | present (11 occurrences) |
|
||||
|
||||
[`MappingXmlNaturalIdTest`](../src/test/java/com/ankurm/hibernatedemo/mappingstyle/MappingXmlNaturalIdTest.java) proves this is not just schema noise: [`MappingXmlNaturalIdEntity`](../src/main/java/com/ankurm/hibernatedemo/mappingstyle/MappingXmlNaturalIdEntity.java) has
|
||||
**zero** annotations, its `<natural-id>` is declared purely in [`mapping-xml-natural-id.xml`](../src/test/resources/mapping-xml-natural-id.xml)
|
||||
(root element `<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping" version="7.0">`),
|
||||
and `session.byNaturalId(...).using("sku", ...).load()` resolves it correctly. So the accurate
|
||||
answer to "what can XML express that annotations can't" is actually inverted from how the
|
||||
article poses it: the JPA-portable `orm.xml` dialect can express **less** than annotations
|
||||
(no Hibernate extensions at all), while Hibernate's own `mapping.xml` dialect can express
|
||||
**anything annotations can**, including natural ids, formulas, and filters — you trade JPA
|
||||
portability for that power, not gain something unavailable to annotations. (Chapter 06 covers
|
||||
`@NaturalId` from the annotation side; this is the same feature expressed purely in XML.)
|
||||
|
||||
## Practical takeaway
|
||||
|
||||
- Legacy `hbm.xml`: still boots and runs in 7.4.5, WARN-level deprecated, no forced migration.
|
||||
- `orm.xml` (JPA-standard): fully capable of defining an entity from scratch; wired into Spring
|
||||
Boot via `spring.jpa.mapping-resources`; portable across providers but capped at what
|
||||
`orm_3_2.xsd` can express — no Hibernate-only concepts.
|
||||
- Hibernate's native `mapping.xml` (`mapping-7.0.xsd`): the actual annotation-equivalent XML
|
||||
dialect, including `@NaturalId`, `@Formula`, and filters — not portable to other JPA
|
||||
providers, but not missing anything either.
|
||||
- XML (either dialect) always wins over a conflicting annotation for the same attribute.
|
||||
- `xml-mapping-metadata-complete` disables annotation processing for the *entire* persistence
|
||||
unit, not just the attributes the XML repeats — a much bigger blast radius than "override."
|
||||
|
||||
[← Previous: 03 — Inserting objects](03-inserting-objects.md) | [Next: 05 — JPA persistence annotations →](05-jpa-persistence-annotations.md)
|
||||
Reference in New Issue
Block a user