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:
2026-09-20 06:06:42 +00:00
committed by Claude
commit 8568c0ce6c
330 changed files with 23668 additions and 0 deletions
@@ -0,0 +1,58 @@
package com.ankurm.hibernatedemo.mappingstyle;
import static org.assertj.core.api.Assertions.assertThat;
import com.ankurm.hibernatedemo.HibernateDemoApplication;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
/**
* The entity's field is annotated {@code @Column(name = "annotation_name")}. The matching
* orm.xml entry maps the same field to {@code xml_name}. This test reads back the ACTUAL
* column name Hibernate used, straight from the runtime metamodel and from the real DDL/SQL,
* to settle who wins.
*
* <p>Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
@SpringBootTest(classes = HibernateDemoApplication.class)
@TestPropertySource(properties = {
"spring.jpa.mapping-resources=orm-xml-override-mapping.xml"
})
class AnnotationXmlOverrideTest {
@Autowired
private EntityManagerFactory emf;
@Test
void xmlColumnMapping_winsOverAnnotationColumnMapping() {
SessionFactoryImplementor sfi = emf.unwrap(SessionFactoryImplementor.class);
EntityPersister persister = sfi.getMappingMetamodel()
.getEntityDescriptor(OverrideEntity.class);
String[] columnNames = persister.getPropertyColumnNames("value");
System.out.println("RESULT[override]: runtime column name for OverrideEntity.value = " + columnNames[0]
+ " (annotation said 'annotation_name', orm.xml said 'xml_name')");
assertThat(columnNames).containsExactly("xml_name");
// Prove it end-to-end: actually persist and read the row back through the winning column.
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
OverrideEntity e = new OverrideEntity("hello");
em.persist(e);
em.getTransaction().commit();
em.close();
EntityManager em2 = emf.createEntityManager();
Object row = em2.createNativeQuery("select xml_name from override_entity where id = " + e.getId())
.getSingleResult();
em2.close();
assertThat(row).isEqualTo("hello");
System.out.println("RESULT[override]: native query against column 'xml_name' returned: " + row);
}
}
@@ -0,0 +1,79 @@
package com.ankurm.hibernatedemo.mappingstyle;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.MappingSettings;
import org.junit.jupiter.api.Test;
/**
* Empirical probe: what does Hibernate 7.4.5.Final actually do with a legacy
* {@code .hbm.xml} mapping file, bypassing Spring entirely so every setting is explicit.
*
* <p>Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
class HbmXmlBootTest {
private StandardServiceRegistry baseRegistry() {
return new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.driver_class", "org.h2.Driver")
.applySetting("hibernate.connection.url", "jdbc:h2:mem:hbmtest;DB_CLOSE_DELAY=-1")
.applySetting("hibernate.connection.username", "sa")
.applySetting("hibernate.connection.password", "")
.applySetting("hibernate.hbm2ddl.auto", "create")
.build();
}
@Test
void defaultSettings_bootingWithHbmXml_printsWhatHappens() {
StandardServiceRegistry registry = baseRegistry();
try {
Metadata metadata = new MetadataSources(registry)
.addResource("com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml")
.buildMetadata();
SessionFactory sf = metadata.buildSessionFactory();
System.out.println("RESULT[default]: BOOT SUCCEEDED, SessionFactory built without hibernate.transform_hbm_xml.enabled");
sf.close();
} catch (Throwable t) {
System.out.println("RESULT[default]: BOOT FAILED: " + t.getClass().getName() + ": " + t.getMessage());
Throwable cause = t.getCause();
while (cause != null) {
System.out.println("RESULT[default]: caused by: " + cause.getClass().getName() + ": " + cause.getMessage());
cause = cause.getCause();
}
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
}
@Test
void transformHbmXmlEnabled_bootingWithHbmXml_printsWhatHappens() {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.driver_class", "org.h2.Driver")
.applySetting("hibernate.connection.url", "jdbc:h2:mem:hbmtest2;DB_CLOSE_DELAY=-1")
.applySetting("hibernate.connection.username", "sa")
.applySetting("hibernate.connection.password", "")
.applySetting("hibernate.hbm2ddl.auto", "create")
.applySetting(MappingSettings.TRANSFORM_HBM_XML, "true")
.build();
try {
Metadata metadata = new MetadataSources(registry)
.addResource("com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml")
.buildMetadata();
SessionFactory sf = metadata.buildSessionFactory();
System.out.println("RESULT[transform=true]: BOOT SUCCEEDED, SessionFactory built WITH " + MappingSettings.TRANSFORM_HBM_XML + "=true");
sf.close();
} catch (Throwable t) {
System.out.println("RESULT[transform=true]: BOOT FAILED: " + t.getClass().getName() + ": " + t.getMessage());
Throwable cause = t.getCause();
while (cause != null) {
System.out.println("RESULT[transform=true]: caused by: " + cause.getClass().getName() + ": " + cause.getMessage());
cause = cause.getCause();
}
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
@@ -0,0 +1,58 @@
package com.ankurm.hibernatedemo.mappingstyle;
import static org.assertj.core.api.Assertions.assertThat;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.MappingSettings;
import org.junit.jupiter.api.Test;
/**
* Proves the hbm.xml-mapped entity actually round-trips through the database -- not just
* that metadata parses. Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
class HbmXmlRuntimeTest {
@Test
void hbmXmlEntity_defaultSettings_actuallyPersistsAndQueries() {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.driver_class", "org.h2.Driver")
.applySetting("hibernate.connection.url", "jdbc:h2:mem:hbmruntime1;DB_CLOSE_DELAY=-1")
.applySetting("hibernate.connection.username", "sa")
.applySetting("hibernate.connection.password", "")
.applySetting("hibernate.hbm2ddl.auto", "create")
// NOTE: hibernate.transform_hbm_xml.enabled is deliberately NOT set here.
.build();
try {
Metadata metadata = new MetadataSources(registry)
.addResource("com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml")
.buildMetadata();
try (SessionFactory sf = metadata.buildSessionFactory()) {
Long id;
try (Session s = sf.openSession()) {
Transaction tx = s.beginTransaction();
HbmEmployee e = new HbmEmployee("Ada", "[email protected]");
s.persist(e);
tx.commit();
id = e.getId();
}
try (Session s = sf.openSession()) {
HbmEmployee loaded = s.get(HbmEmployee.class, id);
assertThat(loaded).isNotNull();
assertThat(loaded.getFirstName()).isEqualTo("Ada");
assertThat(loaded.getEmail()).isEqualTo("[email protected]");
System.out.println("RESULT[hbm-default-runtime]: persisted+loaded id=" + id
+ " firstName=" + loaded.getFirstName() + " email=" + loaded.getEmail()
+ " -- NO hibernate.transform_hbm_xml.enabled setting was applied.");
}
}
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
@@ -0,0 +1,37 @@
package com.ankurm.hibernatedemo.mappingstyle;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.MappingSettings;
import org.junit.jupiter.api.Test;
/** Explicitly setting transform_hbm_xml.enabled=false -- does it throw or refuse? */
class HbmXmlTransformFalseTest {
@Test
void transformExplicitlyFalse_bootingWithHbmXml_printsWhatHappens() {
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.driver_class", "org.h2.Driver")
.applySetting("hibernate.connection.url", "jdbc:h2:mem:hbmtest3;DB_CLOSE_DELAY=-1")
.applySetting("hibernate.connection.username", "sa")
.applySetting("hibernate.connection.password", "")
.applySetting("hibernate.hbm2ddl.auto", "create")
.applySetting(MappingSettings.TRANSFORM_HBM_XML, "false")
.build();
try {
Metadata metadata = new MetadataSources(registry)
.addResource("com/ankurm/hibernatedemo/mappingstyle/HbmEmployee.hbm.xml")
.buildMetadata();
SessionFactory sf = metadata.buildSessionFactory();
System.out.println("RESULT[transform=false]: BOOT SUCCEEDED even with transform_hbm_xml.enabled=false");
sf.close();
} catch (Throwable t) {
System.out.println("RESULT[transform=false]: BOOT FAILED: " + t.getClass().getName() + ": " + t.getMessage());
} finally {
StandardServiceRegistryBuilder.destroy(registry);
}
}
}
@@ -0,0 +1,53 @@
package com.ankurm.hibernatedemo.mappingstyle;
import static org.assertj.core.api.Assertions.assertThat;
import com.ankurm.hibernatedemo.HibernateDemoApplication;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import org.hibernate.Session;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
/**
* A @NaturalId concept, expressed in Hibernate's native "mapping.xml" XML dialect
* (namespace http://www.hibernate.org/xsd/orm/mapping) on a class with ZERO annotations.
* The JPA-standard orm.xml dialect (orm_3_2.xsd) has no &lt;natural-id&gt; element -- this is a
* Hibernate-only extension that only the extended XML dialect (or Java annotations) can express.
*
* <p>Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
@SpringBootTest(classes = HibernateDemoApplication.class)
@TestPropertySource(properties = {
"spring.jpa.mapping-resources=mapping-xml-natural-id.xml"
})
class MappingXmlNaturalIdTest {
@Autowired
private EntityManagerFactory emf;
@Test
void naturalIdDefinedPurelyInXml_resolvesViaByNaturalId() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
MappingXmlNaturalIdEntity e = new MappingXmlNaturalIdEntity("SKU-XML-1", "XML Widget");
em.persist(e);
em.getTransaction().commit();
em.close();
EntityManager em2 = emf.createEntityManager();
Session session = em2.unwrap(Session.class);
MappingXmlNaturalIdEntity loaded = session.byNaturalId(MappingXmlNaturalIdEntity.class)
.using("sku", "SKU-XML-1")
.load();
em2.close();
assertThat(loaded).isNotNull();
assertThat(loaded.getName()).isEqualTo("XML Widget");
System.out.println("RESULT[mapping-xml-natural-id]: session.byNaturalId() resolved an entity whose "
+ "@NaturalId-equivalent was declared ENTIRELY in Hibernate's native mapping.xml dialect, "
+ "zero Java annotations. name=" + loaded.getName());
}
}
@@ -0,0 +1,56 @@
package com.ankurm.hibernatedemo.mappingstyle;
import static org.assertj.core.api.Assertions.assertThat;
import com.ankurm.hibernatedemo.HibernateDemoApplication;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
/**
* Proves that {@code spring.jpa.mapping-resources} is the Spring Boot 4.1.1 wiring that makes
* an orm.xml-only mapping (no {@code @Entity} at all) a real managed JPA entity, backed by a
* table ({@code xml_only_widgets}) that ONLY orm.xml knows about.
*
* <p>Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
@SpringBootTest(classes = HibernateDemoApplication.class)
@TestPropertySource(properties = {
"spring.jpa.mapping-resources=orm-xml-only-mapping.xml"
})
class OrmXmlMappingResourcesTest {
@Autowired
private EntityManagerFactory emf;
@Test
void ormXmlOnlyEntity_isManaged_andRoundTripsThroughItsOwnTable() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
OrmXmlOnlyEntity e = new OrmXmlOnlyEntity("mapped-by-orm-xml-only");
em.persist(e);
em.getTransaction().commit();
Long id = e.getId();
em.close();
assertThat(id).isNotNull();
EntityManager em2 = emf.createEntityManager();
// This JPQL uses the entity name (defaults to simple class name) -- proves the entity is
// registered in metadata purely via orm.xml, with zero annotations on the Java class.
List<OrmXmlOnlyEntity> found = em2.createQuery(
"select o from OrmXmlOnlyEntity o where o.label = :label", OrmXmlOnlyEntity.class)
.setParameter("label", "mapped-by-orm-xml-only")
.getResultList();
em2.close();
assertThat(found).hasSize(1);
assertThat(found.get(0).getId()).isEqualTo(id);
System.out.println("RESULT[orm-xml-only]: persisted+queried id=" + id
+ " via JPQL against entity mapped ENTIRELY by orm.xml (table xml_only_widgets), zero annotations on the Java class.");
}
}
@@ -0,0 +1,46 @@
package com.ankurm.hibernatedemo.mappingstyle;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.ankurm.hibernatedemo.HibernateDemoApplication;
import org.hibernate.AnnotationException;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* &lt;xml-mapping-metadata-complete/&gt; makes Hibernate IGNORE ALL annotations for this
* persistence unit -- not just the ones a matching orm.xml entry overrides. OverrideEntity
* carries @Id/@GeneratedValue on "id" in Java, but the metadata-complete orm.xml entry only
* declares &lt;basic name="value"&gt; and omits &lt;id&gt; entirely. Result: bootstrap fails because
* the (ignored) @Id annotation no longer counts -- proving metadata-complete is not just an
* override switch, it is a full annotation kill-switch for the persistence unit.
*
* <p>Docs: docs/04-annotations-vs-xml.md, Topic 1.
*/
class XmlMappingMetadataCompleteTest {
@Test
void metadataComplete_ignoresAtIdAnnotation_bootFailsWithNoIdentifier() {
SpringApplicationBuilder builder = new SpringApplicationBuilder(HibernateDemoApplication.class)
.properties("spring.jpa.mapping-resources=orm-xml-metadata-complete.xml");
BeanCreationException ex = assertThrows(BeanCreationException.class, () -> {
try (ConfigurableApplicationContext ctx = builder.run()) {
// never reached
}
});
Throwable root = ex;
while (root.getCause() != null) {
root = root.getCause();
}
System.out.println("RESULT[metadata-complete]: boot FAILED as predicted: " + root.getClass().getName()
+ ": " + root.getMessage());
assertThat(root).isInstanceOf(AnnotationException.class);
assertThat(root.getMessage()).contains("has no identifier");
}
}