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,152 @@
package com.ankurm.hibernatedemo.bootstrap;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.PersistenceConfiguration;
import jakarta.persistence.PersistenceException;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Backs ankurm.com post 4855 (bootstrapping EntityManager). Docs: docs/17-entitymanager-bootstrap.md.
*
* <p>Deliberately plain JUnit, NOT {@code @SpringBootTest} -- the whole point of this chapter is
* bootstrapping a raw JPA {@link EntityManagerFactory} with no Spring involved, exactly as a
* Java SE application or a unit test outside a Spring context would. The XML path reads
* {@code src/test/resources/META-INF/persistence.xml}; the programmatic path uses Jakarta
* Persistence 3.2's {@link PersistenceConfiguration}, new in this version.
*
* <p>Run with {@code ./mvnw -Dtest=EntityManagerBootstrapTest test}.
*/
class EntityManagerBootstrapTest {
private static final Logger DEMO = LoggerFactory.getLogger("DEMO");
@Test
void xmlBootstrap_createsFactoryFromPersistenceXmlAndPersistsAUser() {
// No properties map passed here at all -- everything comes from
// META-INF/persistence.xml on the test classpath, resolved purely by unit name.
try (EntityManagerFactory emf = Persistence.createEntityManagerFactory("XmlBootstrapPU")) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
BootstrapUser user = new BootstrapUser("Ankur", "[email protected]");
em.persist(user);
em.getTransaction().commit();
Long id = user.getId();
em.close();
EntityManager reader = emf.createEntityManager();
BootstrapUser reloaded = reader.find(BootstrapUser.class, id);
assertThat(reloaded).isNotNull();
assertThat(reloaded.getEmail()).isEqualTo("[email protected]");
reader.close();
DEMO.info("xmlBootstrap: persisted and reloaded user id={}", id);
}
}
@Test
void programmaticBootstrap_needsNoPersistenceXmlUnitOnClasspath() {
// "ProgrammaticPU" has NO matching <persistence-unit> anywhere in persistence.xml --
// this only works at all if PersistenceConfiguration genuinely bypasses XML lookup.
PersistenceConfiguration config = new PersistenceConfiguration("ProgrammaticPU")
.provider("org.hibernate.jpa.HibernatePersistenceProvider")
.managedClass(BootstrapUser.class)
.property(PersistenceConfiguration.JDBC_DRIVER, "org.h2.Driver")
.property(PersistenceConfiguration.JDBC_URL, "jdbc:h2:mem:bootstrap-programmatic;DB_CLOSE_DELAY=-1")
.property(PersistenceConfiguration.JDBC_USER, "sa")
.property(PersistenceConfiguration.JDBC_PASSWORD, "")
.property("hibernate.hbm2ddl.auto", "create-drop");
try (EntityManagerFactory emf = config.createEntityManagerFactory()) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
BootstrapUser user = new BootstrapUser("Programmatic", "[email protected]");
em.persist(user);
em.getTransaction().commit();
Long id = user.getId();
em.close();
EntityManager reader = emf.createEntityManager();
assertThat(reader.find(BootstrapUser.class, id)).isNotNull();
reader.close();
DEMO.info("programmaticBootstrap: persisted user id={} with zero persistence.xml units named 'ProgrammaticPU'", id);
}
}
@Test
void persistenceUnitName_inProgrammaticConfig_doesNotTriggerXmlSearch() {
// Reusing "XmlBootstrapPU" -- the EXACT SAME name as the real XML unit -- but with
// completely different properties built purely in code, pointed at a third database.
// If the name alone triggered an XML lookup/merge, this factory would end up
// connected to bootstrap-xml (the XML unit's database) instead. It doesn't.
PersistenceConfiguration config = new PersistenceConfiguration("XmlBootstrapPU")
.provider("org.hibernate.jpa.HibernatePersistenceProvider")
.managedClass(BootstrapUser.class)
.property(PersistenceConfiguration.JDBC_DRIVER, "org.h2.Driver")
.property(PersistenceConfiguration.JDBC_URL, "jdbc:h2:mem:bootstrap-namecollision;DB_CLOSE_DELAY=-1")
.property(PersistenceConfiguration.JDBC_USER, "sa")
.property(PersistenceConfiguration.JDBC_PASSWORD, "")
.property("hibernate.hbm2ddl.auto", "create-drop");
try (EntityManagerFactory emf = config.createEntityManagerFactory()) {
EntityManager em = emf.createEntityManager();
@SuppressWarnings("unchecked")
java.util.List<Object> row = em.createNativeQuery("SELECT DATABASE()").getResultList();
String actualDb = (String) row.get(0);
assertThat(actualDb).as("the programmatic config's own JDBC URL won, not the XML unit's")
.isEqualToIgnoringCase("BOOTSTRAP-NAMECOLLISION");
em.close();
DEMO.info("persistenceUnitNameCollision: connected database = {} (unit name 'XmlBootstrapPU' reused on purpose)", actualDb);
}
}
@Test
void unconfiguredUnitName_failsWithPersistenceException_notSilently() {
// "TotallyUnknownPU" exists neither in persistence.xml nor as a PersistenceConfiguration
// -- Persistence.createEntityManagerFactory(name) with no config map has nowhere left
// to look.
assertThatThrownBy(() -> Persistence.createEntityManagerFactory("TotallyUnknownPU"))
.isInstanceOf(PersistenceException.class)
.satisfies(ex -> {
DEMO.info("unconfiguredUnitName: {}: {}", ex.getClass().getName(), ex.getMessage());
assertThat(ex.getMessage()).contains("TotallyUnknownPU");
});
}
@Test
void repeatedFactoryCreation_isMeasurablyExpensive() {
// Not a Metaspace OOM reproduction -- that needs sustained, uncollectable class-loader
// growth over many thousands of factories and isn't something to actually trigger in a
// shared CI sandbox. What IS safely measurable: EntityManagerFactory creation is not
// cheap, which is the whole reason "never create one per request" is the rule in the
// first place.
PersistenceConfiguration config = new PersistenceConfiguration("TimingPU")
.provider("org.hibernate.jpa.HibernatePersistenceProvider")
.managedClass(BootstrapUser.class)
.property(PersistenceConfiguration.JDBC_DRIVER, "org.h2.Driver")
.property(PersistenceConfiguration.JDBC_URL, "jdbc:h2:mem:bootstrap-timing;DB_CLOSE_DELAY=-1")
.property(PersistenceConfiguration.JDBC_USER, "sa")
.property(PersistenceConfiguration.JDBC_PASSWORD, "")
.property("hibernate.hbm2ddl.auto", "create-drop");
long factoryStart = System.nanoTime();
EntityManagerFactory emf = config.createEntityManagerFactory();
long factoryMillis = (System.nanoTime() - factoryStart) / 1_000_000;
long emStart = System.nanoTime();
EntityManager em = emf.createEntityManager();
long emMillis = (System.nanoTime() - emStart) / 1_000_000;
em.close();
emf.close();
assertThat(factoryMillis).as("factory creation happened and was timed").isGreaterThanOrEqualTo(0);
DEMO.info("repeatedFactoryCreation: createEntityManagerFactory() took {} ms, createEntityManager() took {} ms -- "
+ "the factory call is the one doing schema validation, service registry bootstrap, and metadata scanning; "
+ "the EntityManager call is comparatively trivial", factoryMillis, emMillis);
}
}